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