#if !UNITY_2019_1_OR_NEWER
#define CINEMACHINE_UGUI
#endif
using UnityEngine;
#if CINEMACHINE_UGUI
using System.Collections.Generic;
namespace Cinemachine
{
///
/// An add-on module for Cinemachine Virtual Camera that places an image in screen space
/// over the camera's output.
///
[SaveDuringPlay]
[DocumentationSorting(DocumentationSortingAttribute.Level.UserRef)]
[AddComponentMenu("")] // Hide in menu
[ExecuteAlways]
[DisallowMultipleComponent]
[HelpURL(Documentation.BaseURL + "manual/CinemachineStoryboard.html")]
public class CinemachineStoryboard : CinemachineExtension
{
///
/// If checked, all storyboards are globally muted
///
[Tooltip("If checked, all storyboards are globally muted")]
public static bool s_StoryboardGlobalMute;
///
/// If checked, the specified image will be displayed as an overlay over the virtual camera's output
///
[Tooltip("If checked, the specified image will be displayed as an overlay over the virtual camera's output")]
public bool m_ShowImage = true;
///
/// The image to display
///
[Tooltip("The image to display")]
public Texture m_Image;
/// How to fit the image in the frame, in the event that the aspect ratios don't match
public enum FillStrategy
{
/// Image will be as large as possible on the screen, without being cropped
BestFit,
/// Image will be cropped if necessary so that the screen is entirely filled
CropImageToFit,
/// Image will be stretched to cover any aspect mismatch with the screen
StretchToFit
};
///
/// How to handle differences between image aspect and screen aspect
///
[Tooltip("How to handle differences between image aspect and screen aspect")]
public FillStrategy m_Aspect = FillStrategy.BestFit;
///
/// The opacity of the image. 0 is transparent, 1 is opaque
///
[Tooltip("The opacity of the image. 0 is transparent, 1 is opaque")]
[Range(0, 1)]
public float m_Alpha = 1;
///
/// The screen-space position at which to display the image. Zero is center
///
[Tooltip("The screen-space position at which to display the image. Zero is center")]
public Vector2 m_Center = Vector2.zero;
///
/// The screen-space rotation to apply to the image
///
[Tooltip("The screen-space rotation to apply to the image")]
public Vector3 m_Rotation = Vector3.zero;
///
/// The screen-space scaling to apply to the image
///
[Tooltip("The screen-space scaling to apply to the image")]
public Vector2 m_Scale = Vector3.one;
///
/// If checked, X and Y scale are synchronized
///
[Tooltip("If checked, X and Y scale are synchronized")]
public bool m_SyncScale = true;
///
/// If checked, Camera transform will not be controlled by this virtual camera
///
[Tooltip("If checked, Camera transform will not be controlled by this virtual camera")]
public bool m_MuteCamera;
///
/// Wipe the image on and off horizontally
///
[Range(-1, 1)]
[Tooltip("Wipe the image on and off horizontally")]
public float m_SplitView = 0f;
class CanvasInfo
{
public GameObject mCanvas;
public CinemachineBrain mCanvasParent;
public RectTransform mViewport; // for mViewport clipping
public UnityEngine.UI.RawImage mRawImage;
}
List mCanvasInfo = new List();
/// Callback to display the image
/// The virtual camera being processed
/// The current pipeline stage
/// The current virtual camera state
/// The current applicable deltaTime
protected override void PostPipelineStageCallback(
CinemachineVirtualCameraBase vcam,
CinemachineCore.Stage stage, ref CameraState state, float deltaTime)
{
// Apply to this vcam only, not the children
if (vcam != VirtualCamera || stage != CinemachineCore.Stage.Finalize)
return;
if (m_ShowImage)
state.AddCustomBlendable(new CameraState.CustomBlendable(this, 1));
if (m_MuteCamera)
state.BlendHint |= CameraState.BlendHintValue.NoTransform | CameraState.BlendHintValue.NoLens;
}
/// Connect to virtual camera. Adds/removes listener
/// True if connecting, false if disconnecting
protected override void ConnectToVcam(bool connect)
{
base.ConnectToVcam(connect);
CinemachineCore.CameraUpdatedEvent.RemoveListener(CameraUpdatedCallback);
if (connect)
CinemachineCore.CameraUpdatedEvent.AddListener(CameraUpdatedCallback);
else
DestroyCanvas();
}
string CanvasName { get { return "_CM_canvas" + gameObject.GetInstanceID().ToString(); } }
void CameraUpdatedCallback(CinemachineBrain brain)
{
bool showIt = enabled && m_ShowImage && CinemachineCore.Instance.IsLive(VirtualCamera);
int layer = 1 << gameObject.layer;
if (brain.OutputCamera == null || (brain.OutputCamera.cullingMask & layer) == 0)
showIt = false;
if (s_StoryboardGlobalMute)
showIt = false;
CanvasInfo ci = LocateMyCanvas(brain, showIt);
if (ci != null && ci.mCanvas != null)
ci.mCanvas.SetActive(showIt);
}
CanvasInfo LocateMyCanvas(CinemachineBrain parent, bool createIfNotFound)
{
CanvasInfo ci = null;
for (int i = 0; ci == null && i < mCanvasInfo.Count; ++i)
if (mCanvasInfo[i].mCanvasParent == parent)
ci = mCanvasInfo[i];
if (createIfNotFound)
{
if (ci == null)
{
ci = new CanvasInfo() { mCanvasParent = parent };
int numChildren = parent.transform.childCount;
for (int i = 0; ci.mCanvas == null && i < numChildren; ++i)
{
RectTransform child = parent.transform.GetChild(i) as RectTransform;
if (child != null && child.name == CanvasName)
{
ci.mCanvas = child.gameObject;
ci.mViewport = ci.mCanvas.GetComponentsInChildren()[1]; // 0 is mCanvas
ci.mRawImage = ci.mCanvas.GetComponentInChildren();
}
}
mCanvasInfo.Add(ci);
}
if (ci.mCanvas == null || ci.mViewport == null || ci.mRawImage == null)
CreateCanvas(ci);
}
return ci;
}
void CreateCanvas(CanvasInfo ci)
{
ci.mCanvas = new GameObject(CanvasName, typeof(RectTransform));
ci.mCanvas.layer = gameObject.layer;
ci.mCanvas.hideFlags = HideFlags.HideAndDontSave;
ci.mCanvas.transform.SetParent(ci.mCanvasParent.transform);
#if UNITY_EDITOR
// Workaround for Unity bug case Case 1004117
CanvasesAndTheirOwners.AddCanvas(ci.mCanvas, this);
#endif
var c = ci.mCanvas.AddComponent