123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- /**
- * 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 System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.Rendering;
- namespace Live2D.Cubism.Rendering.Masking
- {
- /// <summary>
- /// Texture for rendering masks.
- /// </summary>
- [CreateAssetMenu(menuName = "Live2D Cubism/Mask Texture")]
- public sealed class CubismMaskTexture : ScriptableObject, ICubismMaskCommandSource
- {
- #region Conversion
- /// <summary>
- /// Converts a <see cref="CubismMaskTexture"/> to a <see cref="Texture"/>.
- /// </summary>
- /// <param name="value">Value to convert.</param>
- public static implicit operator Texture(CubismMaskTexture value)
- {
- return value.RenderTexture;
- }
- #endregion
- /// <summary>
- /// The global mask texture.
- /// </summary>
- public static CubismMaskTexture GlobalMaskTexture
- {
- get { return Resources.Load<CubismMaskTexture>("Live2D/Cubism/GlobalMaskTexture"); }
- }
- /// <summary>
- /// <see cref="Size"/> backing field.
- /// </summary>
- [SerializeField, HideInInspector]
- private int _size = 1024;
- /// <summary>
- /// Texture size in pixels.
- /// </summary>
- public int Size
- {
- get { return _size; }
- set
- {
- // Return early if same value given.
- if (value == _size)
- {
- return;
- }
- // Fail silently if not power-of-two.
- if (!value.IsPowerOfTwo())
- {
- return;
- }
- // Apply changes.
- _size = value;
- RefreshRenderTexture();
- }
- }
- /// <summary>
- /// Channel count.
- /// </summary>
- public int Channels
- {
- get { return 4; }
- }
- /// <summary>
- /// <see cref="Subdivisions"/> backing field.
- /// </summary>
- [SerializeField, HideInInspector]
- private int _subdivisions = 3;
- /// <summary>
- /// Subdivision level.
- /// </summary>
- public int Subdivisions
- {
- get { return _subdivisions; }
- set
- {
- if (value == _subdivisions)
- {
- return;
- }
- // Apply changes.
- _subdivisions = value;
- RefreshRenderTexture();
- }
- }
- /// <summary>
- /// Tile pool 'allocator'.
- /// </summary>
- private CubismMaskTilePool TilePool { get; set; }
- /// <summary>
- /// <see cref="RenderTexture"/> backing field.
- /// </summary>
- private RenderTexture _renderTexture;
- /// <summary>
- /// <see cref="RenderTexture"/> to draw on.
- /// </summary>
- private RenderTexture RenderTexture
- {
- get
- {
- if (_renderTexture == null)
- {
- RefreshRenderTexture();
- }
- return _renderTexture;
- }
- set { _renderTexture = value; }
- }
- /// <summary>
- /// Sources.
- /// </summary>
- private List<SourcesItem> Sources { get; set; }
- /// <summary>
- /// True if instance is revived.
- /// </summary>
- private bool IsRevived
- {
- get { return TilePool != null; }
- }
- /// <summary>
- /// True if instance contains any sources.
- /// </summary>
- private bool ContainsSources
- {
- get { return Sources != null && Sources.Count > 0; }
- }
- #region Interface For ICubismMaskSources
- /// <summary>
- /// Add source of masks for drawing.
- /// </summary>
- public void AddSource(ICubismMaskTextureCommandSource source)
- {
- // Make sure instance is valid.
- TryRevive();
- // Initialize container if necessary.
- if (Sources == null)
- {
- Sources = new List<SourcesItem>();
- }
- // Return early if source already exists.
- else if (Sources.FindIndex(i => i.Source == source) != -1)
- {
- return;
- }
- // Register source.
- var item = new SourcesItem
- {
- Source = source,
- Tiles = TilePool.AcquireTiles(source.GetNecessaryTileCount())
- };
- Sources.Add(item);
- // Apply tiles to source.
- source.SetTiles(item.Tiles);
- }
- /// <summary>
- /// Remove source of masks
- /// </summary>
- public void RemoveSource(ICubismMaskTextureCommandSource source)
- {
- // Return early if empty.
- if (!ContainsSources)
- {
- return;
- }
- var itemIndex = Sources.FindIndex(i => i.Source == source);
- // Return if source is invalid.
- if (itemIndex == -1)
- {
- return;
- }
- // Return tiles and deregister source.
- TilePool.ReturnTiles(Sources[itemIndex].Tiles);
- Sources.RemoveAt(itemIndex);
- }
- #endregion
- private void TryRevive()
- {
- // Return early if already revived.
- if (IsRevived)
- {
- return;
- }
- RefreshRenderTexture();
- }
- private void ReinitializeSources()
- {
- // Reallocate tiles if sources exist.
- if (ContainsSources)
- {
- for (var i = 0; i < Sources.Count; ++i)
- {
- var source = Sources[i];
- source.Tiles = TilePool.AcquireTiles(source.Source.GetNecessaryTileCount());
- source.Source.SetTiles(source.Tiles);
- Sources[i] = source;
- }
- }
- }
- private void RefreshRenderTexture()
- {
- // Recreate render texture.
- RenderTexture = new RenderTexture(Size, Size, 0, RenderTextureFormat.ARGB32);
- // Recreate allocator.
- TilePool = new CubismMaskTilePool(Subdivisions, Channels);
- // Reinitialize sources.
- ReinitializeSources();
- }
- #region Unity Event Handling
- /// <summary>
- /// Initializes instance.
- /// </summary>
- // ReSharper disable once UnusedMember.Local
- private void OnEnable()
- {
- CubismMaskCommandBuffer.AddSource(this);
- }
- /// <summary>
- /// Finalizes instance.
- /// </summary>
- // ReSharper disable once UnusedMember.Local
- private void OnDestroy()
- {
- CubismMaskCommandBuffer.RemoveSource(this);
- }
- #endregion
- #region ICubismMaskCommandSource
- /// <summary>
- /// Called to enqueue source.
- /// </summary>
- /// <param name="buffer">Buffer to enqueue in.</param>
- void ICubismMaskCommandSource.AddToCommandBuffer(CommandBuffer buffer)
- {
- // Return early if empty.
- if (!ContainsSources)
- {
- return;
- }
- // Enqueue render target.
- buffer.SetRenderTarget(RenderTexture);
- buffer.ClearRenderTarget(false, true, Color.clear);
- // Enqueue sources.
- for (var i = 0; i < Sources.Count; ++i)
- {
- Sources[i].Source.AddToCommandBuffer(buffer);
- }
- }
- #endregion
- #region Source Item
- /// <summary>
- /// Source of masks and its tiles
- /// </summary>
- private struct SourcesItem
- {
- /// <summary>
- /// SourcesItem instance.
- /// </summary>
- public ICubismMaskTextureCommandSource Source;
- /// <summary>
- /// Tiles assigned to the instance.
- /// </summary>
- public CubismMaskTile[] Tiles;
- }
- #endregion
- }
- }
|