| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 | /** * Copyright(c) Live2D Inc. All rights reserved. * * Use of this source code is governed by the Live2D Open Software license * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html. */using Live2D.Cubism.Core.Unmanaged;using System.Threading;namespace Live2D.Cubism.Core{    /// <summary>    /// 'Atomic' <see cref="CubismModel"/> update task.    /// </summary>    internal sealed class CubismTaskableModel : ICubismTask    {        #region Factory Methods        /// <summary>        /// Creates a <see cref="CubismTaskableModel"/> from a <see cref="CubismMoc"/>.        /// </summary>        /// <param name="moc">Moc source.</param>        /// <returns>Instance.</returns>        public static CubismTaskableModel CreateTaskableModel(CubismMoc moc)        {            return new CubismTaskableModel(moc);        }        #endregion        /// <summary>        /// Handle to unmanaged model.        /// </summary>        public CubismUnmanagedModel UnmanagedModel { get; private set; }        /// <summary>        /// <see cref="CubismMoc"/> the model was instantiated from.        /// </summary>        public CubismMoc Moc { get; private set; }        private CubismDynamicDrawableData[] _dynamicDrawableData;        /// <summary>        /// Buffer to write dynamic data to.        /// </summary>        public CubismDynamicDrawableData[] DynamicDrawableData        {            get            {                CubismDynamicDrawableData[] dynamicDrawableData = null;                if (Monitor.TryEnter(Lock))                {                    dynamicDrawableData = _dynamicDrawableData;                    Monitor.Exit(Lock);                }                return dynamicDrawableData;            }            private set            {                _dynamicDrawableData = value;            }        }        /// <summary>        /// True if task is currently executing.        /// </summary>        public bool IsExecuting        {            get            {                var isExecuting = false;                if (Monitor.TryEnter(Lock))                {                    isExecuting = (State == TaskState.Enqueued || State == TaskState.Executing);                    Monitor.Exit(Lock);                }                return isExecuting;            }        }        /// <summary>        /// True if did run to completion at least once.        /// </summary>        public bool DidExecute        {            get            {                var didExecute = false;                if (Monitor.TryEnter(Lock))                {                    didExecute = (State == TaskState.Executed);                    Monitor.Exit(Lock);                }                return didExecute;            }        }        /// <summary>        /// True if unmanaged model and moc should be released.        /// </summary>        private bool ShouldReleaseUnmanaged { get; set; }        #region Constructor        /// <summary>        /// Initializes instance.        /// </summary>        /// <param name="moc">Moc unmanaged model was instantiated from.</param>        public CubismTaskableModel(CubismMoc moc)        {            Moc = moc;            // Instantiate unmanaged model.            var unmanagedMoc = moc.AcquireUnmanagedMoc();            UnmanagedModel = CubismUnmanagedModel.FromMoc(unmanagedMoc);            Lock = new object();            State = TaskState.Idle;            DynamicDrawableData = CubismDynamicDrawableData.CreateData(UnmanagedModel);            ShouldReleaseUnmanaged = false;        }        #endregion        /// <summary>        /// Tries to read parameters into a buffer.        /// </summary>        /// <param name="parameters">Buffer to write to.</param>        /// <returns><see langword="true"/> on success; <see langword="false"/> otherwise.</returns>        public bool TryReadParameters(CubismParameter[] parameters)        {            var didRead = false;            if (Monitor.TryEnter(Lock))            {                try                {                    if (State == TaskState.Executed)                    {                        parameters.ReadFrom(UnmanagedModel);                        didRead = true;                    }                }                finally                {                    Monitor.Exit(Lock);                }            }            return didRead;        }        /// <summary>        /// Tries to write parameters to a buffer.        /// </summary>        /// <param name="parameters">Buffer to read from.</param>        /// <param name="parts">Buffer to read from.</param>        /// <returns><see langword="true"/> on success; <see langword="false"/> otherwise.</returns>        public bool TryWriteParametersAndParts(CubismParameter[] parameters, CubismPart[] parts)        {            var didWrite = false;            if (Monitor.TryEnter(Lock))            {                try                {                    if (State != TaskState.Executing)                    {                        parameters.WriteTo(UnmanagedModel);                        parts.WriteTo(UnmanagedModel);                        didWrite = true;                    }                }                finally                {                    Monitor.Exit(Lock);                }            }            return didWrite;        }        /// <summary>        /// Dispatches the task for (maybe async) execution.        /// </summary>        public void Update()        {            // Validate state.            lock (Lock)            {                if (State == TaskState.Enqueued || State == TaskState.Executing)                {                    return;                }                // Update state.                State = TaskState.Enqueued;            }            CubismTaskQueue.Enqueue(this);        }        /// <summary>        /// Forces the task to run now to completion.        /// </summary>        public bool UpdateNow()        {            // Validate state.            lock (Lock)            {                if (State == TaskState.Enqueued || State == TaskState.Executing)                {                    return false;                }                // Update state.                State = TaskState.Enqueued;            }            // Run execution directly.            Execute();            return true;        }        /// <summary>        /// Releases unmanaged resource.        /// </summary>        public void ReleaseUnmanaged()        {            ShouldReleaseUnmanaged = true;            // Return if task is ongoing.            lock (Lock)            {                if (State == TaskState.Enqueued || State == TaskState.Executing)                {                    return;                }            }            OnReleaseUnmanaged();            ShouldReleaseUnmanaged = false;        }        /// <summary>        /// Runs the task.        /// </summary>        private void Execute()        {            // Validate state.            lock (Lock)            {                State = TaskState.Executing;            }            // Update native backend.            UnmanagedModel.Update();            // Get results.            DynamicDrawableData.ReadFrom(UnmanagedModel);            // Update state.            lock (Lock)            {                State = TaskState.Executed;                // Release native if requested.                if (ShouldReleaseUnmanaged)                {                    OnReleaseUnmanaged();                }            }        }        /// <summary>        /// Actually releases native resource(s).        /// </summary>        private void OnReleaseUnmanaged()        {            UnmanagedModel.Release();            Moc.ReleaseUnmanagedMoc();            UnmanagedModel = null;        }        #region Implementation of ICubismTask        void ICubismTask.Execute()        {            Execute();        }        #endregion        #region Threading        /// <summary>        /// Task states.        /// </summary>        private enum TaskState        {            /// <summary>            /// Idle state.            /// </summary>            Idle,            /// <summary>            /// Waiting-for-execution state.            /// </summary>            Enqueued,            /// <summary>            /// Executing state.            /// </summary>            Executing,            /// <summary>            /// Executed state.            /// </summary>            Executed        }        /// <summary>        /// Lock.        /// </summary>        private object Lock { get; set; }        /// <summary>        /// Internal state.        /// </summary>        private TaskState State { get; set; }        #endregion    }}
 |