protected override void OnCreate()
        {
            base.OnCreate();

            var scene = CreateScene(false);

            Component_Mesh mesh = ObjectOfPreview as Component_Mesh;

            if (mesh != null)
            {
                Component_MeshInSpace objInSpace = scene.CreateComponent <Component_MeshInSpace>();
                objInSpace.Mesh = mesh;
            }

            scene.Enabled = true;

            SetCameraByBounds(scene.CalculateTotalBoundsOfObjectsInSpace());

            if (mesh.EditorCameraTransform != null)
            {
                var tr = mesh.EditorCameraTransform;
                CameraInitialDistance = (tr.Position - CameraLookTo).Length();
                CameraDirection       = SphericalDirection.FromVector(CameraLookTo - tr.Position);
            }
        }
        //void ParentSprite_GetRenderSceneDataBefore( Component_ObjectInSpace sender, ViewportRenderingContext context, GetRenderSceneDataMode mode )
        //{
        //}

        private void ParentSprite_GetRenderSceneDataAddToFrameData(Component_MeshInSpace sender, ViewportRenderingContext context, GetRenderSceneDataMode mode, ref Component_RenderingPipeline.RenderSceneData.MeshItem item)
        {
            Component_Material material = null;

            var animation = PlayAnimation.Value as Component_SpriteAnimation;

            if (animation != null)
            {
                UpdateAnimationTime();

                material = animation.Material;

                var frame = animation.GetFrameByTime(currentAnimationTime);
                if (frame != null)
                {
                    var m = frame.Material.Value;
                    if (m != null)
                    {
                        material = m;
                    }
                }
            }

            item.ReplaceMaterial            = material;
            item.ReplaceMaterialSelectively = null;
        }
Esempio n. 3
0
        protected override void OnEnabledInSimulation()
        {
            //create a mesh
            mesh      = CreateComponent <Component_Mesh>(enabled: false);
            mesh.Name = "Mesh 1";

            //generate vertices. use StandardVertex to make it easier
            StandardVertex.StaticOneTexCoord[] vertices = new StandardVertex.StaticOneTexCoord[4];

            var v = new StandardVertex.StaticOneTexCoord();

            v.Position = new Vector3F(-0.4f, -0.4f, 0f);
            v.Normal   = new Vector3F(0, 0, 1);
            v.Tangent  = new Vector4F(1, 0, 0, 0);
            v.Color    = new ColorValue(1, 1, 1);
            //v.TexCoord0 = new Vector2F(-1, -1);

            vertices[0] = v;

            v.Position  = new Vector3F(0.4f, -0.4f, 0);
            vertices[1] = v;

            v.Position  = new Vector3F(0.4f, 0.4f, 0);
            vertices[2] = v;

            v.Position  = new Vector3F(-0.4f, 0.4f, 0);
            vertices[3] = v;

            //generate indices
            var indices = new int[] { 0, 1, 2, 2, 3, 0 };

            //create geometry of the mesh
            geometry = mesh.CreateComponent <Component_MeshGeometry>();
            geometry.VertexStructure = StandardVertex.MakeStructure(StandardVertex.Components.StaticOneTexCoord, true, out int vertexSize);
            geometry.Vertices        = ConvertVertices(vertices);
            geometry.Indices         = indices;


            //mesh has been created, now we can enable it
            mesh.Enabled = true;

            meshInSpace           = CreateComponent <Component_MeshInSpace>(enabled: false);
            meshInSpace.Transform = new Transform(new Vector3(1, 1, 1));

            //make reference to the mesh. 'Root' reference - global path from scene root.
            meshInSpace.Mesh = ReferenceUtility.MakeRootReference(mesh);

            meshInSpace.Color   = new ColorValue(1, 0, 0);
            meshInSpace.Enabled = true;
        }
        private void ParentSprite_MeshOutputOverride(Component_MeshInSpace sender, ref Component_Mesh result)
        {
            var animation = PlayAnimation.Value as Component_SpriteAnimation;

            if (animation != null)
            {
                UpdateAnimationTime();

                var frame = animation.GetFrameByTime(currentAnimationTime);
                if (frame != null)
                {
                    result = SpriteMeshManager.GetMesh(frame.UV.Value.ToRectangleF());
                }
            }
        }
        protected override void CalculateCPU(Component_Skeleton skeleton, Component_Mesh originalMesh, Component_Mesh modifiableMesh)
        {
            if (EngineApp.ApplicationType == EngineApp.ApplicationTypeEnum.Simulation)
            {
                if (Component_Scene.All != null && Component_Scene.All.Length > 0)
                {
//					Component_MeshInSpace[] sphs = new Component_MeshInSpace[2];
//					Component_MeshInSpace sph = Component_Scene.All[0]?.GetComponent<Component_MeshInSpace>("chest");
//					sphs[0] = sph?.GetComponent<Component_MeshInSpace>("upper_arm.R");
//					sphs[1] = sphs[0]?.GetComponent<Component_MeshInSpace>("forearm.R");

//					var bones = skeleton?.GetBones(false);
//					if (bones != null)
//					{
//						var sR = Array.Find(bones, item => item.Name == "upper_arm.R");
//						sR.Transform = new Transform(sphs[0].TransformV.Position, sphs[0].TransformV.Rotation, sR.Transform.Value.Scale);
//						var sR1 = Array.Find(bones, item => item.Name == "forearm.R");
//						sR1.Transform = new Transform(sphs[1].TransformV.Position, sphs[1].TransformV.Rotation, sR1.Transform.Value.Scale);

//					}

                    Component_MeshInSpace sph = Component_Scene.All[0]?.GetComponent <Component_MeshInSpace>("chest");
                    var sphch = sph.GetComponents <Component_MeshInSpace>(false, true, false);

                    var bones = skeleton?.GetBones(false);
                    if (bones != null)
                    {
                        var sR = Array.Find(bones, item => item.Name == "chest");
                        sR.Transform = new Transform(sph.TransformV.Position, sph.TransformV.Rotation, sR.Transform.Value.Scale);
                        var chB = sR.GetComponents <Component_SkeletonBone>(false, true, false);

                        for (int i = 0; i < chB.Length; i = i + 1)
                        {
                            var cursph = Array.Find(sphch, item => item.Name == chB[i].Name);
                            if (cursph != null)
                            {
                                chB[i].Transform = new Transform(cursph.TransformV.Position, cursph.TransformV.Rotation, chB[i].Transform.Value.Scale);
                            }
                        }
                    }
                }

                MainViewport_UpdateBeforeOutput(Project.SimulationApp.MainViewport, skeleton);
                base.CalculateCPU(skeleton, originalMesh, modifiableMesh);
            }
        }
