Aetheria/Assets/Wwise/MonoBehaviour/Runtime/AkRoom.cs
2021-04-30 07:09:07 +01:00

478 lines
No EOL
16 KiB
C#

#if ! (UNITY_DASHBOARD_WIDGET || UNITY_WEBPLAYER || UNITY_WII || UNITY_WIIU || UNITY_NACL || UNITY_FLASH || UNITY_BLACKBERRY) // Disable under unsupported platforms.
[UnityEngine.AddComponentMenu("Wwise/Spatial Audio/AkRoom")]
[UnityEngine.RequireComponent(typeof(UnityEngine.Collider))]
[UnityEngine.DisallowMultipleComponent]
/// @brief An AkRoom is an enclosed environment that can only communicate to the outside/other rooms with AkRoomPortals
/// @details The AkRoom component uses its required Collider component to determine when AkRoomAwareObjects enter and exit the room using the OnTriggerEnter and OnTriggerExit callbacks.
public class AkRoom : AkTriggerHandler
{
public static ulong INVALID_ROOM_ID = unchecked((ulong)-1.0f);
public static ulong GetAkRoomID(AkRoom room)
{
return room == null ? INVALID_ROOM_ID : room.GetID();
}
public static int RoomCount { get; private set; }
#region Fields
[UnityEngine.Tooltip("Higher number has a higher priority")]
/// In cases where a game object is in an area with two rooms, the higher priority room will be chosen for AK::SpatialAudio::SetGameObjectInRoom()
/// The higher the priority number, the higher the priority of a room.
public int priority = 0;
/// The reverb auxiliary bus.
public AK.Wwise.AuxBus reverbAuxBus = new AK.Wwise.AuxBus();
[UnityEngine.Range(0, 1)]
/// The reverb control value for the send to the reverb aux bus.
public float reverbLevel = 1;
[UnityEngine.Range(0, 1)]
/// Loss value modeling transmission through walls.
public float transmissionLoss = 1;
/// Wwise Event to be posted on the room game object.
public AK.Wwise.Event roomToneEvent = new AK.Wwise.Event();
[UnityEngine.Range(0, 1)]
[UnityEngine.Tooltip("Send level for sounds that are posted on the room game object; adds reverb to ambience and room tones. Valid range: (0.f-1.f). A value of 0 disables the aux send.")]
/// Send level for sounds that are posted on the room game object; adds reverb to ambience and room tones. Valid range: (0.f-1.f). A value of 0 disables the aux send.
public float roomToneAuxSend = 0;
/// This is the list of AkRoomAwareObjects that have entered this AkRoom
private System.Collections.Generic.List<AkRoomAwareObject> roomAwareObjectsEntered = new System.Collections.Generic.List<AkRoomAwareObject>();
/// This is the list of AkRoomAwareObjects that have entered this AkRoom while it was inactive or disabled.
private System.Collections.Generic.List<AkRoomAwareObject> roomAwareObjectsDetectedWhileDisabled = new System.Collections.Generic.List<AkRoomAwareObject>();
private UnityEngine.Collider roomCollider = null;
private System.Type previousColliderType;
#if UNITY_EDITOR
private UnityEngine.Vector3 previousPosition;
private UnityEngine.Vector3 previousScale;
private UnityEngine.Quaternion previousRotation;
private UnityEngine.MeshCollider previousMeshCollider;
private UnityEngine.BoxCollider previousBoxCollider;
private UnityEngine.CapsuleCollider previousCapsuleCollider;
private UnityEngine.Vector3 previousUp;
private UnityEngine.Vector3 previousFront;
private uint previousReverbAuxBus;
private float previousReverbLevel;
private float previousTransmissionLoss;
private float previousRoomGameObj_AuxSendLevelToSelf;
private bool previousRoomGameObj_KeepRegistered;
private ulong previousGeometryID;
#endif
#endregion
public bool TryEnter(AkRoomAwareObject roomAwareObject)
{
if (roomAwareObject)
{
if (isActiveAndEnabled)
{
if(!roomAwareObjectsEntered.Contains(roomAwareObject))
roomAwareObjectsEntered.Add(roomAwareObject);
return true;
}
else
{
if (!roomAwareObjectsDetectedWhileDisabled.Contains(roomAwareObject))
roomAwareObjectsDetectedWhileDisabled.Add(roomAwareObject);
return false;
}
}
return false;
}
public void Exit(AkRoomAwareObject roomAwareObject)
{
if (roomAwareObject)
{
roomAwareObjectsEntered.Remove(roomAwareObject);
roomAwareObjectsDetectedWhileDisabled.Remove(roomAwareObject);
}
}
/// Access the room's ID
public ulong GetID()
{
return AkSoundEngine.GetAkGameObjectID(gameObject);
}
public void SetRoom()
{
ulong geometryID = GetGeometryID();
#if UNITY_EDITOR
if (previousUp == transform.up &&
previousFront == transform.forward &&
previousReverbAuxBus == reverbAuxBus.Id &&
previousReverbLevel == reverbLevel &&
previousTransmissionLoss == transmissionLoss &&
previousRoomGameObj_AuxSendLevelToSelf == roomToneAuxSend &&
previousRoomGameObj_KeepRegistered == roomToneEvent.IsValid() &&
previousGeometryID == geometryID)
return;
#endif
var roomParams = new AkRoomParams
{
Up = transform.up,
Front = transform.forward,
ReverbAuxBus = reverbAuxBus.Id,
ReverbLevel = reverbLevel,
TransmissionLoss = transmissionLoss,
RoomGameObj_AuxSendLevelToSelf = roomToneAuxSend,
RoomGameObj_KeepRegistered = roomToneEvent.IsValid(),
};
RoomCount++;
AkSoundEngine.SetRoom(GetID(), roomParams, geometryID, name);
#if UNITY_EDITOR
previousUp = transform.up;
previousFront = transform.forward;
previousReverbAuxBus = reverbAuxBus.Id;
previousReverbLevel = reverbLevel;
previousTransmissionLoss = transmissionLoss;
previousRoomGameObj_AuxSendLevelToSelf = roomToneAuxSend;
previousRoomGameObj_KeepRegistered = roomToneEvent.IsValid();
previousGeometryID = geometryID;
#endif
/// In case a room is disabled and re-enabled.
AkRoomManager.RegisterRoomUpdate(this);
}
#if UNITY_EDITOR
private void Update()
{
if (UnityEditor.EditorApplication.isPlaying)
SetRoom();
}
#endif
private UnityEngine.Vector3 GetCapsuleScale(UnityEngine.Vector3 localScale, float radius, float height, int direction)
{
UnityEngine.Vector3 scale = new UnityEngine.Vector3();
switch (direction)
{
case 0:
scale.y = UnityEngine.Mathf.Max(localScale.y, localScale.z) * (radius * 2);
scale.z = scale.y;
scale.x = UnityEngine.Mathf.Max(scale.y, localScale.x * height);
break;
case 2:
scale.x = UnityEngine.Mathf.Max(localScale.x, localScale.y) * (radius * 2);
scale.y = scale.x;
scale.z = UnityEngine.Mathf.Max(scale.x, localScale.z * height);
break;
case 1:
default:
scale.x = UnityEngine.Mathf.Max(localScale.x, localScale.z) * (radius * 2);
scale.y = UnityEngine.Mathf.Max(scale.x, localScale.y * height);
scale.z = scale.x;
break;
}
return scale;
}
private ulong GetGeometryID()
{
ulong geometryID = AkSurfaceReflector.INVALID_GEOMETRY_ID;
AkSurfaceReflector surfaceReflector = GetComponent<AkSurfaceReflector>();
if (surfaceReflector && surfaceReflector.enabled)
geometryID = surfaceReflector.GetID();
else
{
if (roomCollider == null)
roomCollider = GetComponent<UnityEngine.Collider>();
if (roomCollider.GetType() == typeof(UnityEngine.MeshCollider))
{
geometryID = GetID();
UnityEngine.MeshCollider meshCollider = GetComponent<UnityEngine.MeshCollider>();
#if UNITY_EDITOR
if (previousColliderType == typeof(UnityEngine.MeshCollider) &&
previousMeshCollider != null &&
previousMeshCollider.sharedMesh == meshCollider.sharedMesh &&
previousPosition == transform.position &&
previousRotation == transform.rotation &&
previousScale == transform.localScale)
return geometryID;
#endif
AkSurfaceReflector.SetGeometryFromMesh(meshCollider.sharedMesh, transform, geometryID, INVALID_ROOM_ID, false, false, false);
#if UNITY_EDITOR
previousMeshCollider = meshCollider;
previousPosition = transform.position;
previousRotation = transform.rotation;
previousScale = transform.localScale;
#endif
previousColliderType = typeof(UnityEngine.MeshCollider);
}
else if (roomCollider.GetType() == typeof(UnityEngine.BoxCollider))
{
geometryID = GetID();
UnityEngine.BoxCollider boxCollider = GetComponent<UnityEngine.BoxCollider>();
#if UNITY_EDITOR
if (previousColliderType == typeof(UnityEngine.BoxCollider) &&
previousBoxCollider != null &&
previousPosition == roomCollider.bounds.center &&
previousRotation == transform.rotation &&
previousScale == new UnityEngine.Vector3(transform.localScale.x * boxCollider.size.x,
transform.localScale.y * boxCollider.size.y,
transform.localScale.z * boxCollider.size.z))
return geometryID;
#endif
UnityEngine.GameObject tempGameObject = UnityEngine.GameObject.CreatePrimitive(UnityEngine.PrimitiveType.Cube);
UnityEngine.Mesh mesh = tempGameObject.GetComponent<UnityEngine.MeshFilter>().sharedMesh;
tempGameObject.transform.position = boxCollider.bounds.center;
tempGameObject.transform.rotation = transform.rotation;
UnityEngine.Vector3 roomScale = new UnityEngine.Vector3();
roomScale.x = transform.localScale.x * boxCollider.size.x;
roomScale.y = transform.localScale.y * boxCollider.size.y;
roomScale.z = transform.localScale.z * boxCollider.size.z;
tempGameObject.transform.localScale = roomScale;
AkSurfaceReflector.SetGeometryFromMesh(mesh, tempGameObject.transform, geometryID, INVALID_ROOM_ID, false, false, false);
#if UNITY_EDITOR
previousBoxCollider = boxCollider;
previousPosition = tempGameObject.transform.position;
previousRotation = tempGameObject.transform.rotation;
previousScale = tempGameObject.transform.localScale;
#endif
previousColliderType = typeof(UnityEngine.BoxCollider);
UnityEngine.GameObject.Destroy(tempGameObject);
}
else if (roomCollider.GetType() == typeof(UnityEngine.CapsuleCollider))
{
geometryID = GetID();
UnityEngine.CapsuleCollider capsuleCollider = GetComponent<UnityEngine.CapsuleCollider>();
#if UNITY_EDITOR
if (previousColliderType == typeof(UnityEngine.CapsuleCollider) &&
previousCapsuleCollider != null &&
previousPosition == capsuleCollider.bounds.center &&
previousRotation == transform.rotation &&
previousScale == GetCapsuleScale(transform.localScale, capsuleCollider.radius, capsuleCollider.height, capsuleCollider.direction))
return geometryID;
#endif
UnityEngine.GameObject tempGameObject = UnityEngine.GameObject.CreatePrimitive(UnityEngine.PrimitiveType.Cube);
UnityEngine.Mesh mesh = tempGameObject.GetComponent<UnityEngine.MeshFilter>().sharedMesh;
tempGameObject.transform.position = capsuleCollider.bounds.center;
tempGameObject.transform.rotation = transform.rotation;
tempGameObject.transform.localScale = GetCapsuleScale(transform.localScale, capsuleCollider.radius, capsuleCollider.height, capsuleCollider.direction);
AkSurfaceReflector.SetGeometryFromMesh(mesh, tempGameObject.transform, geometryID, INVALID_ROOM_ID, false, false, false);
#if UNITY_EDITOR
previousCapsuleCollider = capsuleCollider;
previousPosition = tempGameObject.transform.position;
previousRotation = tempGameObject.transform.rotation;
previousScale = tempGameObject.transform.localScale;
#endif
previousColliderType = typeof(UnityEngine.CapsuleCollider);
UnityEngine.GameObject.Destroy(tempGameObject);
}
else if (roomCollider.GetType() == typeof(UnityEngine.SphereCollider))
{
geometryID = GetID();
#if UNITY_EDITOR
if (previousColliderType == typeof(UnityEngine.SphereCollider) &&
previousPosition == roomCollider.bounds.center &&
previousScale == roomCollider.bounds.size)
return geometryID;
#endif
UnityEngine.GameObject tempGameObject = UnityEngine.GameObject.CreatePrimitive(UnityEngine.PrimitiveType.Sphere);
UnityEngine.Mesh mesh = tempGameObject.GetComponent<UnityEngine.MeshFilter>().sharedMesh;
tempGameObject.transform.position = roomCollider.bounds.center;
tempGameObject.transform.localScale = roomCollider.bounds.size;
AkSurfaceReflector.SetGeometryFromMesh(mesh, tempGameObject.transform, geometryID, INVALID_ROOM_ID, false, false, false);
#if UNITY_EDITOR
previousColliderType = typeof(UnityEngine.SphereCollider);
previousPosition = tempGameObject.transform.position;
previousScale = tempGameObject.transform.localScale;
#endif
previousColliderType = typeof(UnityEngine.SphereCollider);
UnityEngine.GameObject.Destroy(tempGameObject);
}
else
{
if (previousColliderType == roomCollider.GetType())
return geometryID;
UnityEngine.Debug.LogWarning(name + " has an invalid collider for wet transmission. Wet Transmission will be disabled.");
// in case a geometry was added with the room's ID, remove it
if (previousColliderType == typeof(UnityEngine.MeshCollider) ||
previousColliderType == typeof(UnityEngine.BoxCollider) ||
previousColliderType == typeof(UnityEngine.SphereCollider) ||
previousColliderType == typeof(UnityEngine.CapsuleCollider))
AkSoundEngine.RemoveGeometry(GetID());
previousColliderType = roomCollider.GetType();
}
}
return geometryID;
}
public override void OnEnable()
{
roomCollider = GetComponent<UnityEngine.Collider>();
SetRoom();
// if objects entered the room while disabled, enter them now
for (var i = 0; i < roomAwareObjectsDetectedWhileDisabled.Count; ++i)
AkRoomAwareManager.ObjectEnteredRoom(roomAwareObjectsDetectedWhileDisabled[i], this);
roomAwareObjectsDetectedWhileDisabled.Clear();
base.OnEnable();
}
private void OnDisable()
{
for (var i = 0; i < roomAwareObjectsEntered.Count; ++i)
{
roomAwareObjectsEntered[i].ExitedRoom(this);
AkRoomAwareManager.RegisterRoomAwareObjectForUpdate(roomAwareObjectsEntered[i]);
roomAwareObjectsDetectedWhileDisabled.Add(roomAwareObjectsEntered[i]);
}
roomAwareObjectsEntered.Clear();
AkRoomManager.RegisterRoomUpdate(this);
// in case a geometry was added with the room's ID, remove it
if (previousColliderType == typeof(UnityEngine.MeshCollider) ||
previousColliderType == typeof(UnityEngine.BoxCollider) ||
previousColliderType == typeof(UnityEngine.SphereCollider) ||
previousColliderType == typeof(UnityEngine.CapsuleCollider))
AkSoundEngine.RemoveGeometry(GetID());
previousColliderType = null;
// stop sounds applied to the room game object
AkSoundEngine.StopAll(GetID());
RoomCount--;
AkSoundEngine.RemoveRoom(GetID());
}
private void OnTriggerEnter(UnityEngine.Collider in_other)
{
AkRoomAwareManager.ObjectEnteredRoom(in_other, this);
}
private void OnTriggerExit(UnityEngine.Collider in_other)
{
AkRoomAwareManager.ObjectExitedRoom(in_other, this);
}
public void PostRoomTone()
{
if (roomToneEvent.IsValid())
AkSoundEngine.PostEventOnRoom(roomToneEvent.Id, GetID());
}
public override void HandleEvent(UnityEngine.GameObject in_gameObject)
{
PostRoomTone();
}
public class PriorityList
{
private static readonly CompareByPriority s_compareByPriority = new CompareByPriority();
/// Contains all active rooms sorted by priority.
private System.Collections.Generic.List<AkRoom> rooms = new System.Collections.Generic.List<AkRoom>();
public ulong GetHighestPriorityActiveAndEnabledRoomID()
{
var room = GetHighestPriorityActiveAndEnabledRoom();
return room == null ? INVALID_ROOM_ID : room.GetID();
}
public AkRoom GetHighestPriorityActiveAndEnabledRoom()
{
for (int i = 0; i < rooms.Count; i++)
{
if (rooms[i].isActiveAndEnabled)
return rooms[i];
}
return null;
}
public int Count { get { return rooms.Count; } }
public void Clear()
{
rooms.Clear();
}
public void Add(AkRoom room)
{
var index = BinarySearch(room);
if (index < 0)
rooms.Insert(~index, room);
}
public void Remove(AkRoom room)
{
rooms.Remove(room);
}
public bool Contains(AkRoom room)
{
return room && rooms.Contains(room);
}
public int BinarySearch(AkRoom room)
{
return room ? rooms.BinarySearch(room, s_compareByPriority) : -1;
}
public AkRoom this[int index]
{
get { return rooms[index]; }
}
private class CompareByPriority : System.Collections.Generic.IComparer<AkRoom>
{
public virtual int Compare(AkRoom a, AkRoom b)
{
var result = a.priority.CompareTo(b.priority);
if (result == 0 && a != b)
return 1;
return -result; // inverted to have highest priority first
}
}
}
#region Obsolete
[System.Obsolete(AkSoundEngine.Deprecation_2021_1_0)]
public float wallOcclusion
{
get
{
return transmissionLoss;
}
set
{
transmissionLoss = value;
}
}
#endregion
}
#endif // #if ! (UNITY_DASHBOARD_WIDGET || UNITY_WEBPLAYER || UNITY_WII || UNITY_WIIU || UNITY_NACL || UNITY_FLASH || UNITY_BLACKBERRY) // Disable under unsupported platforms.