update
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
using Rive.EditorTools;
|
||||
using Rive.Utils;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Rive.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// The PointerInputMode determines whether the panel will receive pointer input events.
|
||||
/// </summary>
|
||||
public enum PointerInputMode
|
||||
{
|
||||
/// <summary>
|
||||
/// The panel will receive pointer input events.
|
||||
/// </summary>
|
||||
EnablePointerInput = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The panel will not receive pointer input events.
|
||||
/// </summary>
|
||||
DisablePointerInput = 1
|
||||
}
|
||||
|
||||
[DisallowMultipleComponent]
|
||||
public abstract class PanelRenderer : MonoBehaviour
|
||||
{
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[OnValueChanged(nameof(HandlePointerInputModeChanged))]
|
||||
#endif
|
||||
[Tooltip("Determines whether the panel will receive pointer input events from this renderer.")]
|
||||
[SerializeField] private PointerInputMode m_pointerInputMode = PointerInputMode.EnablePointerInput;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The RivePanel that this renderer is associated with.
|
||||
/// </summary>
|
||||
public abstract IRivePanel RivePanel { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The PointerInputMode determines whether the panel render will pass pointer input events to the RivePanel.
|
||||
/// </summary>
|
||||
public PointerInputMode PointerInputMode
|
||||
{
|
||||
get => m_pointerInputMode; set
|
||||
{
|
||||
if (m_pointerInputMode == value) { return; }
|
||||
m_pointerInputMode = value; HandlePointerInputModeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void SubscribeToPanelEvents()
|
||||
{
|
||||
if (RivePanel == null)
|
||||
{
|
||||
DebugLogger.Instance.LogWarning($"No {nameof(RivePanel)} component found for this {nameof(PanelRenderer)} - {gameObject.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
RivePanel.OnRenderingStateChanged += OnRenderingStateChanged;
|
||||
RivePanel.OnRenderTargetUpdated += HandleRenderTargetUpdated;
|
||||
}
|
||||
|
||||
protected void UnsubscribeFromPanelEvents()
|
||||
{
|
||||
if (RivePanel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
RivePanel.OnRenderingStateChanged -= OnRenderingStateChanged;
|
||||
RivePanel.OnRenderTargetUpdated -= HandleRenderTargetUpdated;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
|
||||
if (RivePanel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (RivePanel.IsRendering)
|
||||
{
|
||||
UpdateVisualTarget();
|
||||
}
|
||||
SubscribeToPanelEvents();
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
if (RivePanel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
UnsubscribeFromPanelEvents();
|
||||
}
|
||||
|
||||
protected void HandleRenderTargetUpdated()
|
||||
{
|
||||
UpdateVisualTarget();
|
||||
|
||||
}
|
||||
|
||||
private void OnRenderingStateChanged()
|
||||
{
|
||||
UpdateVisualTarget();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Use this method to reflect the Rive visual on the target where the Rive graphic is being displayed. This is called when the render target is updated or when the panel detects it might need to update the targets using the render texture.
|
||||
/// </summary>
|
||||
protected abstract void UpdateVisualTarget();
|
||||
|
||||
|
||||
protected virtual void HandlePointerInputModeChanged()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This method is called when the script is loaded or a value is changed in the inspector (Called in the editor only).
|
||||
/// </summary>
|
||||
protected virtual void OnValidate()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 86bfe1bae01fc421390c0d36814b3a74
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 350858
|
||||
packageName: Rive
|
||||
packageVersion: 0.4.2
|
||||
assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/PanelRenderer.cs
|
||||
uploadId: 896810
|
||||
@@ -0,0 +1,334 @@
|
||||
using Rive.EditorTools;
|
||||
using Rive.Utils;
|
||||
using Rive;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Rive.Components
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
[HelpURL(InspectorDocLinks.RiveCanvasRenderer)]
|
||||
#endif
|
||||
[AddComponentMenu("Rive/Rive Canvas Renderer")]
|
||||
[HideComponents(hideFlags: HideFlags.HideInInspector, typeof(CanvasRendererRawImage), typeof(CanvasPanelInputProvider))]
|
||||
[RequireComponent(typeof(CanvasRendererRawImage), typeof(IRivePanel))]
|
||||
public class RiveCanvasRenderer : PanelRenderer
|
||||
{
|
||||
[Tooltip("The RiveRawImage to display the Rive content.")]
|
||||
[HideInInspector]
|
||||
[SerializeField]
|
||||
private CanvasRendererRawImage m_displayImage;
|
||||
|
||||
// We hide the RivePanel field because we want to use the RivePanel on the GameObject that this component is attached to.
|
||||
[HideInInspector]
|
||||
[Tooltip("The RivePanel to display")]
|
||||
[SerializeField] private RivePanel m_initialRivePanel;
|
||||
|
||||
[Tooltip("A custom UI material to use when rendering the Rive graphic.")]
|
||||
[SerializeField] private Material m_customMaterial;
|
||||
|
||||
[Tooltip("Whether to match the canvas resolution to the RivePanel's resolution. \n\nThis is useful for keeping the Rive graphic crisp when using a Canvas Scaler. By default, the RivePanel resolution is defined by it's rect transform's width and height. Setting this to true will cause the RivePanel to be rendered at a higher resolution than the panel's rect transform's size if needed.\n\nThis feature is currently only supported when the RivePanel uses the SimpleRenderTargetStrategy, which is the default strategy used if none is provided.")]
|
||||
[SerializeField] private bool m_matchCanvasResolution = false;
|
||||
|
||||
|
||||
private IRivePanel m_rivePanel;
|
||||
|
||||
internal CanvasRendererRawImage DisplayImage => m_displayImage;
|
||||
|
||||
[HideInInspector]
|
||||
[SerializeField] private CanvasPanelInputProvider m_inputProvider;
|
||||
|
||||
public Canvas Canvas => DisplayImage == null ? null : DisplayImage.canvas;
|
||||
|
||||
public RectTransform RectTransform => DisplayImage == null ? null : DisplayImage.rectTransform;
|
||||
|
||||
public override IRivePanel RivePanel { get => m_rivePanel; internal set => m_rivePanel = value; }
|
||||
|
||||
/// <summary>
|
||||
/// The custom material to use when rendering the Rive graphic.
|
||||
/// </summary>
|
||||
public Material CustomMaterial
|
||||
{
|
||||
get => m_customMaterial;
|
||||
set
|
||||
{
|
||||
m_customMaterial = value;
|
||||
UpdateCustomMaterial();
|
||||
}
|
||||
}
|
||||
|
||||
public bool MatchCanvasResolution
|
||||
{
|
||||
get => m_matchCanvasResolution;
|
||||
set
|
||||
{
|
||||
if (m_matchCanvasResolution != value)
|
||||
{
|
||||
m_matchCanvasResolution = value;
|
||||
AttachCanvasProviders(RivePanel);
|
||||
|
||||
RivePanel rPanel = RivePanel as RivePanel;
|
||||
if (rPanel != null)
|
||||
{
|
||||
rPanel.SetDirty(); // Force a redraw to apply the new resolution.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
Setup();
|
||||
base.OnEnable();
|
||||
|
||||
|
||||
if (m_matchCanvasResolution) AttachCanvasProviders(RivePanel);
|
||||
|
||||
if (m_inputProvider != null && RivePanel != null)
|
||||
{
|
||||
RivePanel.RegisterInputProvider(m_inputProvider);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
|
||||
if (m_inputProvider != null && RivePanel != null)
|
||||
{
|
||||
RivePanel.UnregisterInputProvider(m_inputProvider);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supersampling multiplier for the RenderTexture only.
|
||||
/// </summary>
|
||||
private float m_renderScale = 1f;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Attach providers that the strategy can call to (1) size the RT and (2) pick draw scale.
|
||||
/// This keeps strategies/panels canvas-agnostic and lets other renderers (UITK, material)
|
||||
/// provide their own sizing rules or none at all.
|
||||
/// </summary>
|
||||
/// <param name="panel"></param>
|
||||
private void AttachCanvasProviders(IRivePanel panel)
|
||||
{
|
||||
var concretePanel = panel as RivePanel;
|
||||
if (concretePanel == null) return;
|
||||
|
||||
var strategy = concretePanel.RenderTargetStrategy as RenderTargetStrategy;
|
||||
if (strategy == null) return;
|
||||
|
||||
if (!m_matchCanvasResolution)
|
||||
{
|
||||
// Explicitly clear to legacy behavior
|
||||
strategy.ExternalPixelSizeProvider = null;
|
||||
strategy.ExternalDrawScaleProvider = null;
|
||||
return;
|
||||
}
|
||||
|
||||
strategy.ExternalPixelSizeProvider = ComputeCanvasPixelSize;
|
||||
strategy.ExternalDrawScaleProvider = ComputeCanvasDrawScale;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Computes the pixel size of the canvas. Determines the size of the render texture based on the canvas scale factor and the local scale of the widget container.
|
||||
/// We do this because the Canvas Scaler (especially when set to "Scale With Screen Size") changes how many pixels each UI unit occupies on screen. Allocating the RT at that pixel size keeps Rive crisp.
|
||||
/// </summary>
|
||||
/// <param name="p">The panel to compute the pixel size for.</param>
|
||||
/// <returns>The pixel size of the canvas.</returns>
|
||||
private Vector2Int ComputeCanvasPixelSize(IRivePanel p)
|
||||
{
|
||||
var rt = p.WidgetContainer;
|
||||
var canvas = DisplayImage != null ? DisplayImage.canvas : null;
|
||||
if (rt == null || canvas == null) return new Vector2Int(1, 1);
|
||||
|
||||
float canvasScale = canvas.scaleFactor;
|
||||
|
||||
// Include local UI scale so “manually scaled” panels (e.g. 1080×2340 at 0.3333) resolve to the same on-screen pixels
|
||||
float uiW = rt.rect.width * Mathf.Abs(rt.localScale.x);
|
||||
float uiH = rt.rect.height * Mathf.Abs(rt.localScale.y);
|
||||
|
||||
int w = Mathf.Max(1, Mathf.CeilToInt(uiW * canvasScale * m_renderScale));
|
||||
int h = Mathf.Max(1, Mathf.CeilToInt(uiH * canvasScale * m_renderScale));
|
||||
return new Vector2Int(w, h);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Computes the draw scale of the canvas. Used to ensure the graphics are drawn at the correct scale and position within the render texture.
|
||||
/// </summary>
|
||||
/// <param name="p">The panel to compute the draw scale for.</param>
|
||||
/// <returns>The draw scale of the canvas.</returns>
|
||||
private Vector2 ComputeCanvasDrawScale(IRivePanel p)
|
||||
{
|
||||
var rt = p.WidgetContainer;
|
||||
var canvas = DisplayImage != null ? DisplayImage.canvas : null;
|
||||
if (rt == null || canvas == null) return Vector2.one;
|
||||
|
||||
float canvasScale = canvas.scaleFactor;
|
||||
|
||||
float sx = canvasScale * Mathf.Abs(rt.localScale.x);
|
||||
float sy = canvasScale * Mathf.Abs(rt.localScale.y);
|
||||
return new Vector2(sx, sy);
|
||||
}
|
||||
|
||||
private void Setup()
|
||||
{
|
||||
if (m_rivePanel == null)
|
||||
{
|
||||
m_rivePanel = m_initialRivePanel;
|
||||
|
||||
}
|
||||
|
||||
if (m_rivePanel == null)
|
||||
{
|
||||
m_rivePanel = GetComponent<IRivePanel>();
|
||||
|
||||
}
|
||||
if (m_displayImage == null)
|
||||
{
|
||||
if (!TryGetComponent(out m_displayImage))
|
||||
{
|
||||
m_displayImage = gameObject.AddComponent<CanvasRendererRawImage>();
|
||||
}
|
||||
}
|
||||
|
||||
// We need to make sure the RivePanel's RawImage is a raycast target, otherwise we won't get any pointer input.
|
||||
if (!m_displayImage.raycastTarget)
|
||||
{
|
||||
m_displayImage.raycastTarget = true;
|
||||
|
||||
}
|
||||
|
||||
if (m_inputProvider == null && !TryGetComponent(out m_inputProvider))
|
||||
{
|
||||
m_inputProvider = gameObject.AddComponent<CanvasPanelInputProvider>();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Initialize the input mode, in case it was not set.
|
||||
HandlePointerInputModeChanged();
|
||||
|
||||
if (m_rivePanel == null)
|
||||
{
|
||||
DebugLogger.Instance.LogWarning($"No {nameof(RivePanel)} component found for this {nameof(RiveCanvasRenderer)} - {gameObject.name}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void LogInputErrorWarningsIfNeeded()
|
||||
{
|
||||
if (PointerInputMode == PointerInputMode.DisablePointerInput)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// If there's no event system in the scene, we log a warning.
|
||||
if (UnityEngine.EventSystems.EventSystem.current == null)
|
||||
{
|
||||
DebugLogger.Instance.LogWarning($"No EventSystem found in the scene. Please add an EventSystem to the scene to receive pointer input events. If you don't want to receive pointer input events, set the {nameof(PointerInputMode)} to {PointerInputMode.DisablePointerInput}.");
|
||||
}
|
||||
|
||||
// If there's no GraphicRaycaster in the scene, we log a warning.
|
||||
if (DisplayImage != null && !DisplayImage.canvas.TryGetComponent<UnityEngine.UI.GraphicRaycaster>(out _))
|
||||
{
|
||||
DebugLogger.Instance.LogWarning($"No GraphicRaycaster found in the scene. Please add a GraphicRaycaster to the scene to receive pointer input events. If you don't want to receive pointer input events, set the {nameof(PointerInputMode)} to {PointerInputMode.DisablePointerInput}.");
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
LogInputErrorWarningsIfNeeded();
|
||||
|
||||
UpdateCustomMaterial();
|
||||
|
||||
}
|
||||
|
||||
private void UpdateCustomMaterial()
|
||||
{
|
||||
if (DisplayImage == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Material materialToApply = m_customMaterial;
|
||||
|
||||
if (materialToApply == null && Application.isPlaying)
|
||||
{
|
||||
materialToApply = TextureHelper.GammaToLinearUIMaterial;
|
||||
}
|
||||
|
||||
DisplayImage.material = materialToApply;
|
||||
}
|
||||
|
||||
|
||||
protected override void UpdateVisualTarget()
|
||||
{
|
||||
if (RivePanel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var renderTexture = RivePanel.RenderTexture;
|
||||
if (renderTexture == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_displayImage.texture = renderTexture;
|
||||
|
||||
Vector2 offset = RivePanel.OffsetInRenderTexture;
|
||||
Vector2 scale = RivePanel.ScaleInRenderTexture;
|
||||
|
||||
|
||||
m_displayImage.uvRect = new Rect(offset, scale);
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected override void OnValidate()
|
||||
{
|
||||
base.OnValidate();
|
||||
|
||||
if (m_initialRivePanel == null)
|
||||
{
|
||||
m_initialRivePanel = GetComponent<RivePanel>();
|
||||
}
|
||||
|
||||
if (m_displayImage == null)
|
||||
{
|
||||
m_displayImage = GetComponent<CanvasRendererRawImage>();
|
||||
}
|
||||
|
||||
if (m_inputProvider == null)
|
||||
{
|
||||
m_inputProvider = GetComponent<CanvasPanelInputProvider>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override void HandlePointerInputModeChanged()
|
||||
{
|
||||
if (m_displayImage == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (PointerInputMode == PointerInputMode.EnablePointerInput && !m_displayImage.raycastTarget)
|
||||
{
|
||||
m_displayImage.raycastTarget = true;
|
||||
}
|
||||
else if (PointerInputMode == PointerInputMode.DisablePointerInput && m_displayImage.raycastTarget)
|
||||
{
|
||||
m_displayImage.raycastTarget = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d4b4a2d64b69b4c0bbdc2f768c08b799
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: f377684eb5623462e80ebba320696f74, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 350858
|
||||
packageName: Rive
|
||||
packageVersion: 0.4.2
|
||||
assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveCanvasRenderer.cs
|
||||
uploadId: 896810
|
||||
@@ -0,0 +1,532 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Rive.EditorTools;
|
||||
using Rive.Utils;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Rive.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Renders a RivePanel to a texture. This component should be attached to a GameObject that has a Renderer component.
|
||||
/// </summary>
|
||||
#if UNITY_EDITOR
|
||||
[HelpURL(InspectorDocLinks.RiveTextureRenderer)]
|
||||
#endif
|
||||
[AddComponentMenu("Rive/Rive Texture Renderer")]
|
||||
#if UNITY_EDITOR
|
||||
[InspectorSection(InspectorSections.RendererSettings, "Renderer Settings", startExpanded: true)]
|
||||
[HideComponents(hideFlags: HideFlags.HideInInspector, typeof(TexturePanelInputProvider), typeof(PanelVisibilityOptimizer))]
|
||||
#endif
|
||||
public class RiveTextureRenderer : PanelRenderer
|
||||
{
|
||||
private static class InspectorSections
|
||||
{
|
||||
|
||||
public const string RendererSettings = "RendererSettings";
|
||||
}
|
||||
|
||||
public enum TextureAssignmentMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets the texture to the main texture of the material.
|
||||
/// </summary>
|
||||
MainTexture = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Sets the texture to the specified material properties.
|
||||
/// </summary>
|
||||
TextureProperties = 1
|
||||
}
|
||||
|
||||
[Tooltip("The RivePanel to display")]
|
||||
[InspectorField(displayName: "Rive Panel")]
|
||||
[SerializeField] private RivePanel m_initialRivePanel;
|
||||
|
||||
private IRivePanel m_rivePanel;
|
||||
|
||||
[InspectorField(InspectorSections.RendererSettings, displayName: "Mesh Renderer")]
|
||||
[Tooltip("The MeshRenderer that will display the Rive graphic.")]
|
||||
[SerializeField] private UnityEngine.Renderer m_objectRenderer;
|
||||
|
||||
[InspectorField(InspectorSections.RendererSettings)]
|
||||
[Tooltip("Determines how the texture is set on the material. If set to MainTexture, the texture is set to the main texture of the material. If set to TextureProperties, the texture is set to the specified material properties.")]
|
||||
[SerializeField] private TextureAssignmentMode m_textureAssignmentMode = TextureAssignmentMode.MainTexture;
|
||||
|
||||
|
||||
[Tooltip("Determines the RivePanel will automatically stop rendering when the mesh is not visible to the camera.")]
|
||||
[SerializeField] private VisibilityOptimizationMode m_visibilityOptimization = VisibilityOptimizationMode.AlwaysRender;
|
||||
|
||||
private Material[] m_materials;
|
||||
|
||||
|
||||
private PanelVisibilityOptimizer m_visibilityOptimizer;
|
||||
|
||||
private TexturePanelInputProvider m_inputProvider;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Inherits from SerializedDictionary to store the material property names. This is needed because Unity does not properly serialize Lists within Lists in the SerializedDictionary.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
internal class SerializedDictionary_Material_ListString : SerializedDictionary<int, PropertyNameListHolder>
|
||||
{
|
||||
|
||||
}
|
||||
// We use a custom editor to display the material property names in a more user-friendly way
|
||||
|
||||
// We use a holder class to store the list of property names for each material because Unity does not properly serialize Lists within Lists in the SerializedDictionary.
|
||||
[System.Serializable]
|
||||
internal class PropertyNameListHolder
|
||||
{
|
||||
[SerializeField]
|
||||
List<string> m_propertyNames = new List<string>();
|
||||
|
||||
|
||||
private List<int> m_propertyIDs;
|
||||
public List<string> PropertyNames => m_propertyNames;
|
||||
|
||||
public List<int> PropertyIDs
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_propertyIDs == null || m_propertyIDs.Count != m_propertyNames.Count)
|
||||
{
|
||||
UpdatePropertyIDs();
|
||||
}
|
||||
return m_propertyIDs;
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdatePropertyIDs()
|
||||
{
|
||||
if (m_propertyIDs == null)
|
||||
{
|
||||
m_propertyIDs = new List<int>();
|
||||
}
|
||||
m_propertyIDs.Clear();
|
||||
for (int i = 0; i < m_propertyNames.Count; i++)
|
||||
{
|
||||
m_propertyIDs.Add(Shader.PropertyToID(m_propertyNames[i]));
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static string BindingPath_PropertyNames => nameof(m_propertyNames);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[ShowIf(nameof(ShouldShowMaterialPropertyNames))]
|
||||
[InspectorField(InspectorSections.RendererSettings)]
|
||||
[Tooltip("The material properties to set the texture to.")]
|
||||
#if UNITY_6000_3_OR_NEWER
|
||||
[MaterialProperties(nameof(GetRendererMaterials), UnityEngine.Rendering.ShaderPropertyType.Texture)]
|
||||
#else
|
||||
[MaterialProperties(nameof(GetRendererMaterials), UnityEditor.ShaderUtil.ShaderPropertyType.TexEnv)]
|
||||
#endif
|
||||
#endif
|
||||
[SerializeField]
|
||||
private SerializedDictionary_Material_ListString m_materialPropertyNameData = new SerializedDictionary_Material_ListString();
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
private Material[] GetRendererMaterials()
|
||||
{
|
||||
if (m_objectRenderer == null)
|
||||
{
|
||||
return new Material[0];
|
||||
}
|
||||
|
||||
return m_objectRenderer.sharedMaterials;
|
||||
}
|
||||
|
||||
private bool ShouldShowMaterialPropertyNames => m_textureAssignmentMode == TextureAssignmentMode.TextureProperties;
|
||||
|
||||
|
||||
protected override void OnValidate()
|
||||
{
|
||||
base.OnValidate();
|
||||
|
||||
if (m_objectRenderer == null || !ReferenceEquals(m_objectRenderer.gameObject, this.gameObject))
|
||||
{
|
||||
m_objectRenderer = GetComponent<UnityEngine.Renderer>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
// Perform one-time conversion of default pipeline materials when the component is first added or Reset is invoked.
|
||||
void Reset()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
|
||||
if (m_objectRenderer == null)
|
||||
{
|
||||
m_objectRenderer = GetComponent<UnityEngine.Renderer>();
|
||||
|
||||
if (m_objectRenderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MaterialConversionUtility.EnsureRiveMaterialsOnRenderer(m_objectRenderer);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Renderer component that is used to render the Rive graphic.
|
||||
/// </summary>
|
||||
public UnityEngine.Renderer Renderer => m_objectRenderer;
|
||||
|
||||
/// <summary>
|
||||
/// The mode of setting the material texture. Use this to determine how the texture is set on the material.
|
||||
/// </summary>
|
||||
public TextureAssignmentMode MaterialTextureAssignmentMode
|
||||
{
|
||||
get => m_textureAssignmentMode;
|
||||
set
|
||||
{
|
||||
m_textureAssignmentMode = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Determines if the RivePanel should stop rendering when the mesh is not visible to the camera.
|
||||
/// </summary>
|
||||
public VisibilityOptimizationMode VisibilityOptimization
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_visibilityOptimizer != null)
|
||||
{
|
||||
return m_visibilityOptimizer.VisibilityMode;
|
||||
}
|
||||
|
||||
return m_visibilityOptimization;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_visibilityOptimization = value;
|
||||
if (m_visibilityOptimizer != null)
|
||||
{
|
||||
m_visibilityOptimizer.VisibilityMode = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of materials that have property names assigned.
|
||||
/// </summary>
|
||||
public int MaterialPropertyCount => m_materialPropertyNameData.Count;
|
||||
|
||||
|
||||
public override IRivePanel RivePanel
|
||||
{
|
||||
get
|
||||
{
|
||||
// Outside of play mode, we want to reference the serialized field.
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
return m_initialRivePanel;
|
||||
}
|
||||
return m_rivePanel;
|
||||
}
|
||||
internal set
|
||||
{
|
||||
|
||||
m_initialRivePanel = value as RivePanel;
|
||||
}
|
||||
}
|
||||
|
||||
public Action OnPanelChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the RivePanel that this renderer will render.
|
||||
/// </summary>
|
||||
/// <param name="panel"></param>
|
||||
public void SetPanel(IRivePanel panel)
|
||||
{
|
||||
if (ReferenceEquals(m_rivePanel, panel))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_rivePanel != null)
|
||||
{
|
||||
m_rivePanel.UnregisterInputProvider(m_inputProvider);
|
||||
|
||||
UnsubscribeFromPanelEvents();
|
||||
}
|
||||
m_rivePanel = panel;
|
||||
|
||||
if (m_rivePanel != null)
|
||||
{
|
||||
if (m_inputProvider != null)
|
||||
{
|
||||
m_rivePanel.RegisterInputProvider(m_inputProvider);
|
||||
|
||||
}
|
||||
SubscribeToPanelEvents();
|
||||
}
|
||||
|
||||
UpdateVisualTarget();
|
||||
|
||||
OnPanelChanged?.Invoke();
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
Setup();
|
||||
base.OnEnable();
|
||||
|
||||
if (m_rivePanel != null && m_inputProvider != null)
|
||||
{
|
||||
RivePanel.RegisterInputProvider(m_inputProvider);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
|
||||
if (m_rivePanel != null && m_inputProvider != null)
|
||||
{
|
||||
m_rivePanel.UnregisterInputProvider(m_inputProvider);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void LogInputErrorWarningsIfNeeded()
|
||||
{
|
||||
if (PointerInputMode == PointerInputMode.DisablePointerInput)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// If there's no event system in the scene, we log a warning.
|
||||
if (UnityEngine.EventSystems.EventSystem.current == null)
|
||||
{
|
||||
DebugLogger.Instance.LogWarning($"No EventSystem found in the scene. Please add an {nameof(UnityEngine.EventSystems.EventSystem)} to the scene to receive pointer input events.");
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
var camera = Camera.main;
|
||||
if (camera != null && camera.gameObject.GetComponent<UnityEngine.EventSystems.PhysicsRaycaster>() == null)
|
||||
{
|
||||
DebugLogger.Instance.LogWarning($"No {nameof(UnityEngine.EventSystems.PhysicsRaycaster)} found on the main camera. Please add a {nameof(UnityEngine.EventSystems.PhysicsRaycaster)} component to the main camera to receive pointer input events. Or set the {nameof(PointerInputMode)} to {nameof(PointerInputMode.DisablePointerInput)}.");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
LogInputErrorWarningsIfNeeded();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void SpawnVisibilityOptimizerIfNeeded()
|
||||
{
|
||||
if (m_objectRenderer == null || m_visibilityOptimizer != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!m_objectRenderer.TryGetComponent(out m_visibilityOptimizer))
|
||||
{
|
||||
// We add the component to the GameObject that has the Renderer component because we can't be certain that it's the same GameObject as the RivePanel.
|
||||
m_visibilityOptimizer = m_objectRenderer.gameObject.AddComponent<PanelVisibilityOptimizer>();
|
||||
}
|
||||
|
||||
m_visibilityOptimizer.VisibilityMode = m_visibilityOptimization;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetMaterialPropertyNames(int materialIndex)
|
||||
{
|
||||
return m_materialPropertyNameData.TryGetValue(materialIndex, out var holder)
|
||||
? holder.PropertyNames
|
||||
: Array.Empty<string>();
|
||||
}
|
||||
|
||||
public void SetMaterialPropertyNames(int materialIndex, IEnumerable<string> propertyNames)
|
||||
{
|
||||
if (!m_materialPropertyNameData.TryGetValue(materialIndex, out var holder))
|
||||
{
|
||||
holder = new PropertyNameListHolder();
|
||||
m_materialPropertyNameData[materialIndex] = holder;
|
||||
}
|
||||
holder.PropertyNames.Clear();
|
||||
holder.PropertyNames.AddRange(propertyNames);
|
||||
|
||||
// Force recreation of property IDs on next use
|
||||
holder.UpdatePropertyIDs();
|
||||
}
|
||||
|
||||
public void ClearMaterialPropertyNames()
|
||||
{
|
||||
m_materialPropertyNameData.Clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a material index has any property names assigned.
|
||||
/// </summary>
|
||||
public bool HasPropertyNames(int materialIndex) => m_materialPropertyNameData.ContainsKey(materialIndex);
|
||||
|
||||
|
||||
private void SetMaterialTexture(RenderTexture texture, Vector2 offset, Vector2 scale)
|
||||
{
|
||||
if (m_objectRenderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// We loop through all the material properties and set the texture to all of them.
|
||||
// We do this because the material might have multiple textures that we want to update.
|
||||
// We also need to account for there being multiple materials on the renderer.
|
||||
|
||||
for (int i = 0; i < m_materials.Length; i++)
|
||||
{
|
||||
var material = m_materials[i];
|
||||
if (material == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_textureAssignmentMode == TextureAssignmentMode.MainTexture)
|
||||
{
|
||||
material.mainTexture = texture;
|
||||
material.mainTextureOffset = offset;
|
||||
material.mainTextureScale = scale;
|
||||
}
|
||||
else if (m_textureAssignmentMode == TextureAssignmentMode.TextureProperties)
|
||||
{
|
||||
if (m_materialPropertyNameData.TryGetValue(i, out var holder))
|
||||
{
|
||||
var propertyIDs = holder.PropertyIDs;
|
||||
for (int g = 0; g < propertyIDs.Count; g++)
|
||||
{
|
||||
material.SetTexture(propertyIDs[g], texture);
|
||||
material.SetTextureOffset(propertyIDs[g], offset);
|
||||
material.SetTextureScale(propertyIDs[g], scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Setup()
|
||||
{
|
||||
if (m_objectRenderer == null)
|
||||
{
|
||||
m_objectRenderer = GetComponent<UnityEngine.Renderer>();
|
||||
}
|
||||
|
||||
if (m_objectRenderer == null)
|
||||
{
|
||||
DebugLogger.Instance.Log($"No {nameof(UnityEngine.Renderer)} found. Please assign a renderer to the {nameof(RiveTextureRenderer)}.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_rivePanel == null)
|
||||
{
|
||||
m_rivePanel = m_initialRivePanel;
|
||||
}
|
||||
|
||||
// Cache the materials so we can set the texture on them later
|
||||
m_materials = m_objectRenderer.materials;
|
||||
|
||||
|
||||
SpawnVisibilityOptimizerIfNeeded();
|
||||
|
||||
SpawnInputProviderIfNeeded();
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns the input provider on the game object that has the MeshRenderer and collider. The input provider receives IPointer events from the Unity Event System and forwards them to the RiveWidgets, so it needs to be attached to the same GameObject that receives the events, which is the Render game object with the collider.
|
||||
/// </summary>
|
||||
private void SpawnInputProviderIfNeeded()
|
||||
{
|
||||
if (m_objectRenderer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_inputProvider != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_objectRenderer.gameObject.TryGetComponent(out m_inputProvider))
|
||||
{
|
||||
m_inputProvider = m_objectRenderer.gameObject.AddComponent<TexturePanelInputProvider>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected override void UpdateVisualTarget()
|
||||
{
|
||||
var renderTexture = RivePanel.RenderTexture;
|
||||
|
||||
|
||||
Vector2 offset = RivePanel.OffsetInRenderTexture;
|
||||
Vector2 scale = RivePanel.ScaleInRenderTexture;
|
||||
|
||||
SetMaterialTexture(renderTexture, offset, scale);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the materials on the renderer. This method should be called after changing the materials on the renderer.
|
||||
/// </summary>
|
||||
public void RefreshMaterials()
|
||||
{
|
||||
m_materials = m_objectRenderer.materials;
|
||||
|
||||
UpdateVisualTarget();
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
|
||||
if (m_materials == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Destroy the materials that we instantiated.
|
||||
for (int i = m_materials.Length - 1; i >= 0; i--)
|
||||
{
|
||||
var material = m_materials[i];
|
||||
|
||||
if (material == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Destroy(material);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6fef7631bb6fb4a2ebebe7bfce6ea442
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {fileID: 2800000, guid: f377684eb5623462e80ebba320696f74, type: 3}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 350858
|
||||
packageName: Rive
|
||||
packageVersion: 0.4.2
|
||||
assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/RiveTextureRenderer.cs
|
||||
uploadId: 896810
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace Rive.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines how the visibility optimization should behave
|
||||
/// </summary>
|
||||
public enum VisibilityOptimizationMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Only renders when the gameobject is rendering
|
||||
/// </summary>
|
||||
RenderWhenVisible = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Always renders regardless of gameobject's visibility
|
||||
/// </summary>
|
||||
AlwaysRender = 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c5802ebe74ae402c96d5bf58ce00d71
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 350858
|
||||
packageName: Rive
|
||||
packageVersion: 0.4.2
|
||||
assetPath: Packages/app.rive.rive-unity/Runtime/Components/Public/PanelRenderers/VisibilityOptimizationMode.cs
|
||||
uploadId: 896810
|
||||
Reference in New Issue
Block a user