Files
BABA_YAGA/Packages/app.rive.rive-unity/Runtime/Components/Public/RenderTargetStategies/SimpleRenderTargetStrategy.cs
2026-05-19 17:39:03 +07:00

289 lines
8.5 KiB
C#

using System.Collections.Generic;
using Rive.Components.Utilities;
using Rive.Utils;
using UnityEngine;
namespace Rive.Components
{
/// <summary>
/// This render target strategy uses a single render texture for each panel. This is the default strategy used unless a custom strategy is specified. This component should be attached to the same GameObject as the RivePanel component it is managing.
/// </summary>
[AddComponentMenu("Rive/Render Target Strategies/Simple Render Target Strategy")]
[DisallowMultipleComponent]
public class SimpleRenderTargetStrategy : RenderTargetStrategy
{
[SerializeField] private RivePanel m_panel;
[Tooltip("Controls when rendering occurs. In Batched mode, panels are rendered once per frame regardless of redraw requests. In Immediate mode, panels are rendered instantly when requested.")]
[SerializeField] private DrawTimingOption m_drawTiming = DrawTimingOption.DrawBatched;
private Renderer m_renderer;
private RenderTexture m_renderTexture;
private bool m_redrawRequested = false;
protected override void OnEnable()
{
base.OnEnable();
if (m_panel == null && !TryGetComponent(out m_panel))
{
DebugLogger.Instance.LogError($"No {nameof(RivePanel)} component found on GameObject. {nameof(SimpleRenderTargetStrategy)} requires a {nameof(RivePanel)} component.");
}
}
private RenderTargetSpaceOccupancy TargetSpaceOccupancy
{
get
{
return RenderTargetSpaceOccupancy.Exclusive;
}
}
public override DrawTimingOption DrawTiming { get => m_drawTiming; set => m_drawTiming = value; }
public override bool RegisterPanel(IRivePanel panel)
{
if (panel == null)
{
DebugLogger.Instance.LogWarning("Trying to add a null panel to the strategy.");
return false;
}
if (!ReferenceEquals(panel, m_panel))
{
DebugLogger.Instance.LogWarning("Trying to register wrong panel with this strategy.");
return false;
}
if (IsPanelRegistered(panel))
{
DebugLogger.Instance.LogWarning("Panel is already registered with this strategy.");
return false;
}
if (IsDestroyed)
{
return false;
}
CreateAndRegisterRendererForPanel();
DrawPanel(panel);
TriggerPanelRegisteredEvent(panel);
return true;
}
public override bool UnregisterPanel(IRivePanel panel)
{
if (IsPanelRegistered(panel))
{
UnregisterRenderer(m_renderer);
TriggerPanelUnregisteredEvent(panel);
return true;
}
return false;
}
private void CreateAndRegisterRendererForPanel()
{
if (m_renderer == null)
{
m_renderer = RendererUtils.CreateRenderer();
}
RegisterRenderer(m_renderer);
}
public override bool IsPanelRegistered(IRivePanel panel)
{
if (m_renderer == null || m_panel == null || panel == null)
{
return false;
}
return ReferenceEquals(panel, m_panel) && RenderPipelineHandler.IsRendererRegistered(m_renderer);
}
public override RenderTexture GetRenderTexture(IRivePanel panel)
{
if (!IsPanelRegistered(panel))
{
return null;
}
return ReferenceEquals(panel, m_panel) ? m_renderTexture : null;
}
public override Vector2 GetPanelOffset(IRivePanel panel)
{
return Vector2.zero;
}
public override Vector2 GetPanelScale(IRivePanel panel)
{
return Vector2.one;
}
private bool RefreshRenderTexture(IRivePanel panel)
{
Vector2Int size =
ExternalPixelSizeProvider != null
? ExternalPixelSizeProvider(panel)
: new Vector2Int(
Mathf.Max(1, (int)panel.WidgetContainer.rect.width),
Mathf.Max(1, (int)panel.WidgetContainer.rect.height)
);
size.x = Mathf.Max(1, size.x);
size.y = Mathf.Max(1, size.y);
// Use the persistent texture if it exists
if (m_renderTexture == null)
{
m_renderTexture = CreateRenderTexture(size.x, size.y);
if (m_renderTexture == null)
{
return false;
}
if (!m_renderTexture.IsCreated())
{
m_renderTexture.Create();
}
RenderPipelineHandler.SetRendererTexture(m_renderer, m_renderTexture);
return true;
}
// Resize if needed
if (m_renderTexture.width != size.x || m_renderTexture.height != size.y)
{
m_renderTexture = ResizeRenderTexture(m_renderTexture, size.x, size.y);
if (!m_renderTexture.IsCreated())
{
m_renderTexture.Create();
}
RenderPipelineHandler.SetRendererTexture(m_renderer, m_renderTexture);
return true;
}
// If for some reason the renderer is not using the correct texture, update it
if (m_renderer != null && !ReferenceEquals(m_renderer.RenderQueue.Texture, m_renderTexture))
{
RenderPipelineHandler.SetRendererTexture(m_renderer, m_renderTexture);
}
return false;
}
protected override IEnumerable<Renderer> GetRenderers()
{
if (m_renderer != null)
{
yield return m_renderer;
}
}
public override void DrawPanel(IRivePanel panel)
{
if (!IsPanelRegistered(panel))
{
return;
}
if (DrawTiming == DrawTimingOption.DrawImmediate)
{
HandlePanelDrawing(panel);
return;
}
// For DrawBatched mode
m_redrawRequested = true;
}
private void HandlePanelDrawing(IRivePanel panel)
{
if (!IsPanelRegistered(panel))
{
return;
}
m_renderer.SetArtboardDirtCheckEnabled(panel.DrawOptimization == DrawOptimizationOptions.DrawWhenChanged);
bool wasRefreshed = RefreshRenderTexture(panel);
m_renderer.Clear();
if (ExternalDrawScaleProvider != null)
{
var s = ExternalDrawScaleProvider(panel);
if (Mathf.Abs(s.x - 1f) > 0.001f || Mathf.Abs(s.y - 1f) > 0.001f)
{
m_renderer.Transform(System.Numerics.Matrix3x2.CreateScale(s.x, s.y));
}
}
var targetInfo = new RenderTargetInfo(
new Vector2Int(m_renderTexture.width, m_renderTexture.height), // Target size
new Vector2Int(m_renderTexture.width, m_renderTexture.height) // Panel allocation (same as target since panel uses entire texture)
);
DrawPanelWithRenderer(m_renderer, panel, targetInfo, TargetSpaceOccupancy);
if (wasRefreshed)
{
TriggerRenderTargetUpdatedEvent(panel);
}
}
internal protected override void PrepareBatchedRender()
{
if (DrawTiming != DrawTimingOption.DrawBatched)
{
return;
}
if (m_redrawRequested)
{
HandlePanelDrawing(m_panel);
m_redrawRequested = false;
}
}
private void Cleanup()
{
if (m_renderer != null)
{
UnregisterRenderer(m_renderer);
RendererUtils.ReleaseRenderer(m_renderer);
m_renderer = null;
}
if (m_renderTexture != null)
{
ReleaseRenderTexture(m_renderTexture);
Destroy(m_renderTexture);
m_renderTexture = null;
}
}
protected override void OnDestroy()
{
Cleanup();
base.OnDestroy();
}
}
}