Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ocean Renderer OnEnabled lifecycle event #629

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,18 @@ public class UnderwaterEnvironmentalLighting : MonoBehaviour

public const float DEPTH_OUTSCATTER_CONSTANT = 0.25f;

OceanRendererLifeCycleHelper _oceanRendererLifeCycle;
bool _isInitialised = false;

void Awake()
{
_oceanRendererLifeCycle = new OceanRendererLifeCycleHelper(this);
}

void OnEnable()
{
if (OceanRenderer.Instance == null)
if (!_oceanRendererLifeCycle.OnEnable())
{
enabled = false;
return;
}

Expand Down Expand Up @@ -76,6 +81,8 @@ void OnEnable()

void OnDisable()
{
_oceanRendererLifeCycle.OnDisable();

if (!_isInitialised)
{
return;
Expand All @@ -93,6 +100,11 @@ void OnDisable()
_isInitialised = false;
}

void OnDestroy()
{
_oceanRendererLifeCycle.OnDestroy();
}

void LateUpdate()
{
if (OceanRenderer.Instance == null)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Crest Ocean System

// This file is subject to the MIT License as seen in the root of this folder structure (LICENSE)

namespace Crest
{
using UnityEngine;

/// <summary>
/// Enables/disables a component based on the OceanRenderer's life cycle. It will allow a component that depend on
/// the OceanRenderer to initialise after the OceanRenderer has initialised (i.e. delayed initialisation).
///
/// It stores the "enabled" state set by the user as it enables or disables the component if the OceanRenderer is
/// enabled or disabled respectively using event subscription broadcasted from the OceanRenderer.
///
/// It supports [ExecuteAlways/InEditMode] by storing the "enabled" state, but does not enable or disable the
/// component as that would change serialized data.
///
/// Components must call OnEnable, OnDisable and OnDestroy from their MonoBehaviour counterparts.
/// </summary>
public class OceanRendererLifeCycleHelper
{
// The mono behaviour we want to track the enabled/disabled preference.
readonly MonoBehaviour _monoBehaviour;

// Store the "enabled" state set by the user so we can respect it.
internal bool _enabledValueSetByTheUser;

// Whether the state change came from the user or from the ocean life cycle event. Generally, this should always
// be true since state changes from users are unknown.
bool _isStateChangeFromUser = false;

public OceanRendererLifeCycleHelper(MonoBehaviour monoBehaviour)
{
_monoBehaviour = monoBehaviour;
// Store the "enabled" state set by the user.
_enabledValueSetByTheUser = _monoBehaviour.enabled;

OceanRenderer.OnOceanRendererEnabled -= OnOceanRendererEnabled;
OceanRenderer.OnOceanRendererEnabled += OnOceanRendererEnabled;
OceanRenderer.OnOceanRendererDisabled -= OnOceanRendererDisabled;
OceanRenderer.OnOceanRendererDisabled += OnOceanRendererDisabled;
}

~OceanRendererLifeCycleHelper()
{
OceanRenderer.OnOceanRendererEnabled -= OnOceanRendererEnabled;
OceanRenderer.OnOceanRendererDisabled -= OnOceanRendererDisabled;
}

/// <summary>
/// Needs to be called to clean up resources. Destructors do not work when domain reload is disabled.
/// </summary>
public void OnDestroy()
{
OceanRenderer.OnOceanRendererEnabled -= OnOceanRendererEnabled;
OceanRenderer.OnOceanRendererDisabled -= OnOceanRendererDisabled;
}

/// <summary>
/// Sets enabled based on OceanRenderer's life cycle. Callee must return early if false is returned.
/// </summary>
public bool OnEnable()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
// In edit mode just store "enabled" as we do not disable the component anyway.
_enabledValueSetByTheUser = _monoBehaviour.enabled;
return OceanRenderer.Instance != null;
}
#endif

// This will be "false" when we know when the user has not changed the state which is something we can
// more easily determine like when we change the state ourselves.
if (_isStateChangeFromUser)
{
// Flip value as it could be either the user enabling or disabling the component. For the case where the
// ocean renderer is not active and this component is set to be enabled, the component will be disabled.
// The user will see an unchecked checkbox for "enable" as they should. When they toggle it, it will
// enable the component but since the ocean is disabled it will disable itself after recording the
// user's preference.
_enabledValueSetByTheUser = !_enabledValueSetByTheUser;
}

// Always revert to "true" as whether the change comes from a user is unknown.
_isStateChangeFromUser = true;

if (OceanRenderer.Instance == null)
{
// Mark "false" as we will now disable the component and the subsequent OnDisable is not from the user.
_isStateChangeFromUser = false;
_monoBehaviour.enabled = false;
return false;
}

return true;
}

/// <summary>
/// Sets enabled based on OceanRenderer's life cycle.
/// </summary>
public void OnDisable()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
{
// In edit mode just store "enabled" as we do not disable the component anyway.
_enabledValueSetByTheUser = _monoBehaviour.enabled;
return;
}
#endif

if (_isStateChangeFromUser)
{
_enabledValueSetByTheUser = false;
}

// Always revert to "true" as whether the change comes from a user is unknown.
_isStateChangeFromUser = true;
}

// This will be called by the OceanRenderer through an event. If during the component's OnEnable event the
// OceanRenderer is already ready, then this will be skipped.
void OnOceanRendererEnabled()
{
#if UNITY_EDITOR
// We do not want to change a serialised value in edit mode.
if (!Application.isPlaying)
{
return;
}
#endif

// If these two are equal then this event will do nothing and next OnEnable/OnDisable could be the user.
_isStateChangeFromUser = _monoBehaviour.enabled == _enabledValueSetByTheUser;
// Apply the "enabled" state that the user wants now that OceanRenderer is ready.
_monoBehaviour.enabled = _enabledValueSetByTheUser;
}

// This will be called by the OceanRenderer through an event.
void OnOceanRendererDisabled()
{
if (!Application.isPlaying)
{
return;
}

// If the user has set the component to disabled, then this event will do nothing and next
// OnEnable/OnDisable could be the user.
_isStateChangeFromUser = _enabledValueSetByTheUser == false;
_monoBehaviour.enabled = false;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 31 additions & 5 deletions crest/Assets/Crest/Crest/Scripts/LodData/OceanDepthCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,32 @@ public enum OceanDepthCacheRefreshMode
Camera _camDepthCache;
Material _copyDepthMaterial;

OceanRendererLifeCycleHelper _oceanRendererLifeCycle;

bool _isInitialized = false;

void Awake()
{
_oceanRendererLifeCycle = new OceanRendererLifeCycleHelper(this);
}

void OnEnable()
{
_oceanRendererLifeCycle.OnEnable();
}

void OnDisable()
{
_oceanRendererLifeCycle.OnDisable();
}

void OnDestroy()
{
_oceanRendererLifeCycle.OnDestroy();
}

void Start()
{
if (OceanRenderer.Instance == null)
{
enabled = false;
return;
}

#if UNITY_EDITOR
if (EditorApplication.isPlaying && _runValidationOnStart)
Expand All @@ -111,11 +130,18 @@ void Start()
{
PopulateCache();
}

_isInitialized = true;
}

#if UNITY_EDITOR
void Update()
{
if (!_isInitialized)
{
Start();
}

// We need to switch the quad texture if the user changes the cache type in the editor.
InitCacheQuad();

Expand Down
6 changes: 6 additions & 0 deletions crest/Assets/Crest/Crest/Scripts/OceanRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ public enum DefaultClippingState
SampleHeightHelper _sampleHeightHelper = new SampleHeightHelper();

public static OceanRenderer Instance { get; private set; }
public static System.Action OnOceanRendererEnabled;
public static System.Action OnOceanRendererDisabled;

// A hash of the settings used to generate the ocean, used to regenerate when necessary
int _generatedSettingsHash = 0;
Expand Down Expand Up @@ -528,6 +530,8 @@ void OnEnable()
}

_canSkipCulling = false;

OnOceanRendererEnabled?.Invoke();
}

private void OnDisable()
Expand All @@ -548,6 +552,8 @@ private void OnDisable()
}
#endif

OnOceanRendererDisabled?.Invoke();

CleanUp();

Instance = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;


Expand Down Expand Up @@ -125,11 +126,17 @@ public class OceanPlanarReflection : MonoBehaviour
const int CULL_DISTANCE_COUNT = 32;
float[] _cullDistances = new float[CULL_DISTANCE_COUNT];

private void Start()
internal OceanRendererLifeCycleHelper _oceanRendererLifeCycle;

private void Awake()
{
if (OceanRenderer.Instance == null)
_oceanRendererLifeCycle = new OceanRendererLifeCycleHelper(this);
}

private void OnEnable()
{
if (!_oceanRendererLifeCycle.OnEnable())
{
enabled = false;
return;
}

Expand Down Expand Up @@ -383,6 +390,8 @@ static void CalculateReflectionMatrix(ref Matrix4x4 reflectionMat, Vector4 plane

private void OnDisable()
{
_oceanRendererLifeCycle.OnDisable();

if (_camViewpoint != null)
{
PreparedReflections.Remove(_camViewpoint.GetHashCode());
Expand All @@ -400,5 +409,31 @@ private void OnDisable()
_camReflections = null;
}
}

private void OnDestroy()
{
_oceanRendererLifeCycle.OnDestroy();
}
}

#if UNITY_EDITOR
[CustomEditor(typeof(OceanPlanarReflection)), CanEditMultipleObjects]
public class OceanPlanarReflectionEditor : Editor
{
public override void OnInspectorGUI()
{
var target = this.target as OceanPlanarReflection;

if (OceanRenderer.Instance == null && target._oceanRendererLifeCycle._enabledValueSetByTheUser)
{
EditorGUILayout.Space();
EditorGUILayout.HelpBox("The component is disabled as there is no active OceanRenderer in " +
"the scene. It will be enabled once there is one.", MessageType.Info);
EditorGUILayout.Space();
}

base.OnInspectorGUI();
}
}
#endif
}