#if GPU_INSTANCER
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace GPUInstancer.CrowdAnimations
{
public static class GPUICrowdAPI
{
#region Crowd Animator
///
/// Start the given Animation Clip on the given instance
///
/// Character that will play the animation clip
/// Animation Clip
/// (Optional) Start time of the animation clip
/// (Optional) Speed of the playing clip
/// (Optional) Time in seconds for smooth transition from the previous animation clips
public static void StartAnimation(GPUICrowdPrefab crowdInstance, AnimationClip animationClip, float startTime = -1.0f, float speed = 1.0f, float transitionTime = 0)
{
crowdInstance.StartAnimation(animationClip, startTime, speed, transitionTime);
}
public static void StartAnimation(GPUICrowdPrefab crowdInstance, GPUIAnimationClipData clipData, float startTime = -1.0f, float speed = 1.0f, float transitionTime = 0)
{
crowdInstance.StartAnimation(clipData, startTime, speed, transitionTime);
}
///
/// Blend the given Animation Clips and start playing for the given instance
///
/// Character that will play the animation clips
/// Weights that will define the blending weights of the given animation clips
/// Clip 1
/// Clip 2
/// (Optional) Clip 3
/// (Optional) Clip 4
/// (Optional) Time of the animation clips
/// (Optional) Speed of the animation clips
/// (Optional) Time in seconds for smooth transition from the previous animation clips
public static void StartBlend(GPUICrowdPrefab crowdInstance, Vector4 animationWeights, AnimationClip animationClip1, AnimationClip animationClip2,
AnimationClip animationClip3 = null, AnimationClip animationClip4 = null, float[] animationTimes = null, float[] animationSpeeds = null, float transitionTime = 0)
{
crowdInstance.StartBlend(animationWeights, animationClip1, animationClip2, animationClip3, animationClip4, animationTimes, animationSpeeds, transitionTime);
}
///
/// Set the blend weights of the playing animation blends
///
/// Character to set the speed
/// Animation Weights
public static void SetAnimationWeights(GPUICrowdPrefab crowdInstance, Vector4 animationWeights)
{
crowdInstance.SetAnimationWeights(animationWeights);
}
///
/// Set the speed of the playing animation clips
///
/// Character to set the speed
/// Speed value
public static void SetAnimationSpeed(GPUICrowdPrefab crowdInstance, float animationSpeed)
{
crowdInstance.SetAnimationSpeed(animationSpeed);
}
///
/// Set the speeds for multiple animation clips
///
/// Character to set the speed
/// Speed values
public static void SetAnimationSpeeds(GPUICrowdPrefab crowdInstance, float[] animationSpeeds)
{
crowdInstance.SetAnimationSpeeds(animationSpeeds);
}
///
/// Returns the current time of the clip
///
/// Character to get the time
/// The clip to get the time for
public static float GetAnimationTime(GPUICrowdPrefab crowdInstance, AnimationClip animationClip)
{
return crowdInstance.GetAnimationTime(animationClip);
}
///
/// Sets the current time of the clip
///
/// Character to set the time
/// The clip to set the time for
/// Time in seconds
public static void SetAnimationTime(GPUICrowdPrefab crowdInstance, AnimationClip animationClip, float time)
{
crowdInstance.SetAnimationTime(animationClip, time);
}
///
/// Set the animation speed for all instances of the given prototype
///
/// Crowd Manager that the prototype is defined on
/// Crowd Prototype
/// Speed value
public static void SetAnimationSpeedsForPrototype(GPUICrowdManager crowdManager, GPUICrowdPrototype crowdPrototype, float animationSpeed)
{
GPUICrowdRuntimeData runtimeData = (GPUICrowdRuntimeData)crowdManager.GetRuntimeData(crowdPrototype);
if (runtimeData != null)
{
List instanceList = crowdManager.GetRegisteredPrefabsRuntimeData()[crowdPrototype];
foreach (GPUICrowdPrefab crowdInstance in instanceList)
{
crowdInstance.SetAnimationSpeed(animationSpeed);
}
}
}
///
/// Set the animation speeds for multiple clips for all instances of the given prototype
///
/// Crowd Manager that the prototype is defined on
/// Crowd Prototype
/// Speed values
public static void SetAnimationSpeedsForPrototype(GPUICrowdManager crowdManager, GPUICrowdPrototype crowdPrototype, float[] animationSpeeds)
{
GPUICrowdRuntimeData runtimeData = (GPUICrowdRuntimeData)crowdManager.GetRuntimeData(crowdPrototype);
if (runtimeData != null)
{
List instanceList = crowdManager.GetRegisteredPrefabsRuntimeData()[crowdPrototype];
foreach (GPUICrowdPrefab crowdInstance in instanceList)
{
crowdInstance.SetAnimationSpeeds(animationSpeeds);
}
}
}
///
/// Add an event to an animation clip of a prototype
///
/// Crowd Manager that the prototype is defined on
/// Crowd Prototype
/// The clip to attach the event
/// Frame of the animation on which the event will take place
/// UnityAction that will be invoked at the given frame for the given clip
/// (Optional) Float parameter value
/// (Optional) Integer parameter value
/// (Optional) String parameter value
public static void AddAnimationEvent(GPUICrowdManager crowdManager, GPUICrowdPrototype crowdPrototype, AnimationClip animationClip, int eventFrame,
UnityAction eventAction, float floatParam = 0, int intParam = 0, string stringParam = null)
{
if (!crowdManager.isInitialized)
crowdManager.InitializeRuntimeDataAndBuffers();
GPUICrowdRuntimeData runtimeData = (GPUICrowdRuntimeData)crowdManager.GetRuntimeData(crowdPrototype);
if (runtimeData != null)
{
GPUIAnimationClipData clipData;
if(runtimeData.animationClipDataDict.TryGetValue(animationClip.GetHashCode(), out clipData))
{
if (runtimeData.eventDict == null)
runtimeData.eventDict = new Dictionary>();
runtimeData.hasEvents = true;
GPUIAnimationEvent animationEvent = new GPUIAnimationEvent(crowdPrototype, animationClip);
animationEvent.eventFrame = eventFrame;
animationEvent.floatParam = floatParam;
animationEvent.intParam = intParam;
animationEvent.stringParam = stringParam;
List animationEvents;
if (!runtimeData.eventDict.TryGetValue(clipData.clipIndex, out animationEvents))
{
animationEvents = new List();
runtimeData.eventDict.Add(clipData.clipIndex, animationEvents);
}
animationEvents.Add(animationEvent);
animationEvent.AddListener(eventAction);
}
}
}
///
/// Add an event to the manager using GPUIAnimationEvent class properties
///
///
///
public static void AddAnimationEvent(GPUICrowdManager crowdManager, GPUIAnimationEvent animationEvent)
{
if (!crowdManager.isInitialized)
crowdManager.InitializeRuntimeDataAndBuffers();
GPUICrowdRuntimeData runtimeData = (GPUICrowdRuntimeData)crowdManager.GetRuntimeData(animationEvent.prototype);
if (runtimeData != null && animationEvent.animationClip != null)
{
int clipIndex = animationEvent.prototype.clipList.IndexOf(animationEvent.animationClip);
if (clipIndex >= 0)
{
if (runtimeData.eventDict == null)
runtimeData.eventDict = new Dictionary>();
runtimeData.hasEvents = true;
List animationEvents;
if (!runtimeData.eventDict.TryGetValue(clipIndex, out animationEvents))
{
animationEvents = new List();
runtimeData.eventDict.Add(clipIndex, animationEvents);
}
animationEvents.Add(animationEvent);
}
}
}
///
/// Removes all animation events for the given prototype
///
/// Crowd Manager that the prototype is defined on
/// Crowd Prototype
public static void ClearAnimationEvents(GPUICrowdManager crowdManager, GPUICrowdPrototype crowdPrototype)
{
if (crowdManager.isInitialized)
{
GPUICrowdRuntimeData runtimeData = (GPUICrowdRuntimeData)crowdManager.GetRuntimeData(crowdPrototype);
if (runtimeData != null && runtimeData.eventDict != null)
{
runtimeData.eventDict.Clear();
runtimeData.hasEvents = false;
}
}
}
#endregion Crowd Animator
///
/// Use this method to define Crowd Prototypes at runtime for procedurally generated GameObjects
///
/// The GPUI Prefab Manager that the prefab prototype will be defined on
/// GameObject to use as reference for the prototype
///
public static GPUICrowdPrototype DefineGameObjectAsCrowdPrototypeAtRuntime(GPUICrowdManager crowdManager, GameObject prototypeGameObject, GPUICrowdAnimationData animationData)
{
return crowdManager.DefineGameObjectAsCrowdPrototypeAtRuntime(prototypeGameObject, animationData);
}
///
/// Can be used to change the material of a prototype at runtime
///
/// GPUI Manager
/// GPUI Prototype
/// New material to set on the renderer
/// LOD level
/// Renderer index on the LOD level
/// Submesh index of the renderer
public static void ChangeMaterial(GPUICrowdManager crowdManager, GPUInstancerPrototype prototype, Material material, int lodLevel = 0, int rendererIndex = 0, int subMeshIndex = 0)
{
GPUICrowdRuntimeData runtimeData = (GPUICrowdRuntimeData)crowdManager.GetRuntimeData(prototype, true);
if (runtimeData == null)
return;
GPUInstancerRenderer gpuiRenderer = runtimeData.instanceLODs[lodLevel].renderers[rendererIndex];
// Generate proxy GO with a Mesh Renderer to get material property blocks
GameObject proxyGameObject = new GameObject("ProxyGO");
MeshFilter meshFilter = proxyGameObject.AddComponent();
MeshRenderer proxyRenderer = proxyGameObject.AddComponent();
// Set mesh to proxy GO
meshFilter.mesh = gpuiRenderer.mesh;
// Set new material to runtime data
gpuiRenderer.materials[subMeshIndex] = GPUInstancerConstants.gpuiSettings.shaderBindings.GetInstancedMaterial(material, GPUICrowdConstants.GPUI_EXTENSION_CODE);
// Set new material to proxy GO
proxyRenderer.materials[subMeshIndex] = material;
// Get material property blocks
proxyRenderer.GetPropertyBlock(gpuiRenderer.mpb);
if (gpuiRenderer.shadowMPB != null)
proxyRenderer.GetPropertyBlock(gpuiRenderer.shadowMPB);
// Destroy proxy GO
GameObject.Destroy(proxyGameObject);
// Setup new materials for instancing
GPUInstancerUtility.SetAppendBuffers(runtimeData);
GPUICrowdUtility.SetAppendBuffers(runtimeData);
}
}
}
#endif //GPU_INSTANCER