1 /*******************************************************************************
\r
2 * Copyright (c) 2007- VTT Technical Research Centre of Finland.
\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
9 * VTT Technical Research Centre of Finland - initial API and implementation
\r
10 *******************************************************************************/
\r
11 package org.simantics.proconf.g3d.shapeeditor.tools;
\r
13 import java.util.ArrayList;
\r
14 import java.util.Collection;
\r
15 import java.util.List;
\r
17 import javax.vecmath.AxisAngle4d;
\r
18 import javax.vecmath.Quat4d;
\r
20 import org.eclipse.jface.action.IMenuManager;
\r
21 import org.eclipse.jface.action.IToolBarManager;
\r
22 import org.eclipse.jface.dialogs.Dialog;
\r
23 import org.eclipse.jface.dialogs.InputDialog;
\r
24 import org.eclipse.jface.dialogs.MessageDialog;
\r
25 import org.eclipse.jface.viewers.ISelectionChangedListener;
\r
26 import org.eclipse.jface.viewers.SelectionChangedEvent;
\r
27 import org.eclipse.swt.SWT;
\r
28 import org.eclipse.swt.custom.CCombo;
\r
29 import org.eclipse.swt.events.FocusAdapter;
\r
30 import org.eclipse.swt.events.FocusEvent;
\r
31 import org.eclipse.swt.events.KeyAdapter;
\r
32 import org.eclipse.swt.events.KeyEvent;
\r
33 import org.eclipse.swt.events.SelectionAdapter;
\r
34 import org.eclipse.swt.events.SelectionEvent;
\r
35 import org.eclipse.swt.layout.FillLayout;
\r
36 import org.eclipse.swt.layout.FormAttachment;
\r
37 import org.eclipse.swt.layout.FormData;
\r
38 import org.eclipse.swt.layout.FormLayout;
\r
39 import org.eclipse.swt.layout.GridData;
\r
40 import org.eclipse.swt.layout.GridLayout;
\r
41 import org.eclipse.swt.widgets.Button;
\r
42 import org.eclipse.swt.widgets.Composite;
\r
43 import org.eclipse.swt.widgets.Slider;
\r
44 import org.eclipse.swt.widgets.Text;
\r
45 import org.simantics.db.ContextGraph;
\r
46 import org.simantics.db.Graph;
\r
47 import org.simantics.db.GraphRequestAdapter;
\r
48 import org.simantics.db.GraphRequestStatus;
\r
49 import org.simantics.db.GraphRequestWithResult;
\r
50 import org.simantics.db.Resource;
\r
51 import org.simantics.animation.stubs.Animation;
\r
52 import org.simantics.animation.stubs.Interpolator;
\r
53 import org.simantics.animation.stubs.ScalarInterpolator;
\r
54 import org.simantics.animation.stubs.SlerpInterpolator;
\r
55 import org.simantics.layer0.utils.EntityFactory;
\r
56 import org.simantics.layer0.utils.IEntity;
\r
57 import org.simantics.layer0.utils.Property;
\r
58 import org.simantics.animation.curve.SlerpCurve;
\r
59 import org.simantics.animation.curve.TCBCurve;
\r
60 import org.simantics.proconf.g3d.actions.ContextAction;
\r
61 import org.simantics.proconf.g3d.actions.RotateAction;
\r
62 import org.simantics.proconf.g3d.actions.TranslateAction;
\r
63 import org.simantics.proconf.g3d.animation.Animatable;
\r
64 import org.simantics.proconf.g3d.base.EditorContribution;
\r
65 import org.simantics.proconf.g3d.base.G3DTools;
\r
66 import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;
\r
67 import org.simantics.proconf.g3d.base.VisualizationScheduler;
\r
68 import org.simantics.proconf.g3d.common.StructuredResourceSelection;
\r
69 import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;
\r
70 import org.simantics.proconf.g3d.scenegraph.ISelectableNode;
\r
71 import org.simantics.proconf.g3d.shapeeditor.ShapeEditorResources;
\r
72 import org.simantics.proconf.g3d.shapeeditor.dialogs.PropertySelectionDialog;
\r
73 import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase;
\r
74 import org.simantics.proconf.g3d.stubs.G3DModel;
\r
75 import org.simantics.proconf.g3d.stubs.Orientation;
\r
76 import org.simantics.utils.ui.ErrorLogger;
\r
78 public class AnimationContribution implements EditorContribution {
\r
79 List<ContextAction> actions = new ArrayList<ContextAction>();
\r
81 private ShapeEditorBase parent;
\r
83 private final String NO_ANIMATION = "None";
\r
85 private Slider timeSlider;
\r
86 private double key = 0;
\r
87 private Composite buttonComposite;
\r
88 private Button insertKeyFrameButton;
\r
89 private Button clearKeyFrameButton;
\r
90 private CCombo animationCombo;
\r
91 private Button addAnimationButton;
\r
92 private Button removeAnimationButton;
\r
93 private Button clearAnimationButton;
\r
94 private Button animateButton;
\r
95 private Button usePrecalculation;
\r
96 private Text timeText;
\r
97 private Composite infoComposite;
\r
98 private Text infoText;
\r
100 private Resource animationResource;
\r
102 private ContextAction translateAction;
\r
103 private ContextAction rotateAction;
\r
105 public AnimationContribution(ThreeDimensionalEditorBase parent) {
\r
106 this.parent = (ShapeEditorBase)parent;
\r
110 public String getName() {
\r
115 public void createControl(Composite parent) {
\r
116 FormLayout flayout = new FormLayout();
\r
117 parent.setLayout(flayout);
\r
118 infoComposite = new Composite(parent, SWT.BORDER);
\r
119 FormData data = new FormData();
\r
120 data.top = new FormAttachment(0, 0);
\r
121 data.left = new FormAttachment(0, 0);
\r
122 data.right = new FormAttachment(100, 0);
\r
123 data.bottom = new FormAttachment(infoComposite, 0, SWT.TOP);
\r
124 this.parent.getRenderingComposite().setLayoutData(data);
\r
126 infoComposite.setLayout(new FillLayout(SWT.VERTICAL));
\r
127 infoText = new Text(infoComposite, SWT.NONE);
\r
128 GridLayout layout = new GridLayout(2, false);
\r
129 layout.horizontalSpacing = 2;
\r
130 layout.verticalSpacing = 2;
\r
131 layout.marginWidth = 1;
\r
132 layout.marginHeight = 1;
\r
133 infoComposite.setLayout(layout);
\r
134 GridData gdata = new GridData(SWT.BEGINNING, SWT.CENTER, true, false, 2, 1);
\r
135 // FIXME : allows text widget to take all available space (horizontal / width)
\r
136 gdata.widthHint = 2000;
\r
137 infoText.setLayoutData(gdata);
\r
138 timeSlider = new Slider(infoComposite, SWT.NONE);
\r
139 timeSlider.setValues(0, 0, 100, 1, 1, 1);
\r
140 timeSlider.addSelectionListener(new SelectionAdapter() {
\r
142 public void widgetSelected(SelectionEvent e) {
\r
143 key = ((double) timeSlider.getSelection()) / 100.0;
\r
147 timeSlider.setLayoutData(new GridData(SWT.FILL, 1, true, false));
\r
148 timeText = new Text(infoComposite, SWT.SINGLE);
\r
149 timeText.addFocusListener(new FocusAdapter() {
\r
151 public void focusLost(FocusEvent e) {
\r
155 timeText.addKeyListener(new KeyAdapter() {
\r
157 public void keyReleased(KeyEvent e) {
\r
158 if (e.keyCode == SWT.CR)
\r
163 buttonComposite = new Composite(infoComposite, SWT.NONE);
\r
164 buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL));
\r
165 buttonComposite.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, false, 2, 1));
\r
166 insertKeyFrameButton = new Button(buttonComposite, SWT.PUSH);
\r
167 insertKeyFrameButton.setText("Insert Keyframe");
\r
168 insertKeyFrameButton.addSelectionListener(new SelectionAdapter() {
\r
169 public void widgetSelected(SelectionEvent e) {
\r
174 clearKeyFrameButton = new Button(buttonComposite, SWT.PUSH);
\r
175 clearKeyFrameButton.setText("Clear Keyframe");
\r
177 animationCombo = new CCombo(buttonComposite, SWT.NONE);
\r
178 animationCombo.add(NO_ANIMATION);
\r
179 animationCombo.select(0);
\r
180 animationCombo.setEditable(false);
\r
181 animationCombo.addSelectionListener(new SelectionAdapter() {
\r
182 public void widgetSelected(SelectionEvent e) {
\r
187 addAnimationButton = new Button(buttonComposite, SWT.PUSH);
\r
188 addAnimationButton.setText("New Animation");
\r
189 addAnimationButton.addSelectionListener(new SelectionAdapter() {
\r
190 public void widgetSelected(SelectionEvent e) {
\r
195 clearAnimationButton = new Button(buttonComposite, SWT.PUSH);
\r
196 clearAnimationButton.setText("Clear Animation");
\r
197 clearAnimationButton.addSelectionListener(new SelectionAdapter() {
\r
198 public void widgetSelected(SelectionEvent e) {
\r
203 removeAnimationButton = new Button(buttonComposite, SWT.PUSH);
\r
204 removeAnimationButton.setText("Remove Animation");
\r
205 removeAnimationButton.addSelectionListener(new SelectionAdapter() {
\r
206 public void widgetSelected(SelectionEvent e) {
\r
211 animateButton = new Button(buttonComposite, SWT.TOGGLE);
\r
212 animateButton.setText("Animate");
\r
213 animateButton.addSelectionListener(new SelectionAdapter() {
\r
214 public void widgetSelected(SelectionEvent e) {
\r
219 usePrecalculation = new Button(buttonComposite, SWT.CHECK);
\r
220 usePrecalculation.setText("Precalc");
\r
222 data = new FormData();
\r
223 data.left = new FormAttachment(0, 0);
\r
224 data.right = new FormAttachment(100, 0);
\r
225 data.bottom = new FormAttachment(100, 0);
\r
226 // FIXME : take account font size
\r
227 data.height = 20 * 3;
\r
228 infoComposite.setLayoutData(data);
\r
230 this.parent.getSelectionAdapter().addSelectionChangedListener(new ISelectionChangedListener() {
\r
231 public void selectionChanged(SelectionChangedEvent event) {
\r
237 this.parent.getSession().asyncRead(new GraphRequestAdapter() {
\r
239 public GraphRequestStatus perform(Graph g) throws Exception {
\r
240 G3DModel m = new G3DModel(g,AnimationContribution.this.parent.getModelResource());
\r
241 Collection<Animation> animations = m.getAnimation();
\r
243 final List<String> animationNames = new ArrayList<String>();
\r
244 for (Animation a : animations) {
\r
245 animationNames.add(a.getName());
\r
247 AnimationContribution.this.parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {
\r
248 public void run() {
\r
249 for (String s : animationNames)
\r
250 animationCombo.add(s);
\r
253 return GraphRequestStatus.transactionComplete();
\r
260 public void disposeControl() {
\r
261 if (animateRunnable != null)
\r
262 VisualizationScheduler.getInstance().removeVisualization(animateRunnable);
\r
263 animateRunnable = null;
\r
265 infoComposite.dispose();
\r
270 public void fillContextMenu(Graph graph, IMenuManager manager, StructuredResourceSelection selection) {
\r
277 public Collection<ContextAction> getActions() {
\r
282 public void initialize(Graph graph) {
\r
283 actions.add(translateAction = new TranslateAction(parent) {
\r
285 public void setInfoText(String text) {
\r
286 infoText.setText(text);
\r
289 actions.add(rotateAction = new RotateAction(parent){
\r
291 public void setInfoText(String text) {
\r
292 infoText.setText(text);
\r
297 private double getCurrentKey() {
\r
301 private void updateTime() {
\r
302 final double t = getCurrentKey();
\r
303 timeText.setText(Double.toString(t));
\r
304 if (animationResource == null)
\r
306 if (usePrecalculation.getSelection()) {
\r
307 for (IGraphicsNode n : parent.getScenegraphAdapter().getNodes()) {
\r
308 if (n instanceof Animatable) {
\r
309 // TODO : frame-rate dependent animations
\r
310 ((Animatable)n).animate(t,0.0);
\r
312 parent.setViewChanged(true);
\r
315 parent.getSession().asyncWrite(new GraphRequestAdapter() {
\r
317 public GraphRequestStatus perform(Graph g) throws Exception {
\r
318 Collection<IEntity> interpolators = getAnimation(g).getRelatedObjects(ShapeEditorResources.animationResource.HasInterpolator);
\r
319 for (IEntity i : interpolators) {
\r
320 if (i.isInstanceOf(ShapeEditorResources.animationResource.ScalarInterpolator)) {
\r
321 // TODO : creating curve each time when time is set is
\r
322 // slow. Curve should be cached
\r
323 TCBCurve c = (TCBCurve) ShapeEditorResources.curveBuilder.loadInterpolator(i);
\r
324 double out = c.evaluate(t);
\r
325 g.setScalarDouble(i.getSingleRelatedObject(ShapeEditorResources.animationResource.HasTarget).getResource(), out);
\r
326 } else if (i.isInstanceOf(ShapeEditorResources.animationResource.SlerpInterpolator)) {
\r
327 // TODO : creating curve each time when time is set is slow.
\r
328 // Curve should be cached
\r
329 SlerpCurve c = (SlerpCurve) ShapeEditorResources.curveBuilder.loadInterpolator(i);
\r
330 Quat4d out = c.evaluate(t);
\r
331 Orientation r = new Orientation(i.getSingleRelatedObject(ShapeEditorResources.animationResource.HasTarget));
\r
332 AxisAngle4d aa = new AxisAngle4d();
\r
334 G3DTools.setOrientation(r, aa);
\r
337 return GraphRequestStatus.transactionComplete();
\r
341 public void requestCompleted(GraphRequestStatus status) {
\r
342 parent.getScenegraphAdapter().setChanged(true);
\r
348 private IEntity findPropertyInterpolator(Graph g, Resource property) {
\r
349 Collection<IEntity> interpolators = getAnimation(g).getRelatedObjects(ShapeEditorResources.animationResource.HasInterpolator);
\r
350 for (IEntity i : interpolators) {
\r
351 IEntity e = i.getAtMostOneRelatedObject(ShapeEditorResources.animationResource.HasTarget);
\r
354 if (e.getResource().equals(property)) {
\r
361 private void insertKeyFrame() {
\r
362 ArrayList<Resource> instances = new ArrayList<Resource>();
\r
363 for (Resource rs : parent.getSelectionAdapter().getCurrentSelection().getSelectionList()) {
\r
366 PropertySelectionDialog dialog = new PropertySelectionDialog(parent.getRenderingComposite().getShell(),"Select property","Select animated property",parent.getSession(),instances);
\r
367 if (dialog.open() == Dialog.CANCEL) {
\r
370 final List<Resource> properties = dialog.getSelectedPropertyInstances();
\r
371 parent.getSession().asyncWrite(new GraphRequestAdapter() {
\r
373 public GraphRequestStatus perform(Graph g) throws Exception {
\r
374 for (Resource r : properties) {
\r
375 IEntity t = EntityFactory.create(g,r);
\r
376 IEntity current = findPropertyInterpolator(g, r);
\r
377 if (t.isInstanceOf(ShapeEditorResources.g3dResource.Position)) {
\r
379 for (int i = 0; i < 3; i++) {
\r
383 d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasX);
\r
386 d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasY);
\r
389 d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasZ);
\r
392 current = findPropertyInterpolator(g, d.getResource());
\r
393 addScalarKey(current,d);
\r
396 } else if (t.isInstanceOf(ShapeEditorResources.g3dResource.Orientation)) {
\r
397 Orientation rot = new Orientation(t);
\r
398 addSlerpKey(current, rot);
\r
399 } else if (t.isInstanceOf(ShapeEditorResources.g3dResource.Color)) {
\r
400 for (int i = 0; i < 3; i++) {
\r
404 d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasRed);
\r
411 current = findPropertyInterpolator(g, d.getResource());
\r
412 addScalarKey(current,d);
\r
414 } else if (t.isInstanceOf(g.getBuiltins().Double)) {
\r
415 addScalarKey(current,t);
\r
417 // TODO: basic cases are handled, only way to support
\r
418 // is to find all doubles from property structure and
\r
419 // interpolators attached to them, if there's any
\r
420 ErrorLogger.getDefault().logWarning("Default keyframe adding has not been implemented", null);
\r
423 return GraphRequestStatus.transactionComplete();
\r
428 private void addScalarKey(IEntity current, IEntity d) {
\r
430 Graph graph = d.getGraph();
\r
431 if (current == null) {
\r
432 current = ScalarInterpolator.createDefault(graph).toInterpolator(); // FIXME : stubcast
\r
433 getAnimation(graph).addStatement(ShapeEditorResources.animationResource.HasInterpolator, current);
\r
434 current.addStatement(ShapeEditorResources.animationResource.HasTarget, d);
\r
436 ShapeEditorResources.curveBuilder.addKey(current,getCurrentKey(),new double[]{d.getGraph().getScalarDouble(d.getResource()),0.0,0.0,0.0});
\r
439 private void addSlerpKey(IEntity current, Orientation r) {
\r
440 Graph graph = r.getGraph();
\r
441 if (current == null) {
\r
442 current = SlerpInterpolator.createDefault(graph).toInterpolator(); // FIXME : stubcast
\r
443 getAnimation(graph).addStatement(ShapeEditorResources.animationResource.HasInterpolator, current);
\r
444 current.addStatement(ShapeEditorResources.animationResource.HasTarget, r);
\r
447 AxisAngle4d aa = G3DTools.getOrientation(r);
\r
448 Quat4d q = new Quat4d();
\r
450 ShapeEditorResources.curveBuilder.addKey(current,getCurrentKey(),new double[]{q.w,q.x,q.y,q.z});
\r
453 private void selectAnimation() {
\r
454 if (animationCombo.getSelectionIndex() == 0) {
\r
455 animationResource = null;
\r
458 final String name = animationCombo.getItem(animationCombo.getSelectionIndex());
\r
459 parent.getSession().asyncRead(new GraphRequestAdapter() {
\r
461 public GraphRequestStatus perform(Graph g) throws Exception {
\r
463 Resource modelResource = parent.getModelResource();
\r
464 G3DModel m = new G3DModel(g, modelResource);
\r
465 Collection<Animation> animations = m.getAnimation();
\r
466 boolean found = false;
\r
467 for (Animation a : animations) {
\r
468 if (a.getName().startsWith(name) && a.getName().length() == name.length()) {
\r
469 animationResource = a.getResource();
\r
475 ErrorLogger.defaultLogError("Could find animation " + name + " for model " + m.getResource(), null);
\r
476 animationResource = null;
\r
478 return GraphRequestStatus.transactionComplete();
\r
481 public void requestCompleted(GraphRequestStatus status) {
\r
482 parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {
\r
484 public void run() {
\r
493 private Animation getAnimation(Graph graph) {
\r
494 return new Animation(graph, animationResource);
\r
497 private void addAnimation() {
\r
498 InputDialog d = new InputDialog(parent.getRenderingComposite().getShell(),"Animation name","Animation name","",null);
\r
499 if (d.open() == InputDialog.CANCEL) {
\r
502 final String name = d.getValue();
\r
503 if (name == null || name.length() == 0) {
\r
506 parent.getSession().asyncWrite(new GraphRequestAdapter() {
\r
508 public GraphRequestStatus perform(Graph g) throws Exception {
\r
509 G3DModel m = parent.getModel(g);
\r
510 Collection<IEntity> animations = m.getRelatedObjects(ShapeEditorResources.animationResource.HasAnimation);
\r
511 for (IEntity a : animations) {
\r
512 if (a.getName().startsWith(name) && a.getName().length() == name.length()) {
\r
513 ErrorLogger.getDefault().logWarning("Cannot add animation with the same name " + name, null);
\r
514 return GraphRequestStatus.transactionCancel();
\r
518 Animation newAnimation = Animation.createDefault(g);
\r
519 newAnimation.setName(name);
\r
520 m.addStatement(ShapeEditorResources.animationResource.HasAnimation, newAnimation);
\r
522 return GraphRequestStatus.transactionComplete();
\r
526 public void requestCompleted(GraphRequestStatus status) {
\r
527 parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {
\r
528 public void run() {
\r
529 animationCombo.add(name);
\r
530 animationCombo.select(animationCombo.indexOf(name));
\r
538 private void removeAnimation() {
\r
539 assert(animationResource != null);
\r
540 GraphRequestWithResult<String> r = new GraphRequestWithResult<String>() {
\r
541 public String performWithResult(Graph g) throws Exception {
\r
542 return getAnimation(g).getName();
\r
545 parent.getSession().syncRead(r);
\r
546 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
547 if (dialog.open() == 1)
\r
549 parent.getSession().asyncWrite(new GraphRequestAdapter() {
\r
552 public GraphRequestStatus perform(Graph g) throws Exception {
\r
554 Animation currentAnimation = getAnimation(g);
\r
555 name = currentAnimation.getName();
\r
556 parent.getModel(g).removeStatement(ShapeEditorResources.animationResource.HasAnimation, currentAnimation);
\r
558 return GraphRequestStatus.transactionComplete();
\r
562 public void requestCompleted(GraphRequestStatus status) {
\r
563 parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {
\r
564 public void run() {
\r
565 animationCombo.remove(animationCombo.indexOf(name));
\r
572 private void clearAnimation() {
\r
573 assert(animationResource != null);
\r
575 parent.getSession().asyncWrite(new GraphRequestAdapter() {
\r
579 public GraphRequestStatus perform(Graph g) throws Exception {
\r
580 int size = getAnimation(g).getInterpolator().size();
\r
582 return GraphRequestStatus.transactionCancel();
\r
583 final String name = getAnimation(g).getName();
\r
584 parent.getRenderingComposite().getDisplay().syncExec(new Runnable() {
\r
585 public void run() {
\r
586 MessageDialog dialog = new MessageDialog(parent.getRenderingComposite().getShell(),"Confirm",null,"Do you want to clear animation " + name ,MessageDialog.QUESTION,new String[]{"Yes","No"},1);
\r
587 proceed = (dialog.open() != MessageDialog.CANCEL);
\r
591 //getAnimation(g).getInterpolator().clear();
\r
592 getAnimation(g).removeRelatedStatements(ShapeEditorResources.animationResource.HasInterpolator);
\r
593 return GraphRequestStatus.transactionComplete();
\r
595 return GraphRequestStatus.transactionCancel();
\r
601 public Graph createAnimationParameterization(Graph g) {
\r
602 if (g.getObjects(parent.getModelResource(), ShapeEditorResources.g3dResource.HasSizingParameter).size() > 0) {
\r
603 ContextGraph graph;
\r
604 if (!(g instanceof ContextGraph)) {
\r
605 graph = new ContextGraph(g);
\r
606 graph.setContext(parent.getModelResource());
\r
608 graph = (ContextGraph)g;
\r
610 Animation animation = getAnimation(graph);
\r
611 Collection<Interpolator> interpolators = animation.getInterpolator();
\r
612 for (org.simantics.animation.stubs.Interpolator interpolator : interpolators) {
\r
613 IEntity target = interpolator.getTarget();
\r
614 // check all model properties
\r
615 G3DModel model = parent.getModel(graph);
\r
616 Collection<Property> modelProperties = model.getRelatedProperties(ShapeEditorResources.g3dResource.HasSizingParameter);
\r
617 for (Property p : modelProperties) {
\r
618 IEntity t = EntityFactory.create(graph,p.getResource());
\r
619 // get parameterization equations
\r
620 Collection<IEntity> equations = t.getRelatedObjects(ShapeEditorResources.equationResource.HasTarget);
\r
621 // get parameterized values
\r
622 Collection<IEntity> parameterTargets = new ArrayList<IEntity>();
\r
623 for (IEntity eq : equations) {
\r
624 Collection<IEntity> tgts = eq.getRelatedObjects(ShapeEditorResources.equationResource.HasTarget);
\r
625 assert(tgts.size() == 1);
\r
626 parameterTargets.add(tgts.iterator().next());
\r
628 // do matching between interpolator targets and parameterized values
\r
629 // TODO : old system did not have inverse relations but current system does.
\r
630 // it is possible to take interpolation target and find if it is connected to an equation
\r
631 // this would make code much faster (no more stupid loops over everything)
\r
632 for (IEntity d : parameterTargets) {
\r
633 if (d.getResource().equals(target.getResource())) {
\r
634 // get default value for sizing property
\r
635 Collection<IEntity> prop = t.getRelatedObjects(ShapeEditorResources.g3dResource.HasDefaultDoubleValue);
\r
636 if (prop.size() == 1) {
\r
637 ShapeEditorResources.curveBuilder.parameterize(interpolator, prop.iterator().next().toProperty().getDoubleArray(), p.getDoubleArray());
\r
639 ErrorLogger.defaultLogError("Cannot parameterize interpolator " + interpolator.getResource() + " of animation " + animation.getResource() + " since parameter " + p.getResource() + " has no default value", null);
\r
652 private AnimateRunnable animateRunnable = null;
\r
654 private void animate() {
\r
656 if (animateButton.getSelection()) {
\r
657 if (animateRunnable != null)
\r
659 if (usePrecalculation.getSelection()) {
\r
660 parent.getSession().asyncRead(new GraphRequestAdapter() {
\r
662 public GraphRequestStatus perform(Graph g) throws Exception {
\r
663 Graph graph = parent.createParameterization(g);
\r
664 createAnimationParameterization(graph);
\r
665 for (IGraphicsNode n : parent.getScenegraphAdapter().getNodes()) {
\r
666 if (n instanceof ISelectableNode) {
\r
667 if (!((ISelectableNode)n).isVisible())
\r
670 if (n instanceof Animatable) {
\r
671 ((Animatable)n).setAnimation(graph,animationResource);
\r
674 return GraphRequestStatus.transactionComplete();
\r
678 public void requestCompleted(GraphRequestStatus status) {
\r
679 animateRunnable = new AnimateRunnable();
\r
680 VisualizationScheduler.getInstance().addVisualization(animateRunnable);
\r
684 animateRunnable = new AnimateRunnable();
\r
685 VisualizationScheduler.getInstance().addVisualization(animateRunnable);
\r
689 if (animateRunnable == null)
\r
691 VisualizationScheduler.getInstance().removeVisualization(animateRunnable);
\r
692 animateRunnable = null;
\r
693 if (usePrecalculation.getSelection()) {
\r
694 // updateTime updates values to graph if precalculation is not used.
\r
695 // we must store current values from animation to synchronize view and graph
\r
696 // information so that use can modify animation properly.
\r
697 usePrecalculation.setSelection(false);
\r
699 usePrecalculation.setSelection(true);
\r
700 for (IGraphicsNode n : parent.getScenegraphAdapter().getNodes()) {
\r
701 if (n instanceof Animatable) {
\r
702 ((Animatable)n).setAnimation(null,null);
\r
709 private void updateUI() {
\r
710 if (animationResource != null) {
\r
711 animateButton.setEnabled(true);
\r
712 timeSlider.setEnabled(true);
\r
713 if (animateButton.getSelection()) {
\r
714 addAnimationButton.setEnabled(false);
\r
715 insertKeyFrameButton.setEnabled(false);
\r
716 removeAnimationButton.setEnabled(false);
\r
717 clearKeyFrameButton.setEnabled(false);
\r
718 animationCombo.setEnabled(false);
\r
719 usePrecalculation.setEnabled(false);
\r
720 clearAnimationButton.setEnabled(false);
\r
722 addAnimationButton.setEnabled(true);
\r
723 insertKeyFrameButton.setEnabled(!parent.getSelectionAdapter().getCurrentSelection().isEmpty());
\r
724 removeAnimationButton.setEnabled(true);
\r
725 clearKeyFrameButton.setEnabled(false); //FIXME : detect keyframes
\r
726 animationCombo.setEnabled(true);
\r
727 usePrecalculation.setEnabled(true);
\r
728 clearAnimationButton.setEnabled(true);
\r
731 timeSlider.setEnabled(false);
\r
732 addAnimationButton.setEnabled(true);
\r
733 insertKeyFrameButton.setEnabled(false);
\r
734 removeAnimationButton.setEnabled(false);
\r
735 clearKeyFrameButton.setEnabled(false);
\r
736 animateButton.setEnabled(false);
\r
737 animateButton.setSelection(false);
\r
738 animationCombo.setEnabled(true);
\r
739 usePrecalculation.setEnabled(false);
\r
740 clearAnimationButton.setEnabled(false);
\r
744 private void updateKey(double k) {
\r
748 else if (key < 0.0)
\r
750 timeSlider.setSelection((int)(key*100.0));
\r
753 private class AnimateRunnable implements Runnable {
\r
754 public void run() {
\r
756 updateKey(key + 0.01);
\r
758 } catch (Exception e) {
\r
759 VisualizationScheduler.getInstance().removeVisualization(animateRunnable);
\r
765 public void fillLocalToolBar(IToolBarManager manager) {
\r
770 public void fillLocalPullDown(IMenuManager manager) {
\r
775 public void dispose() {
\r
780 public void run() {
\r