예제 #1
0
        public void Update(GameTime gameTime)
        {
            if (State == AnimationState.Playing)
            {
                var currentTime = gameTime.TotalGameTime.Ticks;

                // Initialize the star time if necessary.
                if (_startTime < 0)
                {
                    _startTime = currentTime;
                    _endTime   = _startTime + Duration.Ticks;

                    AnimationStarted();
                    OnStarted();
                }

                // Calculate the current progress.
                Position = MathHelper.Clamp(1.0f - 1.0f / (_endTime - _startTime) * (_endTime - currentTime), 0.0f, 1.0f);
                OnProgress(Position);

                // Calculate the easing.
                var easing = Easing != null?Easing.Calculate(Position) : Position;

                DoAnimation(Position, easing);

                // Check if the animation has been finished.
                if (currentTime >= _endTime)
                {
                    State = AnimationState.Finished;

                    AnimationFinished();
                    OnFinished();
                }
            }
        }
예제 #2
0
        public void StaticFunctionTests()
        {
            void InverseWorking(Easing.EaseType easeType, Easing.EaseOption easeOption, double k)
            {
                var output = Easing.Calculate(easeType, easeOption, k);

                var input = Easing.CalculateInverse(easeType, easeOption, output);

                Assert.AreEqual(k, input, .001);
            }

            void RangeTest(Easing.EaseType easeType)
            {
                for (double i = 0; i <= 1; i += .05)
                {
                    InverseWorking(easeType, Easing.EaseOption.In, i);
                    InverseWorking(easeType, Easing.EaseOption.InOut, i);
                    InverseWorking(easeType, Easing.EaseOption.Out, i);
                }
            }

            RangeTest(Easing.EaseType.Linear);
            RangeTest(Easing.EaseType.Cubic);
            RangeTest(Easing.EaseType.Quadratic);
        }
