+++ /dev/null
-/*******************************************************************************\r
- * Copyright (c) 2007- VTT Technical Research Centre of Finland.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.proconf.g3d.shapeeditor.tools;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.List;\r
-\r
-import javax.vecmath.AxisAngle4d;\r
-import javax.vecmath.Quat4d;\r
-\r
-import org.eclipse.jface.action.IMenuManager;\r
-import org.eclipse.jface.action.IToolBarManager;\r
-import org.eclipse.jface.dialogs.Dialog;\r
-import org.eclipse.jface.dialogs.InputDialog;\r
-import org.eclipse.jface.dialogs.MessageDialog;\r
-import org.eclipse.jface.viewers.ISelectionChangedListener;\r
-import org.eclipse.jface.viewers.SelectionChangedEvent;\r
-import org.eclipse.swt.SWT;\r
-import org.eclipse.swt.custom.CCombo;\r
-import org.eclipse.swt.events.FocusAdapter;\r
-import org.eclipse.swt.events.FocusEvent;\r
-import org.eclipse.swt.events.KeyAdapter;\r
-import org.eclipse.swt.events.KeyEvent;\r
-import org.eclipse.swt.events.SelectionAdapter;\r
-import org.eclipse.swt.events.SelectionEvent;\r
-import org.eclipse.swt.layout.FillLayout;\r
-import org.eclipse.swt.layout.FormAttachment;\r
-import org.eclipse.swt.layout.FormData;\r
-import org.eclipse.swt.layout.FormLayout;\r
-import org.eclipse.swt.layout.GridData;\r
-import org.eclipse.swt.layout.GridLayout;\r
-import org.eclipse.swt.widgets.Button;\r
-import org.eclipse.swt.widgets.Composite;\r
-import org.eclipse.swt.widgets.Slider;\r
-import org.eclipse.swt.widgets.Text;\r
-import org.simantics.db.ContextGraph;\r
-import org.simantics.db.Graph;\r
-import org.simantics.db.GraphRequestAdapter;\r
-import org.simantics.db.GraphRequestStatus;\r
-import org.simantics.db.GraphRequestWithResult;\r
-import org.simantics.db.Resource;\r
-import org.simantics.animation.stubs.Animation;\r
-import org.simantics.animation.stubs.Interpolator;\r
-import org.simantics.animation.stubs.ScalarInterpolator;\r
-import org.simantics.animation.stubs.SlerpInterpolator;\r
-import org.simantics.layer0.utils.EntityFactory;\r
-import org.simantics.layer0.utils.IEntity;\r
-import org.simantics.layer0.utils.Property;\r
-import org.simantics.animation.curve.SlerpCurve;\r
-import org.simantics.animation.curve.TCBCurve;\r
-import org.simantics.proconf.g3d.actions.ContextAction;\r
-import org.simantics.proconf.g3d.actions.RotateAction;\r
-import org.simantics.proconf.g3d.actions.TranslateAction;\r
-import org.simantics.proconf.g3d.animation.Animatable;\r
-import org.simantics.proconf.g3d.base.EditorContribution;\r
-import org.simantics.proconf.g3d.base.G3DTools;\r
-import org.simantics.proconf.g3d.base.ThreeDimensionalEditorBase;\r
-import org.simantics.proconf.g3d.base.VisualizationScheduler;\r
-import org.simantics.proconf.g3d.common.StructuredResourceSelection;\r
-import org.simantics.proconf.g3d.scenegraph.IGraphicsNode;\r
-import org.simantics.proconf.g3d.scenegraph.ISelectableNode;\r
-import org.simantics.proconf.g3d.shapeeditor.ShapeEditorResources;\r
-import org.simantics.proconf.g3d.shapeeditor.dialogs.PropertySelectionDialog;\r
-import org.simantics.proconf.g3d.shapeeditor.views.ShapeEditorBase;\r
-import org.simantics.proconf.g3d.stubs.G3DModel;\r
-import org.simantics.proconf.g3d.stubs.Orientation;\r
-import org.simantics.utils.ui.ErrorLogger;\r
-\r
-public class AnimationContribution implements EditorContribution {\r
- List<ContextAction> actions = new ArrayList<ContextAction>();\r
- \r
- private ShapeEditorBase parent;\r
- \r
- private final String NO_ANIMATION = "None";\r
-\r
- private Slider timeSlider;\r
- private double key = 0;\r
- private Composite buttonComposite;\r
- private Button insertKeyFrameButton;\r
- private Button clearKeyFrameButton;\r
- private CCombo animationCombo;\r
- private Button addAnimationButton;\r
- private Button removeAnimationButton;\r
- private Button clearAnimationButton;\r
- private Button animateButton;\r
- private Button usePrecalculation;\r
- private Text timeText;\r
- private Composite infoComposite;\r
- private Text infoText;\r
-\r
- private Resource animationResource;\r
- \r
- private ContextAction translateAction;\r
- private ContextAction rotateAction;\r
- \r
- public AnimationContribution(ThreeDimensionalEditorBase parent) {\r
- this.parent = (ShapeEditorBase)parent;\r
- }\r
- \r
- @Override\r
- public String getName() {\r
- return "Animator";\r
- }\r
- \r
- @Override\r
- public void createControl(Composite parent) {\r
- FormLayout flayout = new FormLayout();\r
- parent.setLayout(flayout);\r
- infoComposite = new Composite(parent, SWT.BORDER);\r
- FormData data = new FormData();\r
- data.top = new FormAttachment(0, 0);\r
- data.left = new FormAttachment(0, 0);\r
- data.right = new FormAttachment(100, 0);\r
- data.bottom = new FormAttachment(infoComposite, 0, SWT.TOP);\r
- this.parent.getRenderingComposite().setLayoutData(data);\r
-\r
- infoComposite.setLayout(new FillLayout(SWT.VERTICAL));\r
- infoText = new Text(infoComposite, SWT.NONE);\r
- GridLayout layout = new GridLayout(2, false);\r
- layout.horizontalSpacing = 2;\r
- layout.verticalSpacing = 2;\r
- layout.marginWidth = 1;\r
- layout.marginHeight = 1;\r
- infoComposite.setLayout(layout);\r
- GridData gdata = new GridData(SWT.BEGINNING, SWT.CENTER, true, false, 2, 1);\r
- // FIXME : allows text widget to take all available space (horizontal / width)\r
- gdata.widthHint = 2000;\r
- infoText.setLayoutData(gdata);\r
- timeSlider = new Slider(infoComposite, SWT.NONE);\r
- timeSlider.setValues(0, 0, 100, 1, 1, 1);\r
- timeSlider.addSelectionListener(new SelectionAdapter() {\r
- @Override\r
- public void widgetSelected(SelectionEvent e) {\r
- key = ((double) timeSlider.getSelection()) / 100.0;\r
- updateTime();\r
- }\r
- });\r
- timeSlider.setLayoutData(new GridData(SWT.FILL, 1, true, false));\r
- timeText = new Text(infoComposite, SWT.SINGLE);\r
- timeText.addFocusListener(new FocusAdapter() {\r
- @Override\r
- public void focusLost(FocusEvent e) {\r
- updateTime();\r
- }\r
- });\r
- timeText.addKeyListener(new KeyAdapter() {\r
- @Override\r
- public void keyReleased(KeyEvent e) {\r
- if (e.keyCode == SWT.CR)\r
- updateTime();\r
- }\r
- });\r
-\r
- buttonComposite = new Composite(infoComposite, SWT.NONE);\r
- buttonComposite.setLayout(new FillLayout(SWT.HORIZONTAL));\r
- buttonComposite.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, false, 2, 1));\r
- insertKeyFrameButton = new Button(buttonComposite, SWT.PUSH);\r
- insertKeyFrameButton.setText("Insert Keyframe");\r
- insertKeyFrameButton.addSelectionListener(new SelectionAdapter() {\r
- public void widgetSelected(SelectionEvent e) {\r
- insertKeyFrame();\r
- }\r
- });\r
-\r
- clearKeyFrameButton = new Button(buttonComposite, SWT.PUSH);\r
- clearKeyFrameButton.setText("Clear Keyframe");\r
-\r
- animationCombo = new CCombo(buttonComposite, SWT.NONE);\r
- animationCombo.add(NO_ANIMATION);\r
- animationCombo.select(0);\r
- animationCombo.setEditable(false);\r
- animationCombo.addSelectionListener(new SelectionAdapter() {\r
- public void widgetSelected(SelectionEvent e) {\r
- selectAnimation();\r
- }\r
- });\r
-\r
- addAnimationButton = new Button(buttonComposite, SWT.PUSH);\r
- addAnimationButton.setText("New Animation");\r
- addAnimationButton.addSelectionListener(new SelectionAdapter() {\r
- public void widgetSelected(SelectionEvent e) {\r
- addAnimation();\r
- }\r
- });\r
-\r
- clearAnimationButton = new Button(buttonComposite, SWT.PUSH);\r
- clearAnimationButton.setText("Clear Animation");\r
- clearAnimationButton.addSelectionListener(new SelectionAdapter() {\r
- public void widgetSelected(SelectionEvent e) {\r
- clearAnimation();\r
- }\r
- });\r
-\r
- removeAnimationButton = new Button(buttonComposite, SWT.PUSH);\r
- removeAnimationButton.setText("Remove Animation");\r
- removeAnimationButton.addSelectionListener(new SelectionAdapter() {\r
- public void widgetSelected(SelectionEvent e) {\r
- removeAnimation();\r
- }\r
- });\r
-\r
- animateButton = new Button(buttonComposite, SWT.TOGGLE);\r
- animateButton.setText("Animate");\r
- animateButton.addSelectionListener(new SelectionAdapter() {\r
- public void widgetSelected(SelectionEvent e) {\r
- animate();\r
- }\r
- });\r
-\r
- usePrecalculation = new Button(buttonComposite, SWT.CHECK);\r
- usePrecalculation.setText("Precalc");\r
-\r
- data = new FormData();\r
- data.left = new FormAttachment(0, 0);\r
- data.right = new FormAttachment(100, 0);\r
- data.bottom = new FormAttachment(100, 0);\r
- // FIXME : take account font size\r
- data.height = 20 * 3;\r
- infoComposite.setLayoutData(data);\r
-\r
- this.parent.getSelectionAdapter().addSelectionChangedListener(new ISelectionChangedListener() {\r
- public void selectionChanged(SelectionChangedEvent event) {\r
- updateUI();\r
- }\r
- });\r
- updateUI();\r
- \r
- this.parent.getSession().asyncRead(new GraphRequestAdapter() {\r
- @Override\r
- public GraphRequestStatus perform(Graph g) throws Exception {\r
- G3DModel m = new G3DModel(g,AnimationContribution.this.parent.getModelResource());\r
- Collection<Animation> animations = m.getAnimation();\r
-\r
- final List<String> animationNames = new ArrayList<String>();\r
- for (Animation a : animations) {\r
- animationNames.add(a.getName());\r
- }\r
- AnimationContribution.this.parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {\r
- public void run() {\r
- for (String s : animationNames)\r
- animationCombo.add(s);\r
- }\r
- });\r
- return GraphRequestStatus.transactionComplete();\r
- }\r
- \r
- });\r
- }\r
- \r
- @Override\r
- public void disposeControl() {\r
- if (animateRunnable != null)\r
- VisualizationScheduler.getInstance().removeVisualization(animateRunnable);\r
- animateRunnable = null;\r
- \r
- infoComposite.dispose();\r
-\r
- }\r
- \r
- @Override\r
- public void fillContextMenu(Graph graph, IMenuManager manager, StructuredResourceSelection selection) {\r
-\r
- }\r
- \r
- \r
- \r
- @Override\r
- public Collection<ContextAction> getActions() {\r
- return actions;\r
- }\r
- \r
- @Override\r
- public void initialize(Graph graph) {\r
- actions.add(translateAction = new TranslateAction(parent) {\r
- @Override\r
- public void setInfoText(String text) {\r
- infoText.setText(text);\r
- }\r
- });\r
- actions.add(rotateAction = new RotateAction(parent){\r
- @Override\r
- public void setInfoText(String text) {\r
- infoText.setText(text);\r
- }\r
- });\r
- }\r
- \r
- private double getCurrentKey() {\r
- return key;\r
- }\r
- \r
- private void updateTime() {\r
- final double t = getCurrentKey();\r
- timeText.setText(Double.toString(t));\r
- if (animationResource == null)\r
- return;\r
- if (usePrecalculation.getSelection()) {\r
- for (IGraphicsNode n : parent.getScenegraphAdapter().getNodes()) {\r
- if (n instanceof Animatable) {\r
- // TODO : frame-rate dependent animations\r
- ((Animatable)n).animate(t,0.0);\r
- }\r
- parent.setViewChanged(true);\r
- } \r
- } else {\r
- parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
- @Override\r
- public GraphRequestStatus perform(Graph g) throws Exception {\r
- Collection<IEntity> interpolators = getAnimation(g).getRelatedObjects(ShapeEditorResources.animationResource.HasInterpolator);\r
- for (IEntity i : interpolators) {\r
- if (i.isInstanceOf(ShapeEditorResources.animationResource.ScalarInterpolator)) {\r
- // TODO : creating curve each time when time is set is\r
- // slow. Curve should be cached\r
- TCBCurve c = (TCBCurve) ShapeEditorResources.curveBuilder.loadInterpolator(i);\r
- double out = c.evaluate(t);\r
- g.setScalarDouble(i.getSingleRelatedObject(ShapeEditorResources.animationResource.HasTarget).getResource(), out);\r
- } else if (i.isInstanceOf(ShapeEditorResources.animationResource.SlerpInterpolator)) {\r
- // TODO : creating curve each time when time is set is slow.\r
- // Curve should be cached\r
- SlerpCurve c = (SlerpCurve) ShapeEditorResources.curveBuilder.loadInterpolator(i);\r
- Quat4d out = c.evaluate(t);\r
- Orientation r = new Orientation(i.getSingleRelatedObject(ShapeEditorResources.animationResource.HasTarget));\r
- AxisAngle4d aa = new AxisAngle4d();\r
- aa.set(out);\r
- G3DTools.setOrientation(r, aa);\r
- }\r
- }\r
- return GraphRequestStatus.transactionComplete();\r
- }\r
- \r
- @Override\r
- public void requestCompleted(GraphRequestStatus status) {\r
- parent.getScenegraphAdapter().setChanged(true);\r
- }\r
- }); \r
- }\r
- }\r
- \r
- private IEntity findPropertyInterpolator(Graph g, Resource property) {\r
- Collection<IEntity> interpolators = getAnimation(g).getRelatedObjects(ShapeEditorResources.animationResource.HasInterpolator);\r
- for (IEntity i : interpolators) {\r
- IEntity e = i.getAtMostOneRelatedObject(ShapeEditorResources.animationResource.HasTarget);\r
- if (e == null)\r
- continue;\r
- if (e.getResource().equals(property)) {\r
- return i;\r
- }\r
- }\r
- return null;\r
- }\r
- \r
- private void insertKeyFrame() {\r
- ArrayList<Resource> instances = new ArrayList<Resource>();\r
- for (Resource rs : parent.getSelectionAdapter().getCurrentSelection().getSelectionList()) {\r
- instances.add(rs);\r
- }\r
- PropertySelectionDialog dialog = new PropertySelectionDialog(parent.getRenderingComposite().getShell(),"Select property","Select animated property",parent.getSession(),instances);\r
- if (dialog.open() == Dialog.CANCEL) {\r
- return;\r
- }\r
- final List<Resource> properties = dialog.getSelectedPropertyInstances(); \r
- parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
- @Override\r
- public GraphRequestStatus perform(Graph g) throws Exception {\r
- for (Resource r : properties) {\r
- IEntity t = EntityFactory.create(g,r);\r
- IEntity current = findPropertyInterpolator(g, r);\r
- if (t.isInstanceOf(ShapeEditorResources.g3dResource.Position)) {\r
- \r
- for (int i = 0; i < 3; i++) {\r
- IEntity d = null;\r
- switch (i) {\r
- case 0:\r
- d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasX);\r
- break;\r
- case 1:\r
- d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasY);\r
- break;\r
- case 2:\r
- d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasZ);\r
- break;\r
- }\r
- current = findPropertyInterpolator(g, d.getResource());\r
- addScalarKey(current,d);\r
- }\r
- \r
- } else if (t.isInstanceOf(ShapeEditorResources.g3dResource.Orientation)) {\r
- Orientation rot = new Orientation(t);\r
- addSlerpKey(current, rot);\r
- } else if (t.isInstanceOf(ShapeEditorResources.g3dResource.Color)) {\r
- for (int i = 0; i < 3; i++) {\r
- IEntity d = null;\r
- switch (i) {\r
- case 0:\r
- d = t.getSingleRelatedObject(ShapeEditorResources.g3dResource.HasRed);\r
- break;\r
- case 1:\r
- break;\r
- case 2:\r
- break;\r
- }\r
- current = findPropertyInterpolator(g, d.getResource());\r
- addScalarKey(current,d);\r
- }\r
- } else if (t.isInstanceOf(g.getBuiltins().Double)) {\r
- addScalarKey(current,t);\r
- } else {\r
- // TODO: basic cases are handled, only way to support\r
- // is to find all doubles from property structure and\r
- // interpolators attached to them, if there's any\r
- ErrorLogger.getDefault().logWarning("Default keyframe adding has not been implemented", null);\r
- }\r
- }\r
- return GraphRequestStatus.transactionComplete();\r
- }\r
- });\r
- }\r
- \r
- private void addScalarKey(IEntity current, IEntity d) {\r
- \r
- Graph graph = d.getGraph();\r
- if (current == null) {\r
- current = ScalarInterpolator.createDefault(graph).toInterpolator(); // FIXME : stubcast\r
- getAnimation(graph).addStatement(ShapeEditorResources.animationResource.HasInterpolator, current);\r
- current.addStatement(ShapeEditorResources.animationResource.HasTarget, d);\r
- }\r
- ShapeEditorResources.curveBuilder.addKey(current,getCurrentKey(),new double[]{d.getGraph().getScalarDouble(d.getResource()),0.0,0.0,0.0});\r
- }\r
- \r
- private void addSlerpKey(IEntity current, Orientation r) {\r
- Graph graph = r.getGraph();\r
- if (current == null) {\r
- current = SlerpInterpolator.createDefault(graph).toInterpolator(); // FIXME : stubcast\r
- getAnimation(graph).addStatement(ShapeEditorResources.animationResource.HasInterpolator, current);\r
- current.addStatement(ShapeEditorResources.animationResource.HasTarget, r);\r
- \r
- }\r
- AxisAngle4d aa = G3DTools.getOrientation(r);\r
- Quat4d q = new Quat4d();\r
- q.set(aa);\r
- ShapeEditorResources.curveBuilder.addKey(current,getCurrentKey(),new double[]{q.w,q.x,q.y,q.z}); \r
- }\r
- \r
- private void selectAnimation() {\r
- if (animationCombo.getSelectionIndex() == 0) {\r
- animationResource = null;\r
- updateUI();\r
- } else {\r
- final String name = animationCombo.getItem(animationCombo.getSelectionIndex());\r
- parent.getSession().asyncRead(new GraphRequestAdapter() {\r
- @Override\r
- public GraphRequestStatus perform(Graph g) throws Exception {\r
- \r
- Resource modelResource = parent.getModelResource();\r
- G3DModel m = new G3DModel(g, modelResource);\r
- Collection<Animation> animations = m.getAnimation();\r
- boolean found = false;\r
- for (Animation a : animations) {\r
- if (a.getName().startsWith(name) && a.getName().length() == name.length()) {\r
- animationResource = a.getResource();\r
- found = true;\r
- break;\r
- }\r
- }\r
- if (!found) {\r
- ErrorLogger.defaultLogError("Could find animation " + name + " for model " + m.getResource(), null);\r
- animationResource = null;\r
- }\r
- return GraphRequestStatus.transactionComplete();\r
- }\r
- @Override\r
- public void requestCompleted(GraphRequestStatus status) {\r
- parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {\r
- @Override\r
- public void run() {\r
- updateUI(); \r
- }\r
- });\r
- }\r
- });\r
- } \r
- }\r
- \r
- private Animation getAnimation(Graph graph) {\r
- return new Animation(graph, animationResource);\r
- }\r
-\r
- private void addAnimation() {\r
- InputDialog d = new InputDialog(parent.getRenderingComposite().getShell(),"Animation name","Animation name","",null);\r
- if (d.open() == InputDialog.CANCEL) {\r
- return;\r
- }\r
- final String name = d.getValue();\r
- if (name == null || name.length() == 0) {\r
- return;\r
- }\r
- parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
- @Override\r
- public GraphRequestStatus perform(Graph g) throws Exception {\r
- G3DModel m = parent.getModel(g);\r
- Collection<IEntity> animations = m.getRelatedObjects(ShapeEditorResources.animationResource.HasAnimation);\r
- for (IEntity a : animations) {\r
- if (a.getName().startsWith(name) && a.getName().length() == name.length()) {\r
- ErrorLogger.getDefault().logWarning("Cannot add animation with the same name " + name, null);\r
- return GraphRequestStatus.transactionCancel();\r
- }\r
- }\r
-\r
- Animation newAnimation = Animation.createDefault(g);\r
- newAnimation.setName(name);\r
- m.addStatement(ShapeEditorResources.animationResource.HasAnimation, newAnimation);\r
- \r
- return GraphRequestStatus.transactionComplete();\r
- }\r
-\r
- @Override\r
- public void requestCompleted(GraphRequestStatus status) {\r
- parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {\r
- public void run() {\r
- animationCombo.add(name);\r
- animationCombo.select(animationCombo.indexOf(name));\r
- selectAnimation();\r
- }\r
- });\r
- }\r
- }); \r
- }\r
- \r
- private void removeAnimation() {\r
- assert(animationResource != null);\r
- GraphRequestWithResult<String> r = new GraphRequestWithResult<String>() {\r
- public String performWithResult(Graph g) throws Exception {\r
- return getAnimation(g).getName();\r
- };\r
- };\r
- parent.getSession().syncRead(r);\r
- 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
- if (dialog.open() == 1)\r
- return;\r
- parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
- String name;\r
- @Override\r
- public GraphRequestStatus perform(Graph g) throws Exception {\r
- \r
- Animation currentAnimation = getAnimation(g);\r
- name = currentAnimation.getName();\r
- parent.getModel(g).removeStatement(ShapeEditorResources.animationResource.HasAnimation, currentAnimation);\r
- \r
- return GraphRequestStatus.transactionComplete();\r
- }\r
- \r
- @Override\r
- public void requestCompleted(GraphRequestStatus status) {\r
- parent.getRenderingComposite().getDisplay().asyncExec(new Runnable() {\r
- public void run() {\r
- animationCombo.remove(animationCombo.indexOf(name));\r
- }\r
- }); \r
- }\r
- });\r
- }\r
- \r
- private void clearAnimation() {\r
- assert(animationResource != null); \r
- \r
- parent.getSession().asyncWrite(new GraphRequestAdapter() {\r
- \r
- boolean proceed;\r
- @Override\r
- public GraphRequestStatus perform(Graph g) throws Exception {\r
- int size = getAnimation(g).getInterpolator().size();\r
- if (size == 0)\r
- return GraphRequestStatus.transactionCancel();\r
- final String name = getAnimation(g).getName();\r
- parent.getRenderingComposite().getDisplay().syncExec(new Runnable() {\r
- public void run() {\r
- MessageDialog dialog = new MessageDialog(parent.getRenderingComposite().getShell(),"Confirm",null,"Do you want to clear animation " + name ,MessageDialog.QUESTION,new String[]{"Yes","No"},1);\r
- proceed = (dialog.open() != MessageDialog.CANCEL);\r
- }\r
- });\r
- if (proceed) {\r
- //getAnimation(g).getInterpolator().clear();\r
- getAnimation(g).removeRelatedStatements(ShapeEditorResources.animationResource.HasInterpolator);\r
- return GraphRequestStatus.transactionComplete();\r
- } else {\r
- return GraphRequestStatus.transactionCancel();\r
- }\r
- }\r
- });\r
- }\r
- \r
- public Graph createAnimationParameterization(Graph g) {\r
- if (g.getObjects(parent.getModelResource(), ShapeEditorResources.g3dResource.HasSizingParameter).size() > 0) {\r
- ContextGraph graph;\r
- if (!(g instanceof ContextGraph)) {\r
- graph = new ContextGraph(g);\r
- graph.setContext(parent.getModelResource());\r
- } else {\r
- graph = (ContextGraph)g;\r
- }\r
- Animation animation = getAnimation(graph);\r
- Collection<Interpolator> interpolators = animation.getInterpolator();\r
- for (org.simantics.animation.stubs.Interpolator interpolator : interpolators) {\r
- IEntity target = interpolator.getTarget();\r
- // check all model properties\r
- G3DModel model = parent.getModel(graph);\r
- Collection<Property> modelProperties = model.getRelatedProperties(ShapeEditorResources.g3dResource.HasSizingParameter);\r
- for (Property p : modelProperties) {\r
- IEntity t = EntityFactory.create(graph,p.getResource());\r
- // get parameterization equations\r
- Collection<IEntity> equations = t.getRelatedObjects(ShapeEditorResources.equationResource.HasTarget);\r
- // get parameterized values\r
- Collection<IEntity> parameterTargets = new ArrayList<IEntity>();\r
- for (IEntity eq : equations) {\r
- Collection<IEntity> tgts = eq.getRelatedObjects(ShapeEditorResources.equationResource.HasTarget);\r
- assert(tgts.size() == 1);\r
- parameterTargets.add(tgts.iterator().next());\r
- }\r
- // do matching between interpolator targets and parameterized values\r
- // TODO : old system did not have inverse relations but current system does.\r
- // it is possible to take interpolation target and find if it is connected to an equation\r
- // this would make code much faster (no more stupid loops over everything)\r
- for (IEntity d : parameterTargets) {\r
- if (d.getResource().equals(target.getResource())) {\r
- // get default value for sizing property\r
- Collection<IEntity> prop = t.getRelatedObjects(ShapeEditorResources.g3dResource.HasDefaultDoubleValue);\r
- if (prop.size() == 1) {\r
- ShapeEditorResources.curveBuilder.parameterize(interpolator, prop.iterator().next().toProperty().getDoubleArray(), p.getDoubleArray());\r
- } else {\r
- ErrorLogger.defaultLogError("Cannot parameterize interpolator " + interpolator.getResource() + " of animation " + animation.getResource() + " since parameter " + p.getResource() + " has no default value", null);\r
- }\r
- }\r
- }\r
- }\r
- }\r
- \r
- return graph;\r
- } else {\r
- return g;\r
- }\r
- }\r
- \r
- private AnimateRunnable animateRunnable = null;\r
- \r
- private void animate() {\r
- updateUI();\r
- if (animateButton.getSelection()) {\r
- if (animateRunnable != null)\r
- return;\r
- if (usePrecalculation.getSelection()) {\r
- parent.getSession().asyncRead(new GraphRequestAdapter() {\r
- @Override\r
- public GraphRequestStatus perform(Graph g) throws Exception {\r
- Graph graph = parent.createParameterization(g);\r
- createAnimationParameterization(graph);\r
- for (IGraphicsNode n : parent.getScenegraphAdapter().getNodes()) {\r
- if (n instanceof ISelectableNode) {\r
- if (!((ISelectableNode)n).isVisible())\r
- continue;\r
- }\r
- if (n instanceof Animatable) {\r
- ((Animatable)n).setAnimation(graph,animationResource);\r
- }\r
- }\r
- return GraphRequestStatus.transactionComplete();\r
- }\r
- \r
- @Override\r
- public void requestCompleted(GraphRequestStatus status) {\r
- animateRunnable = new AnimateRunnable();\r
- VisualizationScheduler.getInstance().addVisualization(animateRunnable);\r
- }\r
- });\r
- } else {\r
- animateRunnable = new AnimateRunnable();\r
- VisualizationScheduler.getInstance().addVisualization(animateRunnable);\r
- }\r
- \r
- } else {\r
- if (animateRunnable == null)\r
- return; \r
- VisualizationScheduler.getInstance().removeVisualization(animateRunnable);\r
- animateRunnable = null;\r
- if (usePrecalculation.getSelection()) {\r
- // updateTime updates values to graph if precalculation is not used.\r
- // we must store current values from animation to synchronize view and graph\r
- // information so that use can modify animation properly.\r
- usePrecalculation.setSelection(false);\r
- updateTime();\r
- usePrecalculation.setSelection(true);\r
- for (IGraphicsNode n : parent.getScenegraphAdapter().getNodes()) {\r
- if (n instanceof Animatable) {\r
- ((Animatable)n).setAnimation(null,null);\r
- }\r
- }\r
- }\r
- }\r
- }\r
- \r
- private void updateUI() {\r
- if (animationResource != null) {\r
- animateButton.setEnabled(true);\r
- timeSlider.setEnabled(true);\r
- if (animateButton.getSelection()) {\r
- addAnimationButton.setEnabled(false);\r
- insertKeyFrameButton.setEnabled(false);\r
- removeAnimationButton.setEnabled(false);\r
- clearKeyFrameButton.setEnabled(false);\r
- animationCombo.setEnabled(false);\r
- usePrecalculation.setEnabled(false);\r
- clearAnimationButton.setEnabled(false);\r
- } else {\r
- addAnimationButton.setEnabled(true);\r
- insertKeyFrameButton.setEnabled(!parent.getSelectionAdapter().getCurrentSelection().isEmpty());\r
- removeAnimationButton.setEnabled(true);\r
- clearKeyFrameButton.setEnabled(false); //FIXME : detect keyframes\r
- animationCombo.setEnabled(true);\r
- usePrecalculation.setEnabled(true);\r
- clearAnimationButton.setEnabled(true);\r
- } \r
- } else {\r
- timeSlider.setEnabled(false);\r
- addAnimationButton.setEnabled(true);\r
- insertKeyFrameButton.setEnabled(false);\r
- removeAnimationButton.setEnabled(false);\r
- clearKeyFrameButton.setEnabled(false);\r
- animateButton.setEnabled(false);\r
- animateButton.setSelection(false);\r
- animationCombo.setEnabled(true);\r
- usePrecalculation.setEnabled(false);\r
- clearAnimationButton.setEnabled(false);\r
- }\r
- }\r
- \r
- private void updateKey(double k) {\r
- key = k;\r
- if (key >= 1.0)\r
- key = 0.0;\r
- else if (key < 0.0)\r
- key = 1.0;\r
- timeSlider.setSelection((int)(key*100.0));\r
- }\r
- \r
- private class AnimateRunnable implements Runnable {\r
- public void run() {\r
- try {\r
- updateKey(key + 0.01);\r
- updateTime();\r
- } catch (Exception e) {\r
- VisualizationScheduler.getInstance().removeVisualization(animateRunnable);\r
- }\r
- }\r
- }\r
- \r
- @Override\r
- public void fillLocalToolBar(IToolBarManager manager) {\r
-\r
- }\r
- \r
- @Override\r
- public void fillLocalPullDown(IMenuManager manager) {\r
- \r
- }\r
- \r
- @Override\r
- public void dispose() {\r
- \r
- }\r
- \r
- @Override\r
- public void run() {\r
-\r
- }\r
-\r
-}\r