Files
2026-11-01 23:39:55 +02:00

228 lines
7.1 KiB
C#

using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
#endif
namespace UnityEngine.Rendering.Universal
{
internal static class Light2DManager
{
private static SortingLayer[] s_SortingLayers;
static List<Light2D> s_Lights = new List<Light2D>(); // Scene/Game/Prefab view
#if UNITY_EDITOR
static Dictionary<SceneHandle, List<Light2D>> s_LightsEditorOnly = new Dictionary<SceneHandle, List<Light2D>>(); // Preview view
#endif
// GetLights return different list depending on the context of the GameObject requesting (Camera or Light2D)
// We determine if the GameObject is part of the preview scene through IsPreviewSceneObject
// Scene, Game, Prefab view uses s_Lights
// Preview view uses s_LightsEditorOnly
static List<Light2D> GetOrCreateLights(GameObject obj)
{
#if UNITY_EDITOR
if (IsPreview(obj, out var key))
{
if (!s_LightsEditorOnly.TryGetValue(key, out var list))
{
list = new List<Light2D>();
s_LightsEditorOnly.Add(key, list);
}
return s_LightsEditorOnly[key];
}
#endif
return s_Lights;
}
internal static bool TryGetLights(GameObject obj, out List<Light2D> lights)
{
#if UNITY_EDITOR
if (IsPreview(obj, out var key))
return s_LightsEditorOnly.TryGetValue(key, out lights);
#endif
lights = s_Lights;
return true;
}
internal static void RemoveLight(Light2D light)
{
#if UNITY_EDITOR
if (IsPreview(light.gameObject, out var key))
{
if (s_LightsEditorOnly.TryGetValue(key, out var list))
{
Debug.Assert(list.Contains(light));
list.Remove(light);
if (list.Count == 0)
s_LightsEditorOnly.Remove(key);
return;
}
}
#endif
Debug.Assert(s_Lights.Contains(light));
s_Lights.Remove(light);
}
#if UNITY_EDITOR
static bool IsPreview(GameObject obj, out SceneHandle handle)
{
handle = obj.scene.handle;
var isPreview = EditorSceneManager.IsPreviewSceneObject(obj);
// Prefab scene
var prefabStage = PrefabStageUtility.GetPrefabStage(obj);
if (prefabStage != null && isPreview)
{
if (obj.TryGetComponent<Camera>(out var cam))
isPreview = cam.cameraType == CameraType.Preview;
else
isPreview = false;
}
return isPreview;
}
#endif
#if UNITY_EDITOR
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void ResetStaticsOnLoad()
{
s_SortingLayers = null;
s_Lights.Clear();
s_LightsEditorOnly.Clear();
}
#endif
internal static void Initialize()
{
#if UNITY_EDITOR
SortingLayer.onLayerChanged += OnSortingLayerChanged;
#endif
}
internal static void Dispose()
{
#if UNITY_EDITOR
SortingLayer.onLayerChanged -= OnSortingLayerChanged;
#endif
}
// Called during OnEnable
public static void RegisterLight(Light2D light)
{
var lights = GetOrCreateLights(light.gameObject);
Debug.Assert(!lights.Contains(light));
lights.Add(light);
ErrorIfDuplicateGlobalLight(light);
}
// Called during OnEnable
public static void DeregisterLight(Light2D light)
{
RemoveLight(light);
}
public static void ErrorIfDuplicateGlobalLight(Light2D light)
{
if (light.lightType != Light2D.LightType.Global)
return;
foreach (var sortingLayer in light.targetSortingLayers)
{
// should this really trigger at runtime?
if (ContainsDuplicateGlobalLight(sortingLayer, light))
Debug.LogError("More than one global light on layer " + SortingLayer.IDToName(sortingLayer) + " for light blend style index " + light.blendStyleIndex);
}
}
internal static bool GetGlobalColor(int sortingLayerIndex, int blendStyleIndex, Camera cam, out Color color)
{
var foundGlobalColor = false;
color = Color.black;
// This should be rewritten to search only global lights
foreach (var light in GetOrCreateLights(cam.gameObject))
{
if (light.lightType != Light2D.LightType.Global ||
light.blendStyleIndex != blendStyleIndex ||
!light.IsLitLayer(sortingLayerIndex))
continue;
var inCurrentPrefabStage = true;
#if UNITY_EDITOR
// If we found the first global light in our prefab stage
inCurrentPrefabStage = PrefabStageUtility.GetCurrentPrefabStage()?.IsPartOfPrefabContents(light.gameObject) ?? true;
#endif
if (inCurrentPrefabStage)
{
color = light.color * light.intensity;
return true;
}
else
{
if (!foundGlobalColor)
{
color = light.color * light.intensity;
foundGlobalColor = true;
}
}
}
return foundGlobalColor;
}
private static bool ContainsDuplicateGlobalLight(int sortingLayerIndex, Light2D inLight)
{
var globalLightCount = 0;
// This should be rewritten to search only global lights
foreach (var light in GetOrCreateLights(inLight.gameObject))
{
if (light.lightType == Light2D.LightType.Global &&
light.blendStyleIndex == inLight.blendStyleIndex &&
light.IsLitLayer(sortingLayerIndex))
{
#if UNITY_EDITOR
// If we found the first global light in our prefab stage
if (PrefabStageUtility.GetPrefabStage(light.gameObject) == PrefabStageUtility.GetCurrentPrefabStage())
#endif
{
if (globalLightCount > 0)
return true;
globalLightCount++;
}
}
}
return false;
}
public static SortingLayer[] GetCachedSortingLayer()
{
if (s_SortingLayers is null)
s_SortingLayers = SortingLayer.layers;
return s_SortingLayers;
}
#if UNITY_EDITOR
internal static void OnSortingLayerChanged()
{
// Update sorting layers that were added or removed or changed order
s_SortingLayers = SortingLayer.layers;
}
#endif
}
}