Esempio n. 6
0
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            var scene = CreateScene(false);

            Component_Mesh mesh = ObjectForPreview as Component_Mesh;

            if (mesh != null)
            {
                Component_MeshInSpace objInSpace = scene.CreateComponent <Component_MeshInSpace>();
                objInSpace.Mesh = mesh;
            }

            scene.Enabled = true;

            SetCameraByBounds(scene.CalculateTotalBoundsOfObjectsInSpace());
        }
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            var scene = CreateScene(false);

            if (Mesh != null)
            {
                Component_MeshInSpace objInSpace = scene.CreateComponent <Component_MeshInSpace>();
                objInSpace.Mesh             = Mesh;
                skeletonAnimationController = objInSpace.CreateComponent <Component_MeshInSpaceAnimationController>();
            }
            scene.Enabled = true;

            if (Document != null)
            {
                Document.UndoSystem.ListOfActionsChanged += UndoSystem_ListOfActionsChanged;
            }

            if (ObjectOfWindow != null)
            {
                SelectObjects(new object[] { ObjectOfWindow });
            }
        }
Esempio n. 8
0
        //static byte[] ToVertices( Net3dBool.Vector3[] vertices, MeshData.MeshGeometryFormat vs )
        //{
        //	byte[] ret = new byte[ vertices.Length * vs.vertexSize ];
        //	unsafe
        //	{
        //		fixed ( byte* ptr = ret )
        //		{
        //			for( int i = 0; i < vertices.Length; i++ )
        //			{
        //				var v = vertices[ i ];

        //				var pos = (Vector3F*)( ptr + i * vs.vertexSize + vs.positionOffset );
        //				( *pos ) = new Vector3F( (float)v.x, (float)v.y, (float)v.z );
        //			}
        //		}
        //	}

        //	return ret;
        //}


        //The data are extracted from Component_Mesh.ExtractedStructure.
        //Хотя можно взять из MeshGeometry.Vertices,Indices, но там проиндексировано вместе с другими элементами(normals,...).
        static List <(Vector3F[] positions, int[] indices)> GetData(Component_MeshInSpace ms)
        {
            Component_Mesh.ExtractedStructure structure = ms.Mesh.Value.ExtractStructure();

            var ret = new List <(Vector3F[] positions, int[] indices)>();

            //extract old positions
            var oldPositions = new Vector3F[structure.MeshGeometries.Length][];

            for (int geomIndex = 0; geomIndex < structure.MeshGeometries.Length; geomIndex++)
            {
                var vs = new MeshData.MeshGeometryFormat(structure.MeshGeometries[geomIndex].VertexStructure);
                oldPositions[geomIndex] = new Vector3F[structure.MeshGeometries[geomIndex].Vertices.Length / vs.vertexSize];

                unsafe
                {
                    fixed(byte *ptr = structure.MeshGeometries[geomIndex].Vertices)
                    {
                        for (int i = 0; i < oldPositions[geomIndex].Length; i++)
                        {
                            oldPositions[geomIndex][i] = *(Vector3F *)(ptr + i * vs.vertexSize + vs.positionOffset);
                        }
                    }
                }
            }
            //------------

            var geomTriangles = new List <Component_Mesh.StructureClass.FaceVertex> [structure.MeshGeometries.Length];

            for (int i = 0; i < structure.MeshGeometries.Length; i++)
            {
                geomTriangles[i] = new List <Component_Mesh.StructureClass.FaceVertex>();
            }
            for (int faceIndex = 0; faceIndex < structure.Structure.Faces.Length; faceIndex++)
            {
                var face = structure.Structure.Faces[faceIndex];
                for (int i = 0; i < face.Triangles.Length; i++)
                {
                    geomTriangles[face.Triangles[i].RawGeometry].Add(face.Triangles[i]);
                }
            }

            for (int i = 0; i < geomTriangles.Length; i++)
            {
                var   g = geomTriangles[i];
                int[] oldVertexToNewMapping = new int[structure.Structure.Vertices.Length];
                for (int j = 0; j < oldVertexToNewMapping.Length; j++)
                {
                    oldVertexToNewMapping[j] = -1;
                }
                int nextIndex    = 0;
                var newPositions = new List <Vector3F>();
                var newIndices   = new int[g.Count];

                for (int j = 0; j < g.Count; j++)
                {
                    var tv       = g[j];
                    int newIndex = oldVertexToNewMapping[tv.Vertex];
                    if (newIndex == -1)
                    {
                        newIndex = nextIndex++;
                        oldVertexToNewMapping[tv.Vertex] = newIndex;
                        newPositions.Add(oldPositions[tv.RawGeometry][tv.RawVertex]);
                    }
                    newIndices[j] = newIndex;
                }
                ret.Add((newPositions.ToArray(), newIndices));
            }

            return(ret);
        }
