| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581 | /** * 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.Framework;using System;using UnityEngine;#if UNITY_2019_3_OR_NEWERusing UnityEngine.LowLevel;using UnityEngine.PlayerLoop;#elif UNITY_2018_1_OR_NEWERusing UnityEngine.Experimental.LowLevel;using UnityEngine.Experimental.PlayerLoop;#endifnamespace Live2D.Cubism.Core{    /// <summary>    /// Runtime Cubism model.    /// </summary>    [ExecuteInEditMode, CubismDontMoveOnReimport]    public sealed class CubismModel : MonoBehaviour    {        #region Delegates        /// <summary>        /// Handler for <see cref="CubismDynamicDrawableData"/>.        /// </summary>        /// <param name="sender">Model the dymanic data applies to.</param>        /// <param name="data">New data.</param>        public delegate void DynamicDrawableDataHandler(CubismModel sender, CubismDynamicDrawableData[] data);        #endregion        #region Events        /// <summary>        /// Event triggered if new <see cref="CubismDynamicDrawableData"/> is available for instance.        /// </summary>        public event DynamicDrawableDataHandler OnDynamicDrawableData;        #endregion        #region Factory Methods        /// <summary>        /// Instantiates a <see cref="CubismMoc"/>.        /// </summary>        /// <param name="moc">Cubism moc to instantiate.</param>        /// <returns>Instance.</returns>        public static CubismModel InstantiateFrom(CubismMoc moc)        {            // Return if argument is invalid.            if (moc == null)            {                return null;            }            // Create model.            var model = new GameObject(moc.name)                .AddComponent<CubismModel>();            // Initialize it by resetting it.            model.Reset(moc);            return model;        }        #endregion        /// <summary>        /// Resets a <see cref="CubismMoc"/> reference in <see cref="CubismModel"/>.        /// </summary>        /// <param name="model">Target Cubism model.</param>        /// <param name="moc">Cubism moc to reset.</param>        public static void ResetMocReference(CubismModel model, CubismMoc moc)        {            model.Moc = moc;        }        /// <summary>        /// <see cref="Moc"/> backing field.        /// </summary>        [SerializeField, HideInInspector]        private CubismMoc _moc;        /// <summary>        /// Moc the instance was instantiated from.        /// </summary>        public CubismMoc Moc        {            get { return _moc; }            private set { _moc = value; }        }        /// <summary>        /// TaskableModel for unmanaged backend.        /// </summary>        private CubismTaskableModel TaskableModel { get; set; }        /// <summary>        /// <see cref="Parameters"/> backing field.        /// </summary>        [NonSerialized]        private CubismParameter[] _parameters;        /// <summary>        /// Drawables of model.        /// </summary>        public CubismParameter[] Parameters        {            get            {                if (_parameters == null)                {                    Revive();                }                return _parameters;            }            private set { _parameters = value; }        }        /// <summary>        /// <see cref="Parts"/> backing field.        /// </summary>        [NonSerialized]        private CubismPart[] _parts;        /// <summary>        /// Drawables of model.        /// </summary>        public CubismPart[] Parts        {            get            {                if (_parts == null)                {                    Revive();                }                return _parts;            }            private set { _parts = value; }        }        /// <summary>        /// <see cref="Drawables"/> backing field.        /// </summary>        [NonSerialized]        private CubismDrawable[] _drawables;        /// <summary>        /// Drawables of model.        /// </summary>        public CubismDrawable[] Drawables        {            get            {                if (_drawables == null)                {                    Revive();                }                return _drawables;            }            private set { _drawables = value; }        }        /// <summary>        /// <see cref="CanvasInformation"/> backing field.        /// </summary>        [NonSerialized]        private CubismCanvasInformation _canvasInformation;        /// <summary>        /// Canvas information of model.        /// </summary>        public CubismCanvasInformation CanvasInformation        {            get            {                if (_canvasInformation == null)                {                    Revive();                }                return _canvasInformation;            }            private set { _canvasInformation = value; }        }        /// <summary>        /// Parameter store cache.        /// </summary>        CubismParameterStore _parameterStore;        /// <summary>        /// True if instance is revived.        /// </summary>        public bool IsRevived        {            get { return TaskableModel != null; }        }        /// <summary>        /// True if instance can revive.        /// </summary>        private bool CanRevive        {            get { return Moc != null; }        }#if UNITY_2018_1_OR_NEWER        /// <summary>        /// Model update functions for player loop.        /// </summary>        [NonSerialized]        private static Action _modelUpdateFunctions;        private bool WasAttachedModelUpdateFunction { get; set; }#endif        /// <summary>        /// True on the frame the instance was enabled.        /// </summary>        private bool WasJustEnabled { get; set; }        /// <summary>        /// Frame number last update was done.        /// </summary>        private int LastTick { get; set; }        /// <summary>        /// Revives instance.        /// </summary>        private void Revive()        {            // Return if already revive.            if (IsRevived)            {                return;            }            // Return if revive isn't possible.            if (!CanRevive)            {                return;            }            // Revive unmanaged model.            TaskableModel = new CubismTaskableModel(Moc);            // Revive proxies.            Parameters = GetComponentsInChildren<CubismParameter>();            Parts = GetComponentsInChildren<CubismPart>();            Drawables = GetComponentsInChildren<CubismDrawable>();            Parameters.Revive(TaskableModel.UnmanagedModel);            Parts.Revive(TaskableModel.UnmanagedModel);            Drawables.Revive(TaskableModel.UnmanagedModel);            CanvasInformation = new CubismCanvasInformation(TaskableModel.UnmanagedModel);            _parameterStore = GetComponent<CubismParameterStore>();        }        /// <summary>        /// Initializes instance for first use.        /// </summary>        /// <param name="moc">Moc to instantiate from.</param>        private void Reset(CubismMoc moc)        {            Moc = moc;            name = moc.name;            TaskableModel = new CubismTaskableModel(moc);            // Create and initialize proxies.            var parameters = CubismParameter.CreateParameters(TaskableModel.UnmanagedModel);            var parts = CubismPart.CreateParts(TaskableModel.UnmanagedModel);            var drawables = CubismDrawable.CreateDrawables(TaskableModel.UnmanagedModel);            parameters.transform.SetParent(transform);            parts.transform.SetParent(transform);            drawables.transform.SetParent(transform);            Parameters = parameters.GetComponentsInChildren<CubismParameter>();            Parts = parts.GetComponentsInChildren<CubismPart>();            Drawables = drawables.GetComponentsInChildren<CubismDrawable>();            CanvasInformation = new CubismCanvasInformation(TaskableModel.UnmanagedModel);        }        /// <summary>        /// Forces update.        /// </summary>        public void ForceUpdateNow()        {            WasJustEnabled = true;            LastTick = -1;            Revive();#if UNITY_2018_1_OR_NEWER            OnModelUpdate();#else            OnRenderObject();#endif        }#if UNITY_2018_1_OR_NEWER        /// <summary>        /// Calls model update functions for player loop.        /// </summary>        private static void OnModelsUpdate()        {            if (_modelUpdateFunctions != null)            {                _modelUpdateFunctions.Invoke();            }        }        /// <summary>        /// Register the model update function into the player loop.        /// </summary>        [RuntimeInitializeOnLoadMethod]        private static void RegisterCallbackFunction()        {            // Prepare the function for using player loop.            var myPlayerLoopSystem = new PlayerLoopSystem()            {                type = typeof(CubismModel),     // Identifier for Profiler Hierarchy view.                updateDelegate = OnModelsUpdate    // Register the function.            };            // Get the default player loop.            var playerLoopSystem =#if UNITY_2019_3_OR_NEWER                PlayerLoop.GetCurrentPlayerLoop();#else                PlayerLoop.GetDefaultPlayerLoop();#endif            var playerLoopIndex = -1;            for (var i = 0; i < playerLoopSystem.subSystemList.Length; i++)            {                if (playerLoopSystem.subSystemList[i].type != typeof(PreLateUpdate))                {                    continue;                }                playerLoopIndex = i;                break;            }            if (playerLoopIndex < 0)            {                Debug.LogError("CubismModel : Failed to add processing to PlayerLoop.");                return;            }            // Get the "PreLateUpdate" system.            var playerLoopSubSystem = playerLoopSystem.subSystemList[playerLoopIndex];            var subSystemList = playerLoopSubSystem.subSystemList;            // Register the model update function after "PreLateUpdate" system.            Array.Resize(ref subSystemList, subSystemList.Length + 1);            subSystemList[subSystemList.Length - 1] = myPlayerLoopSystem;            // Restore the "PreLateUpdate" sytem.            playerLoopSubSystem.subSystemList = subSystemList;            playerLoopSystem.subSystemList[playerLoopIndex] = playerLoopSubSystem;            PlayerLoop.SetPlayerLoop(playerLoopSystem);        }#endif        #region Unity Event Handling        /// <summary>        /// Called by Unity. Triggers <see langword="this"/> to update.        /// </summary>        private void Update()        {#if UNITY_2018_1_OR_NEWER            if (!WasAttachedModelUpdateFunction)            {                _modelUpdateFunctions += OnModelUpdate;                WasAttachedModelUpdateFunction = true;            }#endif            // Return on first frame enabled.            if (WasJustEnabled)            {                return;            }            // Return unless revived.            if (!IsRevived)            {                return;            }            // Return if backend is ticking.            if (!TaskableModel.DidExecute)            {                return;            }            // Sync parameters back.            TaskableModel.TryReadParameters(Parameters);            // restore last frame parameters value and parts opacity.            if (_parameterStore != null)            {                _parameterStore.RestoreParameters();            }            // Trigger event.            if (OnDynamicDrawableData == null)            {                return;            }            OnDynamicDrawableData(this, TaskableModel.DynamicDrawableData);        }        /// <summary>        /// Called by Unity. Blockingly updates <see langword="this"/> on first frame enabled; otherwise tries async update.        /// </summary>        private void OnRenderObject()        {#if !UNITY_2018_1_OR_NEWER            OnModelUpdate();#endif        }        /// <summary>        /// Update model states.        /// </summary>        private void OnModelUpdate()        {            // Return unless revived.            if (!IsRevived)            {                return;            }            // Return if already ticked this frame.            if (LastTick == Time.frameCount && Application.isPlaying)            {                return;            }            LastTick = Time.frameCount;            // Try to sync parameters and parts (without caring whether task is executing or not).            TaskableModel.TryWriteParametersAndParts(Parameters, Parts);            // Return if task is executing.            if (TaskableModel.IsExecuting)            {                return;            }            // Force blocking update on first frame enabled.            if (WasJustEnabled)            {                // Force sync update.                TaskableModel.UpdateNow();                // Unset condition.                WasJustEnabled = false;                // Fetch results by calling own 'Update()'.                Update();                return;            }            // Enqueue update task.            TaskableModel.Update();        }        /// <summary>        /// Called by Unity. Revives instance.        /// </summary>        private void OnEnable()        {            WasJustEnabled = true;            Revive();        }        private void OnDisable()        {#if UNITY_2018_1_OR_NEWER            if (WasAttachedModelUpdateFunction)            {                _modelUpdateFunctions -= OnModelUpdate;                WasAttachedModelUpdateFunction = false;            }#endif        }        /// <summary>        /// Called by Unity. Releases unmanaged memory.        /// </summary>        private void OnDestroy()        {            if (!IsRevived)            {                return;            }            TaskableModel.ReleaseUnmanaged();            TaskableModel = null;        }        /// <summary>        /// Called by Unity. Triggers <see cref="OnEnable"/>.        /// </summary>        private void OnValidate()        {            OnEnable();        }        #endregion    }}
 |