]> gerrit.simantics Code Review - simantics/3d.git/blob - org.simantics.proconf.g3d/src/org/simantics/proconf/g3d/scenegraph/ShapeNode.java
d345b8b416be11b73b7039b6c4bf3d0aa5e7ea1c
[simantics/3d.git] / org.simantics.proconf.g3d / src / org / simantics / proconf / g3d / scenegraph / ShapeNode.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
3  * All rights reserved. This program and the accompanying materials\r
4  * are made available under the terms of the Eclipse Public License v1.0\r
5  * which accompanies this distribution, and is available at\r
6  * http://www.eclipse.org/legal/epl-v10.html\r
7  *\r
8  * Contributors:\r
9  *     VTT Technical Research Centre of Finland - initial API and implementation\r
10  *******************************************************************************/\r
11 package org.simantics.proconf.g3d.scenegraph;\r
12 \r
13 import java.util.ArrayList;\r
14 import java.util.Collection;\r
15 import java.util.List;\r
16 \r
17 import javax.vecmath.AxisAngle4d;\r
18 import javax.vecmath.Quat4d;\r
19 \r
20 import org.simantics.animation.stubs.Interpolator;\r
21 import org.simantics.animation.curve.SlerpCurve;\r
22 import org.simantics.animation.curve.TCBCurve;\r
23 import org.simantics.proconf.g3d.Resources;\r
24 import org.simantics.proconf.g3d.animation.Animatable;\r
25 import org.simantics.proconf.g3d.animation.Animation;\r
26 import org.simantics.proconf.g3d.animation.ChanneledColorInterpolator;\r
27 import org.simantics.proconf.g3d.animation.ChanneledPositionInterpolator;\r
28 import org.simantics.proconf.g3d.animation.ConstantInterpolator;\r
29 import org.simantics.proconf.g3d.animation.ScalarInterpolator;\r
30 import org.simantics.proconf.g3d.animation.SlerpInterpolator;\r
31 import org.simantics.proconf.g3d.animation.TCBInterpolator;\r
32 import org.simantics.proconf.g3d.base.AppearanceProvider;\r
33 import org.simantics.proconf.g3d.base.AppearanceProviderRegistry;\r
34 import org.simantics.proconf.g3d.base.AppearanceTools;\r
35 import org.simantics.proconf.g3d.base.G3DTools;\r
36 import org.simantics.proconf.g3d.base.GeometryProvider;\r
37 import org.simantics.proconf.g3d.base.GeometryProviderRegistry;\r
38 import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
39 import org.simantics.proconf.g3d.stubs.Appearance;\r
40 import org.simantics.proconf.g3d.stubs.Color;\r
41 import org.simantics.proconf.g3d.stubs.G3DModel;\r
42 import org.simantics.proconf.g3d.stubs.G3DNode;\r
43 import org.simantics.proconf.g3d.stubs.Orientation;\r
44 import org.simantics.utils.ui.ErrorLogger;\r
45 \r
46 import com.jme.bounding.BoundingBox;\r
47 import com.jme.bounding.CollisionTreeManager;\r
48 import com.jme.intersection.PickResults;\r
49 import com.jme.math.Ray;\r
50 import com.jme.renderer.ColorRGBA;\r
51 import com.jme.renderer.Renderer;\r
52 import com.jme.scene.Geometry;\r
53 import com.jme.scene.Node;\r
54 import com.jme.scene.SharedMesh;\r
55 import com.jme.scene.TriMesh;\r
56 import com.jme.scene.state.AlphaState;\r
57 import com.jme.scene.state.MaterialState;\r
58 import com.jme.scene.state.RenderState;\r
59 import com.jme.scene.state.WireframeState;\r
60 import com.jme.scene.state.ZBufferState;\r
61 \r
62 import org.simantics.db.Builtins;\r
63 import org.simantics.db.ContextGraph;\r
64 import org.simantics.db.Graph;\r
65 import org.simantics.db.Resource;\r
66 import org.simantics.layer0.utils.IEntity;\r
67 \r
68 public class ShapeNode extends AbstractGraphicsNode implements Animatable, IGeometryNode{\r
69 \r
70     public static final int NORMAL = 0;\r
71     public static final int TRANSPARENT = 1;\r
72     public static final int SELECTED_EDGE = 2;\r
73     public static final int HIGHLIGHTED_EDGE = 3;\r
74     \r
75     private boolean highlighted = false;\r
76 \r
77     protected Geometry mesh = null;\r
78     protected Geometry lines = null;\r
79     protected Geometry[] geometry = null;\r
80 \r
81     private boolean visible[] = new boolean[4];\r
82     \r
83     private Node body;\r
84     private Node transparent;\r
85     private Node edge;\r
86 \r
87     private MaterialState selectedEdgeState;\r
88     private MaterialState highlightedEdgeState;\r
89     \r
90     private Collection<RenderState> renderStates;\r
91     private boolean isTransparent;\r
92     \r
93 \r
94     public ShapeNode(ThreeDimensionalEditorBase editor,IGraphicsNode parent, Graph graph, Resource shapeResource) {\r
95         super(editor,parent, graph, shapeResource);\r
96         for (int i = 0; i < visible.length; i++)\r
97             visible[i] = false;\r
98         \r
99         body = new Node();\r
100 \r
101         body.setName(id); \r
102         \r
103         \r
104         transparent = new Node() {\r
105                 private static final long serialVersionUID = 1L;\r
106                 @Override\r
107                 public void calculatePick(Ray ray, PickResults results) {\r
108                 \r
109                 }\r
110         };\r
111         \r
112        // transparent.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);\r
113         \r
114         edge = new Node(){\r
115                 private static final long serialVersionUID = 1L;\r
116                 @Override\r
117                 public void calculatePick(Ray ray, PickResults results) {\r
118                 \r
119                 }\r
120         };\r
121         transparent.setIsCollidable(false);\r
122         edge.setIsCollidable(false);\r
123         \r
124         MaterialState ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
125         ms.setDiffuse(new ColorRGBA(0.0f, 0.75f, 0.0f,0.3f));\r
126         ms.setEmissive(new ColorRGBA(0f, 0f, 0f,0.3f));\r
127         ms.setSpecular(new ColorRGBA(0.5f, 0.5f, 0.5f,0.3f));\r
128         ms.setAmbient(new ColorRGBA(0.0f, 0.75f, 0.0f,0.3f));\r
129         ms.setShininess(128.f);\r
130         ms.setMaterialFace(MaterialState.MF_FRONT_AND_BACK);\r
131         transparent.setRenderState(ms);\r
132         \r
133         AlphaState as = editor.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState();\r
134         as.setBlendEnabled(true);\r
135         as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);\r
136         as.setSrcFunction(AlphaState.DB_SRC_ALPHA);\r
137         transparent.setRenderState(as);\r
138         \r
139         ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
140         ms.setDiffuse(new ColorRGBA(1.f, 1.f, 1.f, 1.f));\r
141         ms.setEmissive(new ColorRGBA(1.f, 1.f, 1.f, 1.f));\r
142         ms.setSpecular(new ColorRGBA(1.f, 1.f, 1.f, 1.f));\r
143         ms.setAmbient(new ColorRGBA(1.f, 1.f, 1.f, 1.f));\r
144         ms.setShininess(128.f);\r
145         selectedEdgeState = ms;\r
146         \r
147         ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
148         ms.setDiffuse(new ColorRGBA(1.f, 0.f, 1.f, 1.f));\r
149         ms.setEmissive(new ColorRGBA(1.f, 0.f, 1.f, 1.f));\r
150         ms.setSpecular(new ColorRGBA(1.f, 0.f, 1.f, 1.f));\r
151         ms.setAmbient(new ColorRGBA(1.f, 0.f, 1.f, 1.f));\r
152         ms.setShininess(128.f);\r
153         \r
154         highlightedEdgeState = ms;\r
155 \r
156         \r
157     }\r
158 \r
159 \r
160     /**\r
161      * This method is used to get implementation specific geometry.\r
162      * Arrays first element is a mesh, second contains edges.\r
163      * @return\r
164      */\r
165     public Geometry[] getGeometry(Graph graph, boolean update) {\r
166         G3DNode shape = getG3DNode(graph);\r
167         final GeometryProvider provider = GeometryProviderRegistry.getGeometryProvider(shape);\r
168         if (!update) {\r
169                 return provider.getGeometryFromResource(shape, false);\r
170         } else {\r
171                 if (geometry == null) {\r
172                                 geometry = provider.getGeometryFromResource(shape, false);\r
173                         } else {\r
174                                 provider.reconstructGeometry(shape, false, geometry);\r
175                         }\r
176                 return geometry;\r
177         }\r
178     }\r
179 \r
180     /**\r
181      * Updates shapes and it's ancestors geometry\r
182      */\r
183     public void updateGeometry(Graph graph) {\r
184         updateTransform(graph);\r
185        // cleanAnimation();\r
186         //System.out.println("ShapeNode.updateGeometry() " + name);\r
187         if (geometry == null) {\r
188                 Geometry g[] = getGeometry(graph,true);\r
189                 if (g != null) {\r
190                                 mesh = g[0];\r
191                                 //TODO : uid\r
192                                 mesh.setName(id); \r
193                                 mesh.setModelBound(new BoundingBox());\r
194                                 if (g.length > 1) {\r
195                                         lines = g[1];\r
196                                 } else {\r
197                                         lines = null;\r
198                                 }\r
199                                 body.attachChild(mesh);\r
200                                 transparent.detachAllChildren();\r
201                                 SharedMesh m = new SharedMesh("",(TriMesh)mesh);\r
202                                 m.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);\r
203                                 m.getBatch(0).setCastsShadows(false);\r
204                                 transparent.attachChild(m);\r
205                                 \r
206                                 \r
207                                 if (lines == null) {\r
208                                         WireframeState ws = editor.getRenderingComponent().getDisplaySystem().getRenderer().createWireframeState();\r
209                                         edge.attachChild(new SharedMesh("",(TriMesh)mesh));\r
210                                         edge.setRenderState(ws);\r
211                                 } else {\r
212                                         ZBufferState zs = editor.getRenderingComponent().getDisplaySystem().getRenderer().createZBufferState();\r
213                             zs.setFunction(ZBufferState.CF_ALWAYS);\r
214                             AlphaState as = editor.getRenderingComponent().getDisplaySystem().getRenderer().createAlphaState();\r
215                             as.setBlendEnabled(true);\r
216                             as.setDstFunction(AlphaState.DB_ONE_MINUS_SRC_ALPHA);\r
217                             as.setSrcFunction(AlphaState.DB_SRC_ALPHA);\r
218                             lines.setRenderState(zs);\r
219                             lines.setRenderState(as);\r
220                             lines.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);\r
221                             edge.attachChild(lines);\r
222                                 }\r
223 \r
224                 }\r
225         }\r
226         if (geometry != null) {\r
227                 getGeometry(graph,true);\r
228 \r
229             \r
230             G3DNode shape = getG3DNode(graph);\r
231             //if (renderStates == null)\r
232                 updateAppearance(shape);\r
233 \r
234             if (isVisible()) {\r
235                 getGroup().attachChild(body);\r
236             } else {\r
237                 body.removeFromParent();\r
238             }\r
239             if (isTransparentVisible()) {\r
240                 getGroup().attachChild(transparent);\r
241                 //setVisible(TRANSPARENT, true);\r
242             } else {\r
243                 transparent.removeFromParent();\r
244             }\r
245 \r
246             if (isSelectedVisible() || isHighlightedVisible()) {\r
247                 getGroup().attachChild(edge);\r
248                 //setVisible(SELECTED_EDGE, true);\r
249             } else {\r
250                 edge.removeFromParent();\r
251                 //setVisible(SELECTED_EDGE,false);\r
252             }\r
253             \r
254             \r
255             mesh.updateModelBound();\r
256             CollisionTreeManager.getInstance().updateCollisionTree(mesh);\r
257             //mesh.updateCollisionTree();\r
258   \r
259         }\r
260     }\r
261     \r
262     protected void updateAppearance(IEntity shape) {\r
263         AppearanceProvider provider = AppearanceProviderRegistry.getAppearanceProvider(shape);\r
264         if (provider != null) {\r
265             renderStates = provider.getAppearanceFromResource(shape, editor.getRenderingComponent().getDisplaySystem().getRenderer());\r
266         } else {\r
267                 renderStates = getMaterial();\r
268         }\r
269         \r
270         isTransparent = false;\r
271         for (RenderState s : renderStates) {\r
272                 if (s instanceof AlphaState)\r
273                         isTransparent = true;\r
274         }\r
275         setAppearance();\r
276     }\r
277     \r
278     protected void setAppearance() {\r
279         if (mesh ==  null || renderStates == null) {\r
280                 return;\r
281         }\r
282                 for (RenderState s : renderStates)\r
283                         mesh.setRenderState(s);\r
284                 if (isTransparent)\r
285                         mesh.setRenderQueueMode(Renderer.QUEUE_TRANSPARENT);\r
286                 else\r
287                         mesh.setRenderQueueMode(Renderer.QUEUE_OPAQUE);\r
288     }\r
289 \r
290     public void setSelected(boolean selected) {\r
291         if (this.selected == selected)\r
292             return;\r
293         this.selected = selected;\r
294         if (selected) {\r
295 \r
296             setSelectedVisible(true);\r
297             setTransparentVisible(true);\r
298         } else {\r
299             setSelectedVisible(false);\r
300             setTransparentVisible(false);\r
301         }\r
302     }\r
303 \r
304     public boolean isSelected() {\r
305         return selected;\r
306     }\r
307     \r
308     \r
309 \r
310     public boolean isHighlighted() {\r
311         return highlighted;\r
312     }\r
313 \r
314     public void setHighlighted(boolean highlighted) {\r
315         if (this.highlighted == highlighted)\r
316             return;\r
317         this.highlighted = highlighted;\r
318         if (highlighted) {\r
319             setHighlightedVisible(true);\r
320         } else {\r
321             setHighlightedVisible(false);\r
322         }\r
323     }\r
324     \r
325     public boolean isVisible(int shape) {\r
326         return visible[shape];\r
327     }\r
328     \r
329     public void setVisible(int shape, boolean visible) {\r
330         if (this.visible[shape] == visible)\r
331             return;   \r
332         this.visible[shape] = visible;\r
333         if (mesh == null) {\r
334                 return;\r
335         }\r
336         if (this.visible[NORMAL]){\r
337                 getGroup().attachChild(body);\r
338         } else {\r
339                 body.removeFromParent();\r
340         }\r
341         if (this.visible[TRANSPARENT]) {\r
342                 getGroup().attachChild(transparent);\r
343         } else {\r
344                 transparent.removeFromParent();\r
345         }\r
346         if (this.visible[SELECTED_EDGE] || this.visible[HIGHLIGHTED_EDGE]) {\r
347                 if (this.visible[HIGHLIGHTED_EDGE])\r
348                         edge.setRenderState(highlightedEdgeState);\r
349                 else\r
350                         edge.setRenderState(selectedEdgeState);\r
351                 getGroup().attachChild(edge);\r
352                 edge.updateRenderState();\r
353         } else {\r
354                 edge.removeFromParent();\r
355         } \r
356     }\r
357 \r
358     public boolean isVisible() {\r
359         return isVisible(NORMAL);\r
360     }\r
361 \r
362     public void setVisible(boolean visible) {\r
363         setVisible(NORMAL, visible);\r
364     }\r
365 \r
366     public boolean isSelectedVisible() {\r
367         return isVisible(SELECTED_EDGE);\r
368     }\r
369 \r
370     public void setSelectedVisible(boolean visible) {\r
371         setVisible(SELECTED_EDGE, visible);\r
372     }\r
373 \r
374     public boolean isHighlightedVisible() {\r
375         return isVisible(HIGHLIGHTED_EDGE);\r
376     }\r
377 \r
378     public void setHighlightedVisible(boolean visible) {\r
379         setVisible(HIGHLIGHTED_EDGE, visible);\r
380         \r
381     }\r
382 \r
383     \r
384 \r
385     public boolean isTransparentVisible() {\r
386         return isVisible(TRANSPARENT);\r
387     }\r
388 \r
389     public void setTransparentVisible(boolean visible) {\r
390         setVisible(TRANSPARENT, visible);\r
391     }\r
392 \r
393     public void setPickable(boolean pickable) {\r
394         body.setIsCollidable(pickable);\r
395     }\r
396     \r
397     public Collection<RenderState> getMaterial() {\r
398         List<RenderState> states = new ArrayList<RenderState>();\r
399         MaterialState ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState();\r
400         ms.setEmissive(new ColorRGBA(0.f,0.f,0.f,0.f));\r
401         ms.setSpecular(new ColorRGBA(1.f,1.f,1.f,1.f));\r
402         ms.setDiffuse(new ColorRGBA(0.75f,0.f,0.f,0.f));\r
403         ms.setAmbient(new ColorRGBA(0.75f,0.f,0.f,0.f));\r
404         ms.setEnabled(true);\r
405         ms.setShininess(128.f);\r
406         states.add(ms);\r
407 \r
408         return states;  \r
409     }\r
410     \r
411     private Animation animation;\r
412     private static int preCalcSteps = 9;\r
413     private Geometry[] preCalc = null;\r
414     private int currentPreCalc = 0;\r
415     \r
416     public void animate(double delta,double frameTime) {\r
417         if (animation != null)\r
418             animation.interpolate(delta);\r
419         if (preCalc != null) {\r
420             int newPreCalc = (int)Math.round(delta*(preCalc.length-1));\r
421             if (currentPreCalc != newPreCalc) {\r
422 \r
423                 preCalc[currentPreCalc].removeFromParent();\r
424                 currentPreCalc = newPreCalc;\r
425                 \r
426                 body.attachChild(preCalc[currentPreCalc]);\r
427             }\r
428         }\r
429     }\r
430     \r
431     private void cleanAnimation() {\r
432         this.animation = null;\r
433         if (preCalc != null) {\r
434                 for (Geometry g : preCalc) {\r
435                         if (g != null) {\r
436                                 g.removeFromParent();\r
437                                 g.clearBuffers();\r
438                         }\r
439                 }\r
440                 preCalc = null;\r
441         }\r
442     }\r
443 \r
444     /**\r
445      * Sets shape's animation\r
446      * TODO : multiple animations at the same time! (must check common animatable properties)\r
447      * TODO : initial values (material, ..) (requires changes in the ontology)\r
448      * TODO : messy code, refactor!\r
449      * TODO : calculate number of required pre-calculated geometries \r
450      * @param animation\r
451      */\r
452     public boolean setAnimation(Graph g, Resource res) {\r
453         ContextGraph graph;\r
454         if (g instanceof ContextGraph) {\r
455                 graph = (ContextGraph)g;\r
456         } else {\r
457                 graph = new ContextGraph(g);\r
458                 graph.setContext(shapeResource);\r
459         }\r
460         cleanAnimation();\r
461         if (res == null) {\r
462                 if (isVisible())\r
463                         body.attachChild(mesh);\r
464             return false;\r
465         }\r
466         org.simantics.animation.stubs.Animation animation = new org.simantics.animation.stubs.Animation(graph,res);\r
467         G3DNode shape = getG3DNode(graph);\r
468         G3DNode modelResource = G3DTools.getModelFromResource(graph,shape.getResource());\r
469         assert (modelResource != null);\r
470         G3DModel model = new G3DModel(graph,modelResource.getResource());\r
471         Collection<org.simantics.animation.stubs.Animation> animations = model.getAnimation();\r
472         boolean found = false;\r
473         for (org.simantics.animation.stubs.Animation a : animations) {\r
474             if (a.getResource().equals(animation.getResource())) {\r
475                 found = true;\r
476                 break;\r
477             }\r
478         }\r
479         if (!found) {\r
480             ErrorLogger.getDefault().logWarning("Shape " + shape.getResource() + " cannot handle animation " + animation.getResource() + " because it isn't model's animation", null);\r
481             return false;\r
482         }\r
483         Collection<org.simantics.animation.stubs.Interpolator> interpolators = animation.getInterpolator();\r
484         List<org.simantics.animation.stubs.Interpolator> handled = new ArrayList<org.simantics.animation.stubs.Interpolator>();\r
485         List<org.simantics.animation.stubs.Interpolator> precalculated = new ArrayList<org.simantics.animation.stubs.Interpolator>();\r
486         for (org.simantics.animation.stubs.Interpolator i : interpolators) {\r
487             IEntity target = i.getTarget();\r
488             if (G3DTools.hasProperty(graph,shape.getResource(),target.getResource()))\r
489                 handled.add(i);\r
490             else if (G3DTools.hasSubProperty(graph,shape.getResource(),target.getResource())) {\r
491                 precalculated.add(i);\r
492             }\r
493         }\r
494         if (handled.size() == 0 && precalculated.size() == 0) {\r
495             ErrorLogger.getDefault().logWarning("Shape " + shape.getResource() + " cannot handle animation " + animation.getResource() + " since it doesn't change any of shape's properties", null);\r
496             return false;\r
497         }\r
498         \r
499         \r
500         this.animation = new Animation();\r
501         \r
502         org.simantics.animation.stubs.Interpolator[] pos = new org.simantics.animation.stubs.Interpolator[3];\r
503         org.simantics.animation.stubs.Interpolator[] ambient = new org.simantics.animation.stubs.Interpolator[3];\r
504         org.simantics.animation.stubs.Interpolator[] diffuse = new org.simantics.animation.stubs.Interpolator[3];\r
505         org.simantics.animation.stubs.Interpolator[] specular = new org.simantics.animation.stubs.Interpolator[3];\r
506         org.simantics.animation.stubs.Interpolator[] emissive = new org.simantics.animation.stubs.Interpolator[3];\r
507 \r
508         Builtins builtins = graph.getBuiltins();\r
509 \r
510         \r
511         for (org.simantics.animation.stubs.Interpolator i : handled) {\r
512             IEntity target = i.getTarget();\r
513             //if (target.isInstanceOf(Resources.g3dResource.LocalOrientation)) {\r
514             if (target.isInstanceOf(Resources.g3dResource.Orientation) && target.getRelatedObjects(Resources.g3dResource.LocalOrientationOf).size() == 1) {\r
515                 SlerpInterpolator si = new SlerpInterpolator((SlerpCurve)Resources.curveBuilder.loadInterpolator(i));\r
516                 si.setTarget(transform);\r
517                 this.animation.addInterpolator(si);\r
518             } else if (target.isInstanceOf(builtins.Double)) {\r
519                 Resource targetResource = target.getResource();\r
520                 Collection<IEntity> p = target.getRelatedObjects(builtins.PropertyOf);\r
521                 if (p.size() == 1) {\r
522                     IEntity parent = p.iterator().next();\r
523                     //if (parent.isInstanceOf(Resources.g3dResource.LocalPosition)) {\r
524                     if (parent.isInstanceOf(Resources.g3dResource.Position) && parent.getRelatedObjects(Resources.g3dResource.LocalPositionOf).size() == 1) {\r
525                         if (parent.getSingleRelatedObject(Resources.g3dResource.HasX).getResource().equals(targetResource)) {\r
526                              pos[0] = i;\r
527                         } else if (parent.getSingleRelatedObject(Resources.g3dResource.HasY).getResource().equals(targetResource)) {\r
528                             pos[1] = i;\r
529                         } else if (parent.getSingleRelatedObject(Resources.g3dResource.HasZ).getResource().equals(targetResource)) {\r
530                             pos[2] = i;\r
531                         } else {\r
532                             ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target (Position ?)" + target.getResource(),  null);\r
533                         }\r
534                     } else if (parent.isInstanceOf(Resources.g3dResource.Color)) {\r
535                         org.simantics.animation.stubs.Interpolator[] color = null;\r
536                         if (parent.isInstanceOf(Resources.g3dResource.Color) && parent.getRelatedObjects(Resources.g3dResource.AmbientColorOf).size() > 0) {\r
537                                 color = ambient;\r
538                         } else if (parent.isInstanceOf(Resources.g3dResource.Color)&& parent.getRelatedObjects(Resources.g3dResource.DiffuseColorOf).size() > 0) {\r
539                                 color = diffuse;\r
540                         } else if (parent.isInstanceOf(Resources.g3dResource.Color) && parent.getRelatedObjects(Resources.g3dResource.SpecularColorOf).size() > 0) {\r
541                                 color = specular;\r
542                         } else if (parent.isInstanceOf(Resources.g3dResource.Color) && parent.getRelatedObjects(Resources.g3dResource.EmissiveColorOf).size() > 0) {\r
543                                 color = emissive;\r
544                         } else {\r
545                             ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target (Color)" + target.getResource() + " unknown color type",  null);\r
546                         }\r
547                         if (color != null) {\r
548                             if (parent.getSingleRelatedObject(Resources.g3dResource.HasRed).getResource().equals(targetResource)) {\r
549                                 color[0] = i;\r
550                             } else if (parent.getSingleRelatedObject(Resources.g3dResource.HasGreen).getResource().equals(targetResource)) {\r
551                                 color[1] = i;\r
552                             } else if (parent.getSingleRelatedObject(Resources.g3dResource.HasBlue).getResource().equals(targetResource)) {\r
553                                 color[2] = i;\r
554                             } else {\r
555                                 ErrorLogger.getDefault().logWarning(\r
556                                         "Cannot map animation interpolator " + i.getResource()\r
557                                                 + " to target (Color ?)" + target.getResource(), null);\r
558                             }\r
559                         }\r
560                     } else if (parent.isInstanceOf(Resources.g3dResource.Material)) {\r
561                         // TODO : transparency or shininess     \r
562                     } else {\r
563                         ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target" + target.getResource() + " adding it to precalculated interpolators",  null);\r
564                         precalculated.add(i);\r
565                     }\r
566                 } else {\r
567                     if (p.size() == 0) {\r
568                         ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target (Double)" + target.getResource() + " since it is not a part of a property",  null);\r
569                     } else {\r
570                         ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target (Double)" + target.getResource() + " since it acts as a property to more than one entity",  null);  \r
571                     }\r
572                 }\r
573             } else {\r
574                 ErrorLogger.getDefault().logWarning("Cannot map animation interpolator " + i.getResource() + " to target" + target.getResource(),  null);\r
575             }\r
576         }\r
577         \r
578         if (pos[0] != null || pos[1] != null || pos[2] != null) {\r
579             ScalarInterpolator xIp;\r
580             ScalarInterpolator yIp;\r
581             ScalarInterpolator zIp;\r
582             if (pos[0] != null) {\r
583                 xIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(pos[0]));\r
584             } else {\r
585                 xIp = new ConstantInterpolator(shape.getLocalPosition().getX()[0]);\r
586             }\r
587             if (pos[1] != null) {\r
588                 yIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(pos[1]));\r
589             } else {\r
590                 yIp = new ConstantInterpolator(shape.getLocalPosition().getY()[0]);\r
591             }\r
592             if (pos[2] != null) {\r
593                 zIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(pos[2]));\r
594             } else {\r
595                 zIp = new ConstantInterpolator(shape.getLocalPosition().getZ()[0]);\r
596             }\r
597             ChanneledPositionInterpolator ip = new ChanneledPositionInterpolator(xIp,yIp,zIp);\r
598             ip.setTarget(transform);\r
599             this.animation.addInterpolator(ip);\r
600         \r
601         }  \r
602         addColorInterpolator(shape, ambient, ChanneledColorInterpolator.AMBIENT);\r
603         addColorInterpolator(shape, diffuse, ChanneledColorInterpolator.DIFFUSE);\r
604         addColorInterpolator(shape, emissive, ChanneledColorInterpolator.EMISSIVE);\r
605         addColorInterpolator(shape, specular, ChanneledColorInterpolator.SPECULAR);\r
606         \r
607         if (precalculated.size() == 0) {\r
608             preCalc = null;\r
609         } else {\r
610                 preCalc = new Geometry[preCalcSteps+1];\r
611                 for (int i = 0; i <= preCalcSteps; i++) {\r
612                     double delta = ((double)i / (double)preCalcSteps);\r
613                     // TODO : copy-paste from CSGAnimatorView\r
614                     // FIXME : does not update transformations (since ContextGraph does not support queries for context dependent values)\r
615                     for (Interpolator ip : precalculated) {\r
616                         if (ip.isInstanceOf(Resources.animationResource.ScalarInterpolator)) {\r
617                             // TODO : creating curve each time when time is set is slow.\r
618                             // Curve should be cached\r
619                             TCBCurve c = (TCBCurve)Resources.curveBuilder.loadInterpolator(ip);\r
620                             double out = c.evaluate(delta);\r
621                             //Double d = DoubleFactory.create(ip.getTarget());\r
622                             //d.setValue(new double[]{out});\r
623                             IEntity d = ip.getTarget();\r
624                             d.toProperty().setDoubleArray(new double[]{out});\r
625                         } else if (ip.isInstanceOf(Resources.animationResource.SlerpInterpolator)) {\r
626                             // TODO : creating curve each time when time is set is slow.\r
627                             // Curve should be cached\r
628                             SlerpCurve c = (SlerpCurve)Resources.curveBuilder.loadInterpolator(ip);\r
629                             Quat4d out = c.evaluate(delta);\r
630                             Orientation r = new Orientation(ip.getTarget());\r
631                             AxisAngle4d aa = new AxisAngle4d();\r
632                             aa.set(out);\r
633                             G3DTools.setOrientation(r, aa);\r
634                         }\r
635                     }\r
636                     preCalc[i] = getGeometry(graph,false)[0];\r
637                     preCalc[i].setIsCollidable(false);\r
638                     AppearanceTools.copyMaterial(mesh, preCalc[i]);\r
639                 }\r
640                 \r
641                 // We'll have to remove original (non-animated) shape from the node\r
642                 mesh.removeFromParent();\r
643                 body.attachChild(preCalc[0]);\r
644            \r
645         }\r
646         return true;\r
647     }\r
648     \r
649     private void addColorInterpolator(G3DNode shape, org.simantics.animation.stubs.Interpolator[] color, int type) {\r
650         if (color[0] != null || color[1] != null || color[2] != null) {\r
651             ScalarInterpolator xIp;\r
652             ScalarInterpolator yIp;\r
653             ScalarInterpolator zIp;\r
654             Color col = null;\r
655             Collection<IEntity> appearanceResource = shape.getRelatedObjects(Resources.g3dResource.HasAppearance);\r
656             if (appearanceResource.size() == 0) {\r
657                 ErrorLogger.getDefault().logWarning("Cannot create interpolator for color because shape " + shape.getResource() + " has no appearance", null);\r
658             }\r
659             Appearance a = new Appearance(shape.getGraph(),appearanceResource.iterator().next().getResource());\r
660             switch (type) {\r
661                 case ChanneledColorInterpolator.AMBIENT:\r
662                     col = a.getMaterial().getAmbientColor();\r
663                     break;\r
664                 case ChanneledColorInterpolator.DIFFUSE:\r
665                     col = a.getMaterial().getDiffuseColor();\r
666                     break;\r
667                 case ChanneledColorInterpolator.EMISSIVE:\r
668                     col = a.getMaterial().getEmissiveColor();\r
669                     break;\r
670                 case ChanneledColorInterpolator.SPECULAR:\r
671                     col = a.getMaterial().getSpecularColor();\r
672                     break;\r
673                 default:\r
674                     ErrorLogger.defaultLogError("Unknown color type", null);\r
675                     return;\r
676             }\r
677 \r
678             if (color[0] != null) {\r
679                 xIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(color[0]));//CurveUtils.loadCurve(color[0].getResource()));\r
680             } else {\r
681                 xIp = new ConstantInterpolator(col.getRed()[0]);\r
682             }\r
683             if (color[1] != null) {\r
684                 yIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(color[1]));//CurveUtils.loadCurve(color[1].getResource()));\r
685             } else {\r
686                 yIp = new ConstantInterpolator(col.getGreen()[0]);\r
687             }\r
688             if (color[1] != null) {\r
689                 zIp = new TCBInterpolator((TCBCurve)Resources.curveBuilder.loadInterpolator(color[2]));//CurveUtils.loadCurve(color[2].getResource()));\r
690             } else {\r
691                 zIp = new ConstantInterpolator(col.getBlue()[0]);\r
692             }\r
693             ChanneledColorInterpolator ip = new ChanneledColorInterpolator(xIp,yIp,zIp);\r
694             ip.setType(type);\r
695             ip.setTarget(mesh.getRenderState(RenderState.RS_MATERIAL));\r
696             this.animation.addInterpolator(ip);\r
697         } \r
698     }\r
699     \r
700     public boolean setRandomAnimation(Graph graph) {\r
701         return false;\r
702     }\r
703     \r
704     public void dispose() {\r
705 //      mesh.clearBuffers();\r
706 //      mesh.clearBatches();\r
707 //      lines.clearBuffers();\r
708 //      lines.clearBatches();\r
709         if (mesh != null) {\r
710                 mesh.removeFromParent();\r
711                 mesh.dispose();\r
712                 mesh = null;\r
713         }\r
714         if (lines != null) {\r
715                 lines.removeFromParent();\r
716                 lines.dispose();\r
717                 lines = null;\r
718         }\r
719         super.dispose();\r
720     }\r
721 }