Esempio n. 9
0
        public static void BoolActionExecute(Component_MeshInSpace firstMeshInSpace, Component_MeshInSpace secondMeshInSpace, UndoMultiAction undo, DocumentInstance document, BoolActionEnum boolAction)
        {
            //the first operand of the union operation must be a single geometry, otherwise duplicate parts will be made.
            if (boolAction == BoolActionEnum.Union && 1 < firstMeshInSpace.Mesh.Value.GetComponents <Component_MeshGeometry>().Length)
            {
                MergeGeometries(firstMeshInSpace.Mesh, document, undo);
            }
            bool needUndoForNextActions = true;

            CommonFunctions.ConvertProceduralMeshGeometries(document, firstMeshInSpace.Mesh, undo, ref needUndoForNextActions);

            List <(Vector3F[] positions, int[] indices)> data1List = GetData(firstMeshInSpace);

            (Vector3F[] positions, int[] indices)data2 = MergeData(GetData(secondMeshInSpace));

            //convert the second mesh in space, to the transform of first mesh in space
            var matrix = firstMeshInSpace.Transform.Value.ToMatrix4().GetInverse() * secondMeshInSpace.Transform.Value.ToMatrix4();

            Net3dBool.Vector3[] vertices2 = new Net3dBool.Vector3[data2.positions.Length];
            for (int i = 0; i < data2.positions.Length; i++)
            {
                vertices2[i] = ToNet3DBoolVector3((matrix * data2.positions[i]).ToVector3F());
            }
            var operand2 = new Net3dBool.Solid(vertices2, data2.indices);

            var geometries         = firstMeshInSpace.Mesh.Value.GetComponents <Component_MeshGeometry>();
            var resultGeometries   = new List <(Vector3F[] positions, int[] indices, MeshData.MeshGeometryFormat format)>();
            var geometriesToDelete = new List <Component_MeshGeometry>();

            for (int geomIndex = 0; geomIndex < data1List.Count; geomIndex++)
            {
                var data1 = data1List[geomIndex];
                Net3dBool.Vector3[] vertices1 = data1.positions.Select(ToNet3DBoolVector3).ToArray();

                var modeller = new Net3dBool.BooleanModeller(new Net3dBool.Solid(vertices1, data1.indices), operand2);                     //Большую часть времени на вычисления занимает эта сторка

                Net3dBool.Solid result = null;
                switch (boolAction)
                {
                case BoolActionEnum.Union: result = modeller.GetUnion(); break;

                case BoolActionEnum.Intersect: result = modeller.GetIntersection(); break;

                case BoolActionEnum.Subtract: result = modeller.GetDifference(); break;

                default: return;
                }

                var newVertices = result.getVertices().Select(ToVector3F).ToArray();
                if (0 < newVertices.Length)
                {
                    resultGeometries.Add((newVertices, result.getIndices(), new MeshData.MeshGeometryFormat(geometries[geomIndex].VertexStructure)));
                }
                else
                {
                    geometriesToDelete.Add(geometries[geomIndex]);
                }
            }

            foreach (var g in resultGeometries)
            {
                if (!CheckValid(g.positions, g.indices))
                {
                    throw new Exception();
                }
            }

            //delete empty mesh geometry //
            if (0 < geometriesToDelete.Count)
            {
                undo?.AddAction(new UndoActionComponentCreateDelete(document, geometriesToDelete.ToArray(), create: false));
            }

            var meshData = MeshData.BuildFromRaw(resultGeometries);

            meshData?.Save(firstMeshInSpace.Mesh.Value, needUndoForNextActions ? undo : null, null);               //??? No selection?
            firstMeshInSpace.Mesh.Value?.RebuildStructure();
        }