예제 #3
0
        public override Task Rebuild()
        {
            this.DebugDepth("Rebuild");

            bool valuesChanged = false;

            if (Angle < 1 || Angle > 100000)
            {
                Angle         = Math.Min(100000, Math.Max(1, Angle));
                valuesChanged = true;
            }

            if (RotationDistance < 0 || RotationDistance > 100000)
            {
                RotationDistance = Math.Min(100000, Math.Max(0, RotationDistance));
                valuesChanged    = true;
            }

            if (RotationSlices < 3 || RotationSlices > 300)
            {
                RotationSlices = Math.Min(300, Math.Max(3, RotationSlices));
                valuesChanged  = true;
            }

            if (EndHeightPercent < 1 || EndHeightPercent > 100)
            {
                EndHeightPercent = Math.Min(100, Math.Max(1, EndHeightPercent));
                valuesChanged    = true;
            }

            if (StartHeightPercent < 0 || StartHeightPercent > EndHeightPercent - 1)
            {
                StartHeightPercent = Math.Min(EndHeightPercent - 1, Math.Max(0, StartHeightPercent));
                valuesChanged      = true;
            }

            if (OverrideRadius < .01)
            {
                OverrideRadius = Math.Max(this.GetAxisAlignedBoundingBox().XSize, this.GetAxisAlignedBoundingBox().YSize);
                valuesChanged  = true;
            }

            var rebuildLocks = this.RebuilLockAll();

            return(ApplicationController.Instance.Tasks.Execute(
                       "Twist".Localize(),
                       null,
                       (reporter, cancellationToken) =>
            {
                var sourceAabb = this.SourceContainer.GetAxisAlignedBoundingBox();

                var bottom = sourceAabb.MinXYZ.Z;
                var top = sourceAabb.ZSize * EndHeightPercent / 100.0;
                var size = sourceAabb.ZSize;
                if (Advanced)
                {
                    bottom += sourceAabb.ZSize * StartHeightPercent / 100.0;
                    size = top - bottom;
                }

                double numberOfCuts = RotationSlices;

                double cutSize = size / numberOfCuts;
                var cuts = new List <double>();
                for (int i = 0; i < numberOfCuts + 1; i++)
                {
                    var ratio = i / numberOfCuts;
                    if (Advanced)
                    {
                        var goal = ratio;
                        var current = .5;
                        var next = .25;
                        // look for an x value that equals the goal
                        for (int j = 0; j < 64; j++)
                        {
                            var xAtY = Easing.Calculate(EasingType, EasingOption, current);
                            if (xAtY < goal)
                            {
                                current += next;
                            }
                            else if (xAtY > goal)
                            {
                                current -= next;
                            }

                            next *= .5;
                        }

                        ratio = current;
                    }

                    cuts.Add(bottom - cutSize + (size * ratio));
                }

                // get the rotation from the center of the circumscribed circle of the convex hull
                var enclosingCircle = SourceContainer.GetSmallestEnclosingCircleAlongZ();
                var rotationCenter = enclosingCircle.Center + RotationOffset;

                var twistedChildren = new List <IObject3D>();

                var status = new ProgressStatus();

                foreach (var sourceItem in SourceContainer.VisibleMeshes())
                {
                    var originalMesh = sourceItem.Mesh;
                    status.Status = "Copy Mesh".Localize();
                    reporter.Report(status);
                    var transformedMesh = originalMesh.Copy(CancellationToken.None);
                    var itemMatrix = sourceItem.WorldMatrix(SourceContainer);

                    // transform into this space
                    transformedMesh.Transform(itemMatrix);

                    status.Status = "Split Mesh".Localize();
                    reporter.Report(status);

                    // split the mesh along the z axis
                    transformedMesh.SplitOnPlanes(Vector3.UnitZ, cuts, cutSize / 8);

                    for (int i = 0; i < transformedMesh.Vertices.Count; i++)
                    {
                        var position = transformedMesh.Vertices[i];

                        var ratio = (position.Z - bottom) / size;

                        if (Advanced)
                        {
                            if (position.Z < bottom)
                            {
                                ratio = 0;
                            }
                            else if (position.Z > top)
                            {
                                ratio = 1;
                            }
                            else
                            {
                                ratio = (position.Z - bottom) / size;
                                ratio = Easing.Calculate(EasingType, EasingOption, ratio);
                            }
                        }

                        var angleToRotate = ratio * Angle / 360.0 * MathHelper.Tau;
                        if (RotationType == RotationTypes.Distance)
                        {
                            IRadiusProvider radiusProvider = RadiusProvider;

                            // start off with assuming we want to set the radius
                            var radius = this.OverrideRadius;
                            if (radiusProvider != null && !this.EditRadius)
                            {
                                // have a radius provider and not wanting to edit
                                radius = radiusProvider.Radius;
                            }
                            else if (!this.EditRadius)
                            {
                                // not wanting to edit
                                radius = enclosingCircle.Radius;
                            }

                            if (this.PreferedRadius != radius)
                            {
                                this.PreferedRadius = radius;
                                this.OverrideRadius = radius;
                                UiThread.RunOnIdle(() => Invalidate(InvalidateType.DisplayValues));
                            }

                            angleToRotate = ratio * (RotationDistance / radius);
                        }

                        if (!TwistCw)
                        {
                            angleToRotate = -angleToRotate;
                        }

                        var positionXy = new Vector2(position) - rotationCenter;
                        positionXy.Rotate(angleToRotate);
                        positionXy += rotationCenter;
                        transformedMesh.Vertices[i] = new Vector3Float(positionXy.X, positionXy.Y, position.Z);
                    }

                    // transform back into item local space
                    transformedMesh.Transform(itemMatrix.Inverted);

                    //transformedMesh.MergeVertices(.1);
                    transformedMesh.CalculateNormals();

                    var twistedChild = new Object3D()
                    {
                        Mesh = transformedMesh
                    };
                    twistedChild.CopyWorldProperties(sourceItem, SourceContainer, Object3DPropertyFlags.All, false);
                    twistedChild.Visible = true;

                    twistedChildren.Add(twistedChild);
                }

                RemoveAllButSource();
                this.SourceContainer.Visible = false;

                this.Children.Modify((list) =>
                {
                    list.AddRange(twistedChildren);
                });

                if (valuesChanged)
                {
                    Invalidate(InvalidateType.DisplayValues);
                }

                UiThread.RunOnIdle(() =>
                {
                    rebuildLocks.Dispose();
                    Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Children));
                });

                return Task.CompletedTask;
            }));
        }
