1 package org.simantics.proconf.g3d.shapeeditor.tools;
\r
3 import java.util.ArrayList;
\r
4 import java.util.Collection;
\r
5 import java.util.List;
\r
7 import javax.vecmath.AxisAngle4d;
\r
8 import javax.vecmath.Quat4d;
\r
10 import org.eclipse.jface.action.IMenuManager;
\r
11 import org.eclipse.jface.action.IToolBarManager;
\r
12 import org.eclipse.jface.dialogs.Dialog;
\r
13 import org.eclipse.jface.dialogs.InputDialog;
\r
14 import org.eclipse.jface.dialogs.MessageDialog;
\r
15 import org.eclipse.jface.viewers.ISelectionChangedListener;
\r
16 import org.eclipse.jface.viewers.SelectionChangedEvent;
\r
17 import org.eclipse.swt.SWT;
\r
18 import org.eclipse.swt.custom.CCombo;
\r
19 import org.eclipse.swt.events.FocusAdapter;
\r
20 import org.eclipse.swt.events.FocusEvent;
\r
21 import org.eclipse.swt.events.KeyAdapter;
\r
22 import org.eclipse.swt.events.KeyEvent;
\r
23 import org.eclipse.swt.events.SelectionAdapter;
\r
24 import org.eclipse.swt.events.SelectionEvent;
\r
25 import org.eclipse.swt.layout.FillLayout;
\r
26 import org.eclipse.swt.layout.FormAttachment;
\r
27 import org.eclipse.swt.layout.FormData;
\r
28 import org.eclipse.swt.layout.FormLayout;
\r
29 import org.eclipse.swt.layout.GridData;
\r
30 import org.eclipse.swt.layout.GridLayout;
\r
31 import org.eclipse.swt.widgets.Button;
\r
32 import org.eclipse.swt.widgets.Composite;
\r
33 import org.eclipse.swt.widgets.Slider;
\r
34 import org.eclipse.swt.widgets.Text;
\r
35 import org.simantics.db.ContextGraph;
\r
36 import org.simantics.db.Graph;
\r
37 import org.simantics.db.GraphRequestAdapter;
\r
38 import org.simantics.db.GraphRequestStatus;
\r
39 import org.simantics.db.GraphRequestWithResult;
\r
40 import org.simantics.db.Resource;
\r
41 import org.simantics.g2d.stubs.anim.Animation;
\r
42 import org.simantics.g2d.stubs.anim.Interpolator;
\r
43 import org.simantics.g2d.stubs.anim.ScalarInterpolator;
\r
44 import org.simantics.g2d.stubs.anim.SlerpInterpolator;
\r
45 import org.simantics.layer0.utils.EntityFactory;
\r
46 import org.simantics.layer0.utils.IEntity;
\r
47 import org.simantics.layer0.utils.Property;
\r
48 import org.simantics.animation.curve.SlerpCurve;
\r
49 import org.simantics.animation.curve.TCBCurve;
\r
50 import org.simantics.proconf.g3d.actions.ContextAction;
\r
51 import org.simantics.proconf.g3d.actions.RotateAction;
\r
52 import org.simantics.proconf.g3d.actions.TranslateAction;
\r
53 import org.simantics.proconf.g3d.animation.Animatable;
\r
54 import org.simantics.proconf.g3d.base.EditorContribution;
\r
55 import org.simantics.proconf.g3d.base.G3DTools;
\r
56 import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;
\r
57 import org.simantics.proconf.g3d.base.VisualizationScheduler;
\r
58 import org.simantics.proconf.g3d.common.StructuredResourceSelection;
\r
59 import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;
\r
60 import org.simantics.proconf.g3d.scenegraph.ISelectableNode;
\r
61 import org.simantics.proconf.g3d.shapeeditor.ShapeEditorResources;
\r
62 import org.simantics.proconf.g3d.shapeeditor.dialogs.PropertySelectionDialog;
\r
63 import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase;
\r
64 import org.simantics.proconf.g3d.stubs.G3DModel;
\r
65 import org.simantics.proconf.g3d.stubs.Orientation;
\r
66 import org.simantics.utils.ui.ErrorLogger;
\r
68 public class AnimationContribution implements EditorContribution {
\r
69 List<ContextAction> actions = new ArrayList<ContextAction>();
\r
71 private ShapeEditorBase parent;
\r
73 private final String NO_ANIMATION = "None";
\r
75 private Slider timeSlider;
\r
76 private double key = 0;
\r
77 private Composite buttonComposite;
\r
78 private Button insertKeyFrameButton;
\r
79 private Button clearKeyFrameButton;
\r
80 private CCombo animationCombo;
\r
81 private Button addAnimationButton;
\r
82 private Button removeAnimationButton;
\r
83 private Button clearAnimationButton;
\r
84 private Button animateButton;
\r
85 private Button usePrecalculation;
\r
86 private Text timeText;
\r
87 private Composite infoComposite;
\r
88 private Text infoText;
\r
90 private Resource animationResource;
\r
92 private ContextAction translateAction;
\r
93 private ContextAction rotateAction;
\r
95 public AnimationContribution(ThreeDimensionalEditorBase parent) {
\r
96 this.parent = (ShapeEditorBase)parent;
\r
100 public String getName() {
\r
105 public void createControl(Composite parent) {
\r
106 FormLayout flayout = new FormLayout();
\r
107 parent.setLayout(flayout);
\r
108 infoComposite = new Composite(parent, SWT.BORDER);
\r
109 FormData data = new FormData();
\r
110 data.top = new FormAttachment(0, 0);
\r
111 data.left = new FormAttachment(0, 0);
\r
112 data.right = new FormAttachment(100, 0);
\r
113 data.bottom = new FormAttachment(infoComposite, 0, SWT.TOP);
\r
114 this.parent.getRenderingComposite().setLayoutData(data);
\r
116 infoComposite.setLayout(new FillLayout(SWT.VERTICAL));
\r
117 infoText = new Text(infoComposite, SWT.NONE);
\r
118 GridLayout layout = new GridLayout(2, false);
\r
119 layout.horizontalSpacing = 2;
\r
120 layout.verticalSpacing = 2;
\r
121 layout.marginWidth = 1;
\r
122 layout.marginHeight = 1;
\r
123 infoComposite.setLayout(layout);
\r
124 GridData gdata = new GridData(SWT.BEGINNING, SWT.CENTER, true, false, 2, 1);
\r
125 // FIXME : allows text widget to take all available space (horizontal / width)
\r
126 gdata.widthHint = 2000;
\r
127 infoText.setLayoutData(gdata);
\r
128 timeSlider = new Slider(infoComposite, SWT.NONE);
\r
129 timeSlider.setValues(0, 0, 100, 1, 1, 1);
\r
130 timeSlider.addSelectionListener(new SelectionAdapter() {
\r
132 public void widgetSelected(SelectionEvent e) {
\r
133 key = ((double) timeSlider.getSelection()) / 100.0;
\r
137 timeSlider.setLayoutData(new GridData(SWT.FILL, 1, true, false));
\r
138 timeText = new Text(infoComposite, SWT.SINGLE);
\r
139 timeText.addFocusListener(new FocusAdapter() {
\r
141 public void focusLost(FocusEvent e) {
\r
145 timeText.addKeyListener(new KeyAdapter() {
\r
147 public void keyReleased(KeyEvent e) {
\r
148 if (e.keyCode == SWT.CR)
\r
153 buttonComposite = new Composite(infoComposite, SWT.NONE);
\r
154 buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL));
\r
155 buttonComposite.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, false, 2, 1));
\r
156 insertKeyFrameButton = new Button(buttonComposite, SWT.PUSH);
\r
157 insertKeyFrameButton.setText("Insert Keyframe");
\r
158 insertKeyFrameButton.addSelectionListener(new SelectionAdapter() {
\r
159 public void widgetSelected(SelectionEvent e) {
\r
164 clearKeyFrameButton = new Button(buttonComposite, SWT.PUSH);
\r
165 clearKeyFrameButton.setText("Clear Keyframe");
\r
167 animationCombo = new CCombo(buttonComposite, SWT.NONE);
\r
168 animationCombo.add(NO_ANIMATION);
\r
169 animationCombo.select(0);
\r
170 animationCombo.setEditable(false);
\r
171 animationCombo.addSelectionListener(new SelectionAdapter() {
\r
172 public void widgetSelected(SelectionEvent e) {
\r
177 addAnimationButton = new Button(buttonComposite, SWT.PUSH);
\r
178 addAnimationButton.setText("New Animation");
\r
179 addAnimationButton.addSelectionListener(new SelectionAdapter() {
\r
180 public void widgetSelected(SelectionEvent e) {
\r
185 clearAnimationButton = new Button(buttonComposite, SWT.PUSH);
\r
186 clearAnimationButton.setText("Clear Animation");
\r
187 clearAnimationButton.addSelectionListener(new SelectionAdapter() {
\r
188 public void widgetSelected(SelectionEvent e) {
\r
193 removeAnimationButton = new Button(buttonComposite, SWT.PUSH);
\r
194 removeAnimationButton.setText("Remove Animation");
\r
195 removeAnimationButton.addSelectionListener(new SelectionAdapter() {
\r
196 public void widgetSelected(SelectionEvent e) {
\r
201 animateButton = new Button(buttonComposite, SWT.TOGGLE);
\r
202 animateButton.setText("Animate");
\r
203 animateButton.addSelectionListener(new SelectionAdapter() {
\r
204 public void widgetSelected(SelectionEvent e) {
\r
209 usePrecalculation = new Button(buttonComposite, SWT.CHECK);
\r
210 usePrecalculation.setText("Precalc");
\r
212 data = new FormData();
\r
213 data.left = new FormAttachment(0, 0);
\r
214 data.right = new FormAttachment(100, 0);
\r
215 data.bottom = new FormAttachment(100, 0);
\r
216 // FIXME : take account font size
\r
217 data.height = 20 * 3;
\r
218 infoComposite.setLayoutData(data);
\r
220 this.parent.getSelectionAdapter().addSelectionChangedListener(new ISelectionChangedListener() {
\r
221 public void selectionChanged(SelectionChangedEvent event) {
\r
227 this.parent.getSession().asyncRead(new GraphRequestAdapter() {
\r
229 public GraphRequestStatus perform(Graph g) throws Exception {
\r
230 G3DModel m = new G3DModel(g,AnimationContribution.this.parent.getModelResource());
\r
231 Collection<Animation> animations = m.getAnimation();
\r
233 final List<String> animationNames = new ArrayList<String>();
\r
234 for (Animation a : animations) {
\r
235 animationNames.add(a.getName());
\r
237 AnimationContribution.this.parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {
\r
238 public void run() {
\r
239 for (String s : animationNames)
\r
240 animationCombo.add(s);
\r
243 return GraphRequestStatus.transactionComplete();
\r
250 public void disposeControl() {
\r
251 if (animateRunnable != null)
\r
252 VisualizationScheduler.getInstance().removeVisualization(animateRunnable);
\r
253 animateRunnable = null;
\r
255 infoComposite.dispose();
\r
260 public void fillContextMenu(Graph graph, IMenuManager manager, StructuredResourceSelection selection) {
\r
267 public Collection<ContextAction> getActions() {
\r
272 public void initialize(Graph graph) {
\r
273 actions.add(translateAction = new TranslateAction(parent) {
\r
275 public void setInfoText(String text) {
\r
276 infoText.setText(text);
\r
279 actions.add(rotateAction = new RotateAction(parent){
\r
281 public void setInfoText(String text) {
\r
282 infoText.setText(text);
\r
287 private double getCurrentKey() {
\r
291 private void updateTime() {
\r
292 final double t = getCurrentKey();
\r
293 timeText.setText(Double.toString(t));
\r
294 if (animationResource == null)
\r
296 if (usePrecalculation.getSelection()) {
\r
297 for (IGraphicsNode n : parent.getScenegraphAdapter().getNodes()) {
\r
298 if (n instanceof Animatable) {
\r
299 // TODO : frame-rate dependent animations
\r
300 ((Animatable)n).animate(t,0.0);
\r
302 parent.setViewChanged(true);
\r
305 parent.getSession().asyncWrite(new GraphRequestAdapter() {
\r
307 public GraphRequestStatus perform(Graph g) throws Exception {
\r
308 Collection<IEntity> interpolators = getAnimation(g).getRelatedObjects(ShapeEditorResources.animationResource.HasInterpolator);
\r
309 for (IEntity i : interpolators) {
\r
310 if (i.isInstanceOf(ShapeEditorResources.animationResource.ScalarInterpolator)) {
\r
311 // TODO : creating curve each time when time is set is
\r
312 // slow. Curve should be cached
\r
313 TCBCurve c = (TCBCurve) ShapeEditorResources.curveBuilder.loadInterpolator(i);
\r
314 double out = c.evaluate(t);
\r
315 g.setScalarDouble(i.getSingleRelatedObject(ShapeEditorResources.animationResource.HasTarget).getResource(), out);
\r
316 } else if (i.isInstanceOf(ShapeEditorResources.animationResource.SlerpInterpolator)) {
\r
317 // TODO : creating curve each time when time is set is slow.
\r
318 // Curve should be cached
\r
319 SlerpCurve c = (SlerpCurve) ShapeEditorResources.curveBuilder.loadInterpolator(i);
\r
320 Quat4d out = c.evaluate(t);
\r
321 Orientation r = new Orientation(i.getSingleRelatedObject(ShapeEditorResources.animationResource.HasTarget));
\r
322 AxisAngle4d aa = new AxisAngle4d();
\r
324 G3DTools.setOrientation(r, aa);
\r
327 return GraphRequestStatus.transactionComplete();
\r
331 public void requestCompleted(GraphRequestStatus status) {
\r
332 parent.getScenegraphAdapter().setChanged(true);
\r
338 private IEntity findPropertyInterpolator(Graph g, Resource property) {
\r
339 Collection<IEntity> interpolators = getAnimation(g).getRelatedObjects(ShapeEditorResources.animationResource.HasInterpolator);
\r
340 for (IEntity i : interpolators) {
\r
341 IEntity e = i.getAtMostOneRelatedObject(ShapeEditorResources.animationResource.HasTarget);
\r
344 if (e.getResource().equals(property)) {
\r
351 private void insertKeyFrame() {
\r
352 ArrayList<Resource> instances = new ArrayList<Resource>();
\r
353 for (Resource rs : parent.getSelectionAdapter().getCurrentSelection().getSelectionList()) {
\r
356 PropertySelectionDialog dialog = new PropertySelectionDialog(parent.getRenderingComposite().getShell(),"Select property","Select animated property",parent.getSession(),instances);
\r
357 if (dialog.open() == Dialog.CANCEL) {
\r
360 final List<Resource> properties = dialog.getSelectedPropertyInstances();
\r
361 parent.getSession().asyncWrite(new GraphRequestAdapter() {
\r
363 public GraphRequestStatus perform(Graph g) throws Exception {
\r
364 for (Resource r : properties) {
\r
365 IEntity t = EntityFactory.create(g,r);
\r
366 IEntity current = findPropertyInterpolator(g, r);
\r
367 if (t.isInstanceOf(ShapeEditorResources.g3dResource.Position)) {
\r
369 for (int i = 0; i < 3; i++) {
\r
373 d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasX);
\r
376 d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasY);
\r
379 d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasZ);
\r
382 current = findPropertyInterpolator(g, d.getResource());
\r
383 addScalarKey(current,d);
\r
386 } else if (t.isInstanceOf(ShapeEditorResources.g3dResource.Orientation)) {
\r
387 Orientation rot = new Orientation(t);
\r
388 addSlerpKey(current, rot);
\r
389 } else if (t.isInstanceOf(ShapeEditorResources.g3dResource.Color)) {
\r
390 for (int i = 0; i < 3; i++) {
\r
394 d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasRed);
\r
401 current = findPropertyInterpolator(g, d.getResource());
\r
402 addScalarKey(current,d);
\r
404 } else if (t.isInstanceOf(g.getBuiltins().Double)) {
\r
405 addScalarKey(current,t);
\r
407 // TODO: basic cases are handled, only way to support
\r
408 // is to find all doubles from property structure and
\r
409 // interpolators attached to them, if there's any
\r
410 ErrorLogger.getDefault().logWarning("Default keyframe adding has not been implemented", null);
\r
413 return GraphRequestStatus.transactionComplete();
\r
418 private void addScalarKey(IEntity current, IEntity d) {
\r
420 Graph graph = d.getGraph();
\r
421 if (current == null) {
\r
422 current = ScalarInterpolator.createDefault(graph).toInterpolator(); // FIXME : stubcast
\r
423 getAnimation(graph).addStatement(ShapeEditorResources.animationResource.HasInterpolator, current);
\r
424 current.addStatement(ShapeEditorResources.animationResource.HasTarget, d);
\r
426 ShapeEditorResources.curveBuilder.addKey(current,getCurrentKey(),new double[]{d.getGraph().getScalarDouble(d.getResource()),0.0,0.0,0.0});
\r
429 private void addSlerpKey(IEntity current, Orientation r) {
\r
430 Graph graph = r.getGraph();
\r
431 if (current == null) {
\r
432 current = SlerpInterpolator.createDefault(graph).toInterpolator(); // FIXME : stubcast
\r
433 getAnimation(graph).addStatement(ShapeEditorResources.animationResource.HasInterpolator, current);
\r
434 current.addStatement(ShapeEditorResources.animationResource.HasTarget, r);
\r
437 AxisAngle4d aa = G3DTools.getOrientation(r);
\r
438 Quat4d q = new Quat4d();
\r
440 ShapeEditorResources.curveBuilder.addKey(current,getCurrentKey(),new double[]{q.w,q.x,q.y,q.z});
\r
443 private void selectAnimation() {
\r
444 if (animationCombo.getSelectionIndex() == 0) {
\r
445 animationResource = null;
\r
448 final String name = animationCombo.getItem(animationCombo.getSelectionIndex());
\r
449 parent.getSession().asyncRead(new GraphRequestAdapter() {
\r
451 public GraphRequestStatus perform(Graph g) throws Exception {
\r
453 Resource modelResource = parent.getModelResource();
\r
454 G3DModel m = new G3DModel(g, modelResource);
\r
455 Collection<Animation> animations = m.getAnimation();
\r
456 boolean found = false;
\r
457 for (Animation a : animations) {
\r
458 if (a.getName().startsWith(name) && a.getName().length() == name.length()) {
\r
459 animationResource = a.getResource();
\r
465 ErrorLogger.defaultLogError("Could find animation " + name + " for model " + m.getResource(), null);
\r
466 animationResource = null;
\r
468 return GraphRequestStatus.transactionComplete();
\r
471 public void requestCompleted(GraphRequestStatus status) {
\r
472 parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {
\r
474 public void run() {
\r
483 private Animation getAnimation(Graph graph) {
\r
484 return new Animation(graph, animationResource);
\r
487 private void addAnimation() {
\r
488 InputDialog d = new InputDialog(parent.getRenderingComposite().getShell(),"Animation name","Animation name","",null);
\r
489 if (d.open() == InputDialog.CANCEL) {
\r
492 final String name = d.getValue();
\r
493 if (name == null || name.length() == 0) {
\r
496 parent.getSession().asyncWrite(new GraphRequestAdapter() {
\r
498 public GraphRequestStatus perform(Graph g) throws Exception {
\r
499 G3DModel m = parent.getModel(g);
\r
500 Collection<IEntity> animations = m.getRelatedObjects(ShapeEditorResources.animationResource.HasAnimation);
\r
501 for (IEntity a : animations) {
\r
502 if (a.getName().startsWith(name) && a.getName().length() == name.length()) {
\r
503 ErrorLogger.getDefault().logWarning("Cannot add animation with the same name " + name, null);
\r
504 return GraphRequestStatus.transactionCancel();
\r
508 Animation newAnimation = Animation.createDefault(g);
\r
509 newAnimation.setName(name);
\r
510 m.addStatement(ShapeEditorResources.animationResource.HasAnimation, newAnimation);
\r
512 return GraphRequestStatus.transactionComplete();
\r
516 public void requestCompleted(GraphRequestStatus status) {
\r
517 parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {
\r
518 public void run() {
\r
519 animationCombo.add(name);
\r
520 animationCombo.select(animationCombo.indexOf(name));
\r
528 private void removeAnimation() {
\r
529 assert(animationResource != null);
\r
530 GraphRequestWithResult<String> r = new GraphRequestWithResult<String>() {
\r
531 public String performWithResult(Graph g) throws Exception {
\r
532 return getAnimation(g).getName();
\r
535 parent.getSession().syncRead(r);
\r
536 MessageDialog dialog = new MessageDialog(parent.getRenderingComposite().getShell(),"Confirm",null,"Do you want to remove animation " + r.getResult() ,MessageDialog.QUESTION,new String[]{"Yes","No"},1);
\r
537 if (dialog.open() == 1)
\r
539 parent.getSession().asyncWrite(new GraphRequestAdapter() {
\r
542 public GraphRequestStatus perform(Graph g) throws Exception {
\r
544 Animation currentAnimation = getAnimation(g);
\r
545 name = currentAnimation.getName();
\r
546 parent.getModel(g).removeStatement(ShapeEditorResources.animationResource.HasAnimation, currentAnimation);
\r
548 return GraphRequestStatus.transactionComplete();
\r
552 public void requestCompleted(GraphRequestStatus status) {
\r
553 parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {
\r
554 public void run() {
\r
555 animationCombo.remove(animationCombo.indexOf(name));
\r
562 private void clearAnimation() {
\r
563 assert(animationResource != null);
\r
565 parent.getSession().asyncWrite(new GraphRequestAdapter() {
\r
569 public GraphRequestStatus perform(Graph g) throws Exception {
\r
570 int size = getAnimation(g).getInterpolator().size();
\r
572 return GraphRequestStatus.transactionCancel();
\r
573 final String name = getAnimation(g).getName();
\r
574 parent.getRenderingComposite().getDisplay().syncExec(new Runnable() {
\r
575 public void run() {
\r
576 MessageDialog dialog = new MessageDialog(parent.getRenderingComposite().getShell(),"Confirm",null,"Do you want to clear animation " + name ,MessageDialog.QUESTION,new String[]{"Yes","No"},1);
\r
577 proceed = (dialog.open() != MessageDialog.CANCEL);
\r
581 //getAnimation(g).getInterpolator().clear();
\r
582 getAnimation(g).removeRelatedStatements(ShapeEditorResources.animationResource.HasInterpolator);
\r
583 return GraphRequestStatus.transactionComplete();
\r
585 return GraphRequestStatus.transactionCancel();
\r
591 public Graph createAnimationParameterization(Graph g) {
\r
592 if (g.getObjects(parent.getModelResource(), ShapeEditorResources.g3dResource.HasSizingParameter).size() > 0) {
\r
593 ContextGraph graph;
\r
594 if (!(g instanceof ContextGraph)) {
\r
595 graph = new ContextGraph(g);
\r
596 graph.setContext(parent.getModelResource());
\r
598 graph = (ContextGraph)g;
\r
600 Animation animation = getAnimation(graph);
\r
601 Collection<Interpolator> interpolators = animation.getInterpolator();
\r
602 for (org.simantics.g2d.stubs.anim.Interpolator interpolator : interpolators) {
\r
603 IEntity target = interpolator.getTarget();
\r
604 // check all model properties
\r
605 G3DModel model = parent.getModel(graph);
\r
606 Collection<Property> modelProperties = model.getRelatedProperties(ShapeEditorResources.g3dResource.HasSizingParameter);
\r
607 for (Property p : modelProperties) {
\r
608 IEntity t = EntityFactory.create(graph,p.getResource());
\r
609 // get parameterization equations
\r
610 Collection<IEntity> equations = t.getRelatedObjects(ShapeEditorResources.equationResource.HasTarget);
\r
611 // get parameterized values
\r
612 Collection<IEntity> parameterTargets = new ArrayList<IEntity>();
\r
613 for (IEntity eq : equations) {
\r
614 Collection<IEntity> tgts = eq.getRelatedObjects(ShapeEditorResources.equationResource.HasTarget);
\r
615 assert(tgts.size() == 1);
\r
616 parameterTargets.add(tgts.iterator().next());
\r
618 // do matching between interpolator targets and parameterized values
\r
619 // TODO : old system did not have inverse relations but current system does.
\r
620 // it is possible to take interpolation target and find if it is connected to an equation
\r
621 // this would make code much faster (no more stupid loops over everything)
\r
622 for (IEntity d : parameterTargets) {
\r
623 if (d.getResource().equals(target.getResource())) {
\r
624 // get default value for sizing property
\r
625 Collection<IEntity> prop = t.getRelatedObjects(ShapeEditorResources.g3dResource.HasDefaultDoubleValue);
\r
626 if (prop.size() == 1) {
\r
627 ShapeEditorResources.curveBuilder.parameterize(interpolator, prop.iterator().next().toProperty().getDoubleArray(), p.getDoubleArray());
\r
629 ErrorLogger.defaultLogError("Cannot parameterize interpolator " + interpolator.getResource() + " of animation " + animation.getResource() + " since parameter " + p.getResource() + " has no default value", null);
\r
642 private AnimateRunnable animateRunnable = null;
\r
644 private void animate() {
\r
646 if (animateButton.getSelection()) {
\r
647 if (animateRunnable != null)
\r
649 if (usePrecalculation.getSelection()) {
\r
650 parent.getSession().asyncRead(new GraphRequestAdapter() {
\r
652 public GraphRequestStatus perform(Graph g) throws Exception {
\r
653 Graph graph = parent.createParameterization(g);
\r
654 createAnimationParameterization(graph);
\r
655 for (IGraphicsNode n : parent.getScenegraphAdapter().getNodes()) {
\r
656 if (n instanceof ISelectableNode) {
\r
657 if (!((ISelectableNode)n).isVisible())
\r
660 if (n instanceof Animatable) {
\r
661 ((Animatable)n).setAnimation(graph,animationResource);
\r
664 return GraphRequestStatus.transactionComplete();
\r
668 public void requestCompleted(GraphRequestStatus status) {
\r
669 animateRunnable = new AnimateRunnable();
\r
670 VisualizationScheduler.getInstance().addVisualization(animateRunnable);
\r
674 animateRunnable = new AnimateRunnable();
\r
675 VisualizationScheduler.getInstance().addVisualization(animateRunnable);
\r
679 if (animateRunnable == null)
\r
681 VisualizationScheduler.getInstance().removeVisualization(animateRunnable);
\r
682 animateRunnable = null;
\r
683 if (usePrecalculation.getSelection()) {
\r
684 // updateTime updates values to graph if precalculation is not used.
\r
685 // we must store current values from animation to synchronize view and graph
\r
686 // information so that use can modify animation properly.
\r
687 usePrecalculation.setSelection(false);
\r
689 usePrecalculation.setSelection(true);
\r
690 for (IGraphicsNode n : parent.getScenegraphAdapter().getNodes()) {
\r
691 if (n instanceof Animatable) {
\r
692 ((Animatable)n).setAnimation(null,null);
\r
699 private void updateUI() {
\r
700 if (animationResource != null) {
\r
701 animateButton.setEnabled(true);
\r
702 timeSlider.setEnabled(true);
\r
703 if (animateButton.getSelection()) {
\r
704 addAnimationButton.setEnabled(false);
\r
705 insertKeyFrameButton.setEnabled(false);
\r
706 removeAnimationButton.setEnabled(false);
\r
707 clearKeyFrameButton.setEnabled(false);
\r
708 animationCombo.setEnabled(false);
\r
709 usePrecalculation.setEnabled(false);
\r
710 clearAnimationButton.setEnabled(false);
\r
712 addAnimationButton.setEnabled(true);
\r
713 insertKeyFrameButton.setEnabled(!parent.getSelectionAdapter().getCurrentSelection().isEmpty());
\r
714 removeAnimationButton.setEnabled(true);
\r
715 clearKeyFrameButton.setEnabled(false); //FIXME : detect keyframes
\r
716 animationCombo.setEnabled(true);
\r
717 usePrecalculation.setEnabled(true);
\r
718 clearAnimationButton.setEnabled(true);
\r
721 timeSlider.setEnabled(false);
\r
722 addAnimationButton.setEnabled(true);
\r
723 insertKeyFrameButton.setEnabled(false);
\r
724 removeAnimationButton.setEnabled(false);
\r
725 clearKeyFrameButton.setEnabled(false);
\r
726 animateButton.setEnabled(false);
\r
727 animateButton.setSelection(false);
\r
728 animationCombo.setEnabled(true);
\r
729 usePrecalculation.setEnabled(false);
\r
730 clearAnimationButton.setEnabled(false);
\r
734 private void updateKey(double k) {
\r
738 else if (key < 0.0)
\r
740 timeSlider.setSelection((int)(key*100.0));
\r
743 private class AnimateRunnable implements Runnable {
\r
744 public void run() {
\r
746 updateKey(key + 0.01);
\r
748 } catch (Exception e) {
\r
749 VisualizationScheduler.getInstance().removeVisualization(animateRunnable);
\r
755 public void fillLocalToolBar(IToolBarManager manager) {
\r
760 public void fillLocalPullDown(IMenuManager manager) {
\r
765 public void dispose() {
\r
770 public void run() {
\r