Esempio n. 10
0
        //??? Для объединенного MeshInSpace transform выбирать как у первого MeshInSpace или лучше считать средний transform?
        //??? MeshInSpace.ReplaceMeterial,ReplaceMeterialSelectively ? отбрасывать или выбирать первый. Как с geometry?
        static Component_MeshInSpace MergeMeshInSpaces(Component_MeshInSpace[] meshInSpaces, DocumentInstance document, UndoMultiAction undo)
        {
            if (meshInSpaces.Length < 2)
            {
                return(null);
            }

            var newTransform       = meshInSpaces[0].Transform.Value;
            var newMatrixInverse   = newTransform.ToMatrix4().GetInverse();
            var newRotationInverse = newTransform.Rotation.GetInverse();

            Component_Mesh.StructureClass newStructure = null;
            var newGeometries = new List <Component_MeshGeometry>();

            for (int i = 0; i < meshInSpaces.Length; i++)
            {
                var m = meshInSpaces[i].Mesh.Value;
                if (m == null)
                {
                    continue;
                }
                var oldTransform    = meshInSpaces[i].Transform.Value;
                var transformMatrix = newMatrixInverse * oldTransform.ToMatrix4();
                var rotation        = newRotationInverse * oldTransform.Rotation;

                var geometries = m.GetComponents <Component_MeshGeometry>();
                newStructure = Component_Mesh.StructureClass.Concat(newStructure, m.ExtractStructure().Structure, newGeometries.Count);
                foreach (var g in geometries)
                {
                    if (g is Component_MeshGeometry_Procedural meshGeometryProcedural)
                    {
                        VertexElement[]               vertexStructure = null;
                        byte[]                        vertices        = null;
                        int[]                         indices         = null;
                        Component_Material            material        = null;
                        Component_Mesh.StructureClass structure       = null;
                        meshGeometryProcedural.GetProceduralGeneratedData(ref vertexStructure, ref vertices, ref indices, ref material, ref structure);

                        var newMeshGeometry = new Component_MeshGeometry();
                        newMeshGeometry.Name            = meshGeometryProcedural.Name;
                        newMeshGeometry.VertexStructure = vertexStructure;
                        newMeshGeometry.Vertices        = vertices;
                        newMeshGeometry.Indices         = indices;

                        newMeshGeometry.Material = meshGeometryProcedural.Material;
                        //newMeshGeometry.Material = material;

                        TransformVertices(newMeshGeometry.Vertices.Value, new MeshData.MeshGeometryFormat(newMeshGeometry.VertexStructure), transformMatrix, rotation);
                        newGeometries.Add(newMeshGeometry);
                    }
                    else
                    {
                        //??? Проверять CloneSupport?
                        var newMeshGeometry = (Component_MeshGeometry)g.Clone();
                        if (newMeshGeometry.Vertices.Value != null)
                        {
                            newMeshGeometry.Vertices = (byte[])newMeshGeometry.Vertices.Value.Clone();
                            TransformVertices(newMeshGeometry.Vertices.Value, new MeshData.MeshGeometryFormat(newMeshGeometry.VertexStructure), transformMatrix, rotation);
                        }
                        newGeometries.Add(newMeshGeometry);
                    }
                }
            }

            //changes

            var parent = meshInSpaces[0].Parent;

            undo.AddAction(new UndoActionComponentCreateDelete(document, meshInSpaces, create: false));
            Component_MeshInSpace newMeshInSpace = parent.CreateComponent <Component_MeshInSpace>();
            bool wasEnabled = newMeshInSpace.Enabled;

            try
            {
                newMeshInSpace.Enabled   = false;
                newMeshInSpace.Name      = CommonFunctions.GetUniqueFriendlyName(newMeshInSpace);
                newMeshInSpace.Transform = newTransform;

                var newMesh = newMeshInSpace.CreateComponent <Component_Mesh>();
                newMesh.Name        = CommonFunctions.GetUniqueFriendlyName(newMesh);
                newMesh.Structure   = newStructure;
                newMeshInSpace.Mesh = ReferenceUtility.MakeReference <Component_Mesh>(null, ReferenceUtility.CalculateRootReference(newMesh));

                foreach (var g in newGeometries)
                {
                    newMesh.AddComponent(g);
                    CommonFunctions.EnsureNameIsUnique(g);
                }
            }
            finally
            {
                newMeshInSpace.Enabled = wasEnabled;
            }

            undo.AddAction(new UndoActionComponentCreateDelete(document, new[] { newMeshInSpace }, create: true));
            return(newMeshInSpace);
        }