예제 #4
0
        public static GuiWidget GetFieldContentWithSlider(EditableProperty property, PPEContext context, UIField field, UndoBuffer undoBuffer, Func <string, object> valueFromString, ThemeConfig theme)
        {
            var sliderAttribute = property.PropertyInfo.GetCustomAttributes(true).OfType <SliderAttribute>().FirstOrDefault();

            if (sliderAttribute != null)
            {
                var min   = sliderAttribute.Min;
                var max   = sliderAttribute.Max;
                var delta = max - min;

                // the slider values go from 0 to 1 and are then mapped during translation to the field
                var slider = new Slider(new Vector2(0, 0), 80 * GuiWidget.DeviceScale, 0, 1)
                {
                    VAnchor = VAnchor.Center,
                };

                slider.View.TrackColor  = theme.TextColor;
                slider.View.ThumbColor  = theme.PrimaryAccentColor;
                slider.View.TrackHeight = 1 * GuiWidget.DeviceScale;

                Func <double> getFieldValue = null;

                double GetSlider0To1FromField()
                {
                    return(GetSlider0To1FromValue(getFieldValue()));
                }

                double GetSlider0To1FromValue(double value)
                {
                    var mapped0To1 = Math.Max(0, Math.Min(1, (value - min) / delta));

                    return(Easing.CalculateInverse(sliderAttribute.EasingType, sliderAttribute.EaseOption, mapped0To1));
                }

                double GetFieldFromSlider0To1()
                {
                    var fieldValue = Easing.Calculate(sliderAttribute.EasingType,
                                                      sliderAttribute.EaseOption,
                                                      slider.Value) * delta + min;

                    var snapGridDistance = sliderAttribute.SnapDistance;

                    if (sliderAttribute.UseSnappingGrid)
                    {
                        snapGridDistance = SnapGridDistance();
                    }
                    if (snapGridDistance > 0)
                    {
                        // snap this position to the grid
                        // snap this position to the grid
                        fieldValue = ((int)((fieldValue / snapGridDistance) + .5)) * snapGridDistance;
                    }

                    return(fieldValue);
                }

                double SnapGridDistance()
                {
                    var view3DWidget = slider.Parents <View3DWidget>().FirstOrDefault();

                    if (view3DWidget != null)
                    {
                        var object3DControlLayer = view3DWidget.Descendants <Object3DControlsLayer>().FirstOrDefault();
                        if (object3DControlLayer != null)
                        {
                            return(object3DControlLayer.SnapGridDistance);
                        }
                    }

                    return(0);
                }

                var changeDueToSlider = false;
                var changeDueToField  = false;

                slider.ValueChanged += (s, e) =>
                {
                    if (!changeDueToField)
                    {
                        changeDueToSlider = true;
                        SetValue(property, context, valueFromString, GetFieldFromSlider0To1());
                        changeDueToSlider = false;
                    }
                };

                double sliderDownValue = 0;
                slider.SliderGrabed += (s, e) =>
                {
                    sliderDownValue = getFieldValue();
                };

                slider.SliderReleased += (s, e) =>
                {
                    var currentValue = GetFieldFromSlider0To1();

                    changeDueToSlider = true;
                    SetValue(property, context, valueFromString, currentValue);
                    changeDueToSlider = false;

                    // save the undo information
                    undoBuffer.Add(new UndoRedoActions(() =>
                    {
                        SetValue(property, context, valueFromString, sliderDownValue);
                    },
                                                       () =>
                    {
                        SetValue(property, context, valueFromString, currentValue);
                    }));
                };

                GuiWidget content           = null;
                var       sliderRightMargin = 11;
                if (field is DoubleField doubleField)
                {
                    getFieldValue = () => doubleField.DoubleValue;

                    doubleField.ValueChanged += (s, e) =>
                    {
                        changeDueToField = true;
                        slider.Value     = GetSlider0To1FromField();
                        changeDueToField = false;
                    };

                    content = new FlowLayoutWidget();
                    content.AddChild(slider);
                    content.AddChild(new GuiWidget()
                    {
                        Width  = sliderRightMargin * GuiWidget.DeviceScale,
                        Height = 3
                    });
                    content.AddChild(field.Content);
                }
                else if (field is ExpressionField expressionField)
                {
                    getFieldValue = () =>
                    {
                        if (double.TryParse(expressionField.Value, out double value))
                        {
                            return(value);
                        }

                        return(0);
                    };

                    expressionField.ValueChanged += (s, e) =>
                    {
                        if (!changeDueToSlider)
                        {
                            changeDueToField = true;
                            slider.Value     = GetSlider0To1FromField();
                            changeDueToField = false;
                        }
                    };

                    expressionField.Content.Descendants <TextWidget>().First().TextChanged += (s, e) =>
                    {
                        if (!changeDueToSlider)
                        {
                            changeDueToField = true;
                            var textWidget = expressionField.Content.Descendants <TextWidget>().First();
                            double.TryParse(textWidget.Text, out double textWidgetValue);
                            slider.Value     = GetSlider0To1FromValue(textWidgetValue);
                            changeDueToField = false;
                        }
                    };

                    var leftHold = new FlowLayoutWidget()
                    {
                        HAnchor = HAnchor.Stretch,
                        Margin  = new BorderDouble(0, 0, 66 / GuiWidget.DeviceScale + sliderRightMargin, 0)
                    };
                    leftHold.AddChild(new HorizontalSpacer());
                    leftHold.AddChild(slider);
                    field.Content.AddChild(leftHold, 0);

                    content = field.Content;
                }

                // set the initial value of the slider
                changeDueToField = true;
                slider.Value     = GetSlider0To1FromField();
                changeDueToField = false;

                return(content);
            }

            return(field.Content);
        }