Esempio n. 11
0
        private void ParentMeshInSpace_GetRenderSceneDataAddToFrameData(Component_MeshInSpace sender, ViewportRenderingContext context, GetRenderSceneDataMode mode, ref Component_RenderingPipeline.RenderSceneData.MeshItem item)
        {
            if (!CalculateOnCPU)
            {
                Component_Skeleton skeleton = ReplaceSkeleton;
                if (skeleton == null)
                {
                    skeleton = ParentMeshInSpace?.Mesh.Value?.Skeleton;
                }

                if (skeleton != null)
                {
                    var animation = PlayAnimation.Value;
                    if (animation != null)
                    {
                        UpdateAnimationTime();

                        //settings.animationStates = new AnimationStateItem[ 1 ];
                        //settings.animationStates[ 0 ] = new AnimationStateItem( animation, currentLocalTime, 1 );

                        var skeletonAnimation = animation as Component_SkeletonAnimation;
                        var track             = skeletonAnimation?.Track.Value;

                        if (track != null || CalculateBoneTransforms != null)
                        {
                            Update(skeleton, track, currentAnimationTime);

                            if (transformMatrixRelativeToSkin != null && transformMatrixRelativeToSkin.Length != 0)
                            {
                                item.AnimationData = new Component_RenderingPipeline.RenderSceneData.MeshItem.AnimationDataClass();

                                bool dualQuaternion = false;                                // GetSkinningMode( skeleton ) == Component_Skeleton.SkinningModeEnum.DualQuaternion;
                                if (dualQuaternion)
                                {
                                    item.AnimationData.Mode = 2;
                                }
                                else
                                {
                                    item.AnimationData.Mode = 1;
                                }

                                //create dynamic texture
                                var size         = new Vector2I(4, MathEx.NextPowerOfTwo(transformMatrixRelativeToSkin.Length));
                                var bonesTexture = context.DynamicTexture_Alloc(ViewportRenderingContext.DynamicTextureType.DynamicTexture, Component_Image.TypeEnum._2D, size, PixelFormat.Float32RGBA, 0, false);

                                //try get array from texture to minimize memory allocations
                                var surfaces = bonesTexture.Result.GetData();
                                if (surfaces == null)
                                {
                                    surfaces = new GpuTexture.SurfaceData[] { new GpuTexture.SurfaceData(0, 0, new byte[size.X * size.Y * 16]) }
                                }
                                ;
                                var data = surfaces[0].data;

                                //copy data to the texture
                                unsafe
                                {
                                    fixed(byte *pData2 = data)
                                    {
                                        Matrix4F *pData = (Matrix4F *)pData2;

                                        for (int n = 0; n < transformMatrixRelativeToSkin.Length; n++)
                                        {
                                            pData[n] = transformMatrixRelativeToSkin[n];
                                        }
                                    }
                                }
                                bonesTexture.Result.SetData(new GpuTexture.SurfaceData[] { new GpuTexture.SurfaceData(0, 0, data) });

                                item.AnimationData.BonesTexture = bonesTexture;
                            }
                        }
                    }
                }
            }
        }

        void RenderSkeleton(Viewport viewport)
        {
            // ParentMeshInSpace.Transform is automaticaly applyed to ParentMeshInSpace.Mesh, skeleton must be transformed manually
            var transformMatrix = ParentMeshInSpace?.Transform.Value?.ToMatrix4() ?? Matrix4.Identity;

            var skeletonArrows = GetCurrentAnimatedSkeletonArrows();

            if (skeletonArrows != null)
            {
                var color = new ColorValue(0, 0.5, 1, 0.7);                   //ToDo : Вынести в другое место.
                viewport.Simple3DRenderer.SetColor(color, color * ProjectSettings.Get.HiddenByOtherObjectsColorMultiplier);

                foreach (var arrow in skeletonArrows)
                {
                    viewport.Simple3DRenderer.AddArrow(transformMatrix * arrow.Start, transformMatrix * arrow.End);
                }
            }
        }

        bool CheckNeedModifiableMesh()
        {
            if (CalculateOnCPU)
            {
                if (ReplaceSkeleton.ReferenceSpecified)
                {
                    return(true);
                }
                var mesh = ParentMeshInSpace?.Mesh.Value;
                if (mesh != null && mesh.Skeleton.ReferenceSpecified)
                {
                    return(true);
                }

                if (PlayAnimation.ReferenceSpecified)
                {
                    return(true);
                }
            }

            return(false);
        }

        void UpdateModifiableMesh(ViewportRenderingContext context)
        {
            var originalMesh   = ParentMeshInSpace.Mesh.Value;
            var modifiableMesh = ParentMeshInSpace.ModifiableMesh;

            Component_Skeleton skeleton = ReplaceSkeleton;

            if (skeleton == null)
            {
                skeleton = originalMesh.Skeleton;
            }
            if (skeleton != null)
            {
                //!!!!сериализовывать

                var animation = PlayAnimation.Value;
                if (animation != null)
                {
                    UpdateAnimationTime();

                    //settings.animationStates = new AnimationStateItem[ 1 ];
                    //settings.animationStates[ 0 ] = new AnimationStateItem( animation, currentLocalTime, 1 );

                    var skeletonAnimation = animation as Component_SkeletonAnimation;
                    var track             = skeletonAnimation?.Track.Value;

                    if (track != null || CalculateBoneTransforms != null)
                    {
                        Update(skeleton, track, currentAnimationTime);
                        CalculateCPU(skeleton, originalMesh, modifiableMesh);
                    }
                }

                if (needResetToOriginalMesh)
                {
                    needResetToOriginalMesh = false;
                    if (CalculateOnCPU)
                    {
                        ResetToOriginalMesh(originalMesh, modifiableMesh);
                    }
                }
            }
        }

        /////////////////////////////////////////

        void ResetTime(bool needResetToOriginalMesh)
        {
            if (needResetToOriginalMesh)
            {
                this.needResetToOriginalMesh = true;
            }
            currentEngineTime    = EngineApp.EngineTime;
            currentAnimationTime = (PlayAnimation.Value as Component_SkeletonAnimation)?.TrackStartTime ?? 0;
        }

        void UpdateAnimationTime()
        {
            double t         = EngineApp.EngineTime;
            double increment = t - currentEngineTime;

            currentEngineTime     = t;
            currentAnimationTime += increment * Speed;

            var animation = PlayAnimation.Value as Component_SkeletonAnimation;

            if (animation != null)
            {
                double animationStartTime = animation.TrackStartTime;
                double animationLength    = animation.Length;
                if (animationLength > 0)
                {
                    if (AutoRewind)
                    {
                        while (currentAnimationTime > animationStartTime + animationLength)
                        {
                            currentAnimationTime -= animationLength;
                        }
                        while (currentAnimationTime < animationStartTime)
                        {
                            currentAnimationTime += animationLength;
                        }
                    }
                    else
                    {
                        MathEx.Clamp(ref currentAnimationTime, animationStartTime, animationStartTime + animationLength);
                    }
                }
                else
                {
                    currentAnimationTime = animationStartTime;
                }
            }
            else
            {
                currentAnimationTime = 0;
            }
        }