Added new audio banks, fix scaling for options sliders #416

Merged
srishamharan merged 2 commits from AudioImpl into main 2023-03-10 17:55:58 +08:00
108 changed files with 10468 additions and 772 deletions
Showing only changes of commit 9a39e52939 - Show all commits

View File

@ -0,0 +1,7 @@
Name: MD_RigTest01_SkinningTestAnims
ID: 203438081
Type: 12
Sub Assets:
Name: Full
ID: 231416496
Type: 13

BIN
Assets/Animation Clips/Main Normal file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,40 @@
Name: racoonAnims
ID: 201804216
Type: 12
Sub Assets:
Name: TPose
ID: 231493784
Type: 13
Name: Idle
ID: 227450439
Type: 13
Name: Run
ID: 229125027
Type: 13
Name: Pickup
ID: 219605278
Type: 13
Name: Carry_Idle
ID: 231128260
Type: 13
Name: Carry_Run
ID: 227671720
Type: 13
Name: Throw
ID: 223399345
Type: 13
Name: Sprint
ID: 228149757
Type: 13
Name: Jump_Start
ID: 223009573
Type: 13
Name: Jump_Loop
ID: 230974023
Type: 13
Name: Jump_End
ID: 228134756
Type: 13
Name: Full
ID: 223752972
Type: 13

File diff suppressed because it is too large Load Diff

View File

@ -45,18 +45,18 @@
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
Transform Component: Transform Component:
Translate: {x: 0.242245644, y: 1.56757355, z: -6.07086945} Translate: {x: 0.236000001, y: 1.56757355, z: -6.07086945}
Rotate: {x: -0, y: 0, z: -0} Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 1, y: 1, z: 1} Scale: {x: 1, y: 1, z: 1}
IsActive: true IsActive: true
Light Component: Light Component:
Position: {x: 2, y: 1.5, z: -5.5999999} Position: {x: 2, y: 1.5, z: -5.5999999}
Type: Directional Type: Directional
Direction: {x: 0, y: 0, z: -1} Direction: {x: -0.0780000016, y: 0.159999996, z: -1}
Color: {x: 0, y: 0, z: 0, w: 1} Color: {x: 0, y: 0, z: 0, w: 1}
Layer: 4294967295 Layer: 4294967295
Strength: 1 Strength: 1
Casting Shadows: false Casting Shadows: true
IsActive: true IsActive: true
Scripts: ~ Scripts: ~
- EID: 240 - EID: 240
@ -7530,7 +7530,7 @@
Components: Components:
Transform Component: Transform Component:
Translate: {x: 2, y: 0, z: 0} Translate: {x: 2, y: 0, z: 0}
Rotate: {x: -0, y: 0, z: 0} Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 1, y: 1, z: 1} Scale: {x: 1, y: 1, z: 1}
IsActive: true IsActive: true
Renderable Component: Renderable Component:
@ -14257,3 +14257,30 @@
FOV: 90 FOV: 90
IsActive: true IsActive: true
Scripts: ~ Scripts: ~
- EID: 537
Name: ShadowFixRoof
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: -0.0146873593, y: 2.83242893, z: 0}
Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 5.15999985, y: 5.15999985, z: 5.15999985}
IsActive: true
Renderable Component:
Mesh: 142812576
Material: 127069936
IsActive: true
Collider Component:
Colliders:
- Is Trigger: false
Collision Tag: 0
Type: Box
Half Extents: {x: 2, y: 0.0500000007, z: 2}
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: -0.00999999978, z: 0}
Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true
Scripts: ~

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,7 @@
NumberOfChildren: 1 NumberOfChildren: 1
Components: Components:
Transform Component: Transform Component:
Translate: {x: 0, y: 0.189419448, z: 0} Translate: {x: 0, y: 0.201105013, z: 0}
Rotate: {x: 0.00523597933, y: -2.96353412, z: -6.40293041e-10} Rotate: {x: 0.00523597933, y: -2.96353412, z: -6.40293041e-10}
Scale: {x: 1.00000191, y: 1, z: 1.00000191} Scale: {x: 1.00000191, y: 1, z: 1.00000191}
IsActive: true IsActive: true
@ -41,9 +41,9 @@
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
Transform Component: Transform Component:
Translate: {x: 0.006237939, y: -0.000393368304, z: 0} Translate: {x: 0.00623797067, y: -0.000395311916, z: -2.03726813e-08}
Rotate: {x: -0, y: 2.79945588, z: 0} Rotate: {x: 1.35041773e-08, y: 2.79945588, z: -9.6043955e-09}
Scale: {x: 1.0000881, y: 1, z: 1.0000881} Scale: {x: 1.00008798, y: 1, z: 1.0000881}
IsActive: true IsActive: true
Renderable Component: Renderable Component:
Mesh: 144838771 Mesh: 144838771
@ -67,6 +67,7 @@
Color: {x: 1, y: 1, z: 1, w: 1} Color: {x: 1, y: 1, z: 1, w: 1}
Layer: 4294967295 Layer: 4294967295
Strength: 0 Strength: 0
Casting Shadows: false
IsActive: true IsActive: true
Scripts: ~ Scripts: ~
- EID: 4 - EID: 4
@ -81,6 +82,7 @@
Color: {x: 1, y: 1, z: 1, w: 1} Color: {x: 1, y: 1, z: 1, w: 1}
Layer: 4294967295 Layer: 4294967295
Strength: 0.600000024 Strength: 0.600000024
Casting Shadows: false
IsActive: true IsActive: true
Scripts: ~ Scripts: ~
- EID: 5 - EID: 5
@ -98,3 +100,49 @@
Material: 124370424 Material: 124370424
IsActive: true IsActive: true
Scripts: ~ Scripts: ~
- EID: 6
Name: TrajectoryTest
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: -3.39616156, y: 3.66783714, z: -0.722039163}
Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 1, y: 1, z: 1}
IsActive: true
RigidBody Component:
Type: Dynamic
Drag: 0.00999999978
Angular Drag: 0.100000001
Gravity Scale: 1
Use Gravity: true
Interpolate: true
Sleeping Enabled: false
Freeze Position X: false
Freeze Position Y: false
Freeze Position Z: false
Freeze Rotation X: false
Freeze Rotation Y: false
Freeze Rotation Z: false
IsActive: true
Collider Component:
Colliders:
- Is Trigger: false
Collision Tag: 0
Type: Sphere
Radius: 1
Friction: 0.400000006
Bounciness: 0
Density: 1
Position Offset: {x: 0, y: 0, z: 0}
Rotation Offset: {x: 0, y: 0, z: 0}
IsActive: true
Trajectory Renderer Component:
Mesh: 134305891
Start Color: {x: 1, y: 0.951541781, z: 0}
Start Alpha: 1
End Color: {x: 0, y: 1, z: 0.748898745}
End Alpha: 1
"Color Eval Rate ": 0.192000002
IsActive: true
Scripts: ~

View File

@ -10,6 +10,7 @@
Color: {x: 1, y: 1, z: 1, w: 1} Color: {x: 1, y: 1, z: 1, w: 1}
Layer: 4294967295 Layer: 4294967295
Strength: 1 Strength: 1
Casting Shadows: false
IsActive: true IsActive: true
Scripts: ~ Scripts: ~
- EID: 2 - EID: 2
@ -18,16 +19,66 @@
NumberOfChildren: 0 NumberOfChildren: 0
Components: Components:
Transform Component: Transform Component:
Translate: {x: 0, y: 0, z: 0} Translate: {x: -0.291508496, y: 0, z: 0}
Rotate: {x: 0, y: 0, z: 0} Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 1, y: 1, z: 1} Scale: {x: 1, y: 1, z: 1}
IsActive: true IsActive: true
Renderable Component: Renderable Component:
Mesh: 148542784 Mesh: 149697411
Material: 121518381 Material: 128805346
IsActive: true IsActive: true
Animator Component: Animator Component:
Rig: 76586906 Rig: 77816045
Clip: 76586906 AnimationController: 0
IsActive: true
Scripts:
- Type: SHADE.Test.AnimTest
Enabled: true
fullClip: 223752972
idleClip: 227450439
runClip: 229125027
pickUpClip: 219605278
controlAniSys: true
- EID: 1
Name: Default
IsActive: true
NumberOfChildren: 0
Components:
Camera Component:
Position: {x: 0, y: 0.5, z: 0.699999988}
Pitch: 0
Yaw: 0
Roll: 0
Width: 1920
Near: 0.00999999978
Far: 10000
Perspective: true
FOV: 90
IsActive: true IsActive: true
Scripts: ~ Scripts: ~
- EID: 3
Name: Leg
IsActive: true
NumberOfChildren: 0
Components:
Transform Component:
Translate: {x: 0.332949668, y: 0, z: 0}
Rotate: {x: -0, y: 0, z: -0}
Scale: {x: 0.0710000023, y: 0.0710000023, z: 0.0710000023}
IsActive: true
Renderable Component:
Mesh: 141097368
Material: 128805346
IsActive: true
Animator Component:
Rig: 72178939
AnimationController: 0
IsActive: true
Scripts:
- Type: SHADE.Test.AnimTest
Enabled: true
fullClip: 231416496
idleClip: 0
runClip: 0
pickUpClip: 0
controlAniSys: false

View File

@ -0,0 +1,67 @@
using System;
namespace SHADE.Test
{
public class AnimTest : Script
{
#region Serialized Fields
[SerializeField]
private AnimationClipAsset fullClip;
[SerializeField]
private AnimationClipAsset idleClip;
[SerializeField]
private AnimationClipAsset runClip;
[SerializeField]
private AnimationClipAsset pickUpClip;
[SerializeField]
private bool controlAniSys = false;
#endregion
#region Components
public Animator Animator { get; private set; }
#endregion
#region Lifecycle Functions
protected override void awake()
{
Animator = GetComponent<Animator>();
}
protected override void update()
{
// Play loop if shift is held
Action<AnimationClipAsset> playFunc = Input.GetKey(Input.KeyCode.LeftShift) ? (x) => Animator.Play(x)
: (x) => Animator.PlayOneShot(x);
// Play animations
if (Input.GetKeyUp(Input.KeyCode.Equals))
{
if (fullClip)
playFunc(fullClip);
}
else if (Input.GetKeyUp(Input.KeyCode.Alpha1))
{
if (idleClip)
playFunc(idleClip);
}
else if (Input.GetKeyUp(Input.KeyCode.Alpha2))
{
if (runClip)
playFunc(runClip);
}
else if (Input.GetKeyUp(Input.KeyCode.Alpha3))
{
if (pickUpClip)
playFunc(pickUpClip);
}
// Play and pause
if (controlAniSys && Input.GetKeyUp(Input.KeyCode.Space))
{
AnimationSystem.TimeScale = AnimationSystem.TimeScale > 0.0f ? 0.0f
: AnimationSystem.DefaultTimeScale;
}
}
#endregion
}
}

View File

@ -0,0 +1,3 @@
Name: AnimTest
ID: 165676130
Type: 9

View File

@ -156,7 +156,7 @@ public partial class LeafSearch : BehaviourTreeNode
//Draw a ray, succeed if ray is unobstructed //Draw a ray, succeed if ray is unobstructed
Vector3 eyePosition = transform.GlobalPosition + eyeOffset; Vector3 eyePosition = transform.GlobalPosition + eyeOffset;
BoxCollider playerCollider = player.GetValueOrDefault().GetComponent<Collider>().GetCollisionShape<BoxCollider>(0); Collider playerCollider = player.GetValueOrDefault().GetComponent<Collider>();
if (playerCollider == null) if (playerCollider == null)
{ {
//Debug.Log("Failure: Player has no collider"); //Debug.Log("Failure: Player has no collider");
@ -167,7 +167,7 @@ public partial class LeafSearch : BehaviourTreeNode
} }
//Ray destination to target the centre of the player's collider instead of transform position //Ray destination to target the centre of the player's collider instead of transform position
//Since transform position is often the raccoon's base and the ray needs to hit somewhere higher to be more reliable //Since transform position is often the raccoon's base and the ray needs to hit somewhere higher to be more reliable
Vector3 rayDestination = plrT.GlobalPosition + plrT.GlobalScale * playerCollider.PositionOffset; Vector3 rayDestination = plrT.GlobalPosition + plrT.GlobalScale * playerCollider.GetCollisionShape(0).PositionOffset;
Ray sightRay = new Ray(eyePosition, rayDestination - eyePosition); Ray sightRay = new Ray(eyePosition, rayDestination - eyePosition);
RaycastHit sightRayHit = Physics.Raycast(sightRay, false, (ushort)65535)[0]; RaycastHit sightRayHit = Physics.Raycast(sightRay, false, (ushort)65535)[0];
//As of November 2022, RaycastHit contains only the FIRST object hit by //As of November 2022, RaycastHit contains only the FIRST object hit by

View File

@ -86,12 +86,17 @@ public class Item : Script
if (returnBack && !dontReturn) if (returnBack && !dontReturn)
{ {
if (rb)
{
rb.LinearVelocity = Vector3.Zero;
rb.AngularVelocity = Vector3.Zero;
rb.ClearForces();
rb.ClearTorque();
}
if(transform) if(transform)
transform.LocalPosition = firstPostion; transform.LocalPosition = firstPostion;
if (rb)
rb.LinearVelocity = Vector3.Zero;
returnBack = false; returnBack = false;
} }

View File

@ -3,13 +3,28 @@ using System;
public class PlayerIdleState : BaseState public class PlayerIdleState : BaseState
{ {
public PlayerIdleState(StateMachine stateMachine) : base(stateMachine) private bool holdItem;
public PlayerIdleState(StateMachine stateMachine, bool hi) : base(stateMachine)
{ {
stateName = "Idle State"; stateName = "Idle State";
holdItem = hi;
} }
public override void OnEnter() public override void OnEnter()
{ {
//Debug.Log("WALK ENTER"); //Debug.Log("WALK ENTER");
if (PlayerAnimations.Instance)
{
if (!holdItem)
{
PlayerAnimations.Instance.playerAnimator.Play(PlayerAnimations.Instance.playerIdleClip);
PlayerAnimations.Instance.BagAnimator.Play(PlayerAnimations.Instance.playerIdleClip);
}
else
{
PlayerAnimations.Instance.playerAnimator.Play(PlayerAnimations.Instance.playerCarryIdleClip);
PlayerAnimations.Instance.BagAnimator.Play(PlayerAnimations.Instance.playerCarryIdleClip);
}
}
} }
public override void update() public override void update()
{ {

View File

@ -1,4 +1,5 @@
using SHADE; using SHADE;
using SHADE_Scripting.Audio;
using System; using System;
public class PlayerRunState : BaseState public class PlayerRunState : BaseState
@ -13,6 +14,11 @@ public class PlayerRunState : BaseState
public override void OnEnter() public override void OnEnter()
{ {
//Debug.Log("WALK ENTER"); //Debug.Log("WALK ENTER");
if (PlayerAnimations.Instance)
{
PlayerAnimations.Instance.playerAnimator.Play(PlayerAnimations.Instance.playerRunClip);
PlayerAnimations.Instance.BagAnimator.Play(PlayerAnimations.Instance.playerRunClip);
}
} }
public override void update() public override void update()
{ {
@ -21,7 +27,7 @@ public class PlayerRunState : BaseState
if (timer > delay) if (timer > delay)
{ {
Audio.PlaySFXOnce2D("event:/Raccoon/raccoon_footsteps"); AudioHandler.audioClipHandlers["footsteps"].Play();
timer = 0; timer = 0;
} }
} }

View File

@ -1,18 +1,38 @@
using SHADE; using SHADE;
using SHADE_Scripting.Audio;
using System; using System;
public class PlayerWalkState : BaseState public class PlayerWalkState : BaseState
{ {
private float timer; private float timer;
private float delay = 0.5f; private float delay = 0.5f;
public PlayerWalkState(StateMachine stateMachine) : base(stateMachine) private bool holdItem;
public PlayerWalkState(StateMachine stateMachine, bool hi) : base(stateMachine)
{ {
stateName = "Walk State"; stateName = "Walk State";
holdItem = hi;
} }
public override void OnEnter() public override void OnEnter()
{ {
//Debug.Log("WALK ENTER"); //Debug.Log("WALK ENTER");
timer = delay; timer = delay;
if (PlayerAnimations.Instance)
{
if (!holdItem)
{
if(PlayerAnimations.Instance.playerWalkClip)
PlayerAnimations.Instance.playerAnimator.Play(PlayerAnimations.Instance.playerWalkClip);
if(PlayerAnimations.Instance.playerWalkClip)
PlayerAnimations.Instance.BagAnimator.Play(PlayerAnimations.Instance.playerWalkClip);
}
else
{
if(PlayerAnimations.Instance.playerCarryWalkClip)
PlayerAnimations.Instance.playerAnimator.Play(PlayerAnimations.Instance.playerCarryWalkClip);
if(PlayerAnimations.Instance.playerCarryWalkClip)
PlayerAnimations.Instance.BagAnimator.Play(PlayerAnimations.Instance.playerCarryWalkClip);
}
}
} }
public override void update() public override void update()
{ {
@ -21,7 +41,7 @@ public class PlayerWalkState : BaseState
if (timer > delay) if (timer > delay)
{ {
Audio.PlaySFXOnce2D("event:/Raccoon/raccoon_footsteps"); AudioHandler.audioClipHandlers["footsteps"].Play();
timer = 0; timer = 0;
} }
} }

View File

@ -0,0 +1,81 @@
using SHADE;
using System;
using System.Collections.Generic;
public class PlayerAnimations : Script
{
#region Raccoon
[SerializeField]
public AnimationClipAsset playerIdleClip; // done
[SerializeField]
public AnimationClipAsset playerWalkClip; // done
[SerializeField]
public AnimationClipAsset playerRunClip; // done
[SerializeField]
public AnimationClipAsset playerPickUpClip;
[SerializeField]
public AnimationClipAsset playerCarryIdleClip; // done
[SerializeField]
public AnimationClipAsset playerCarryWalkClip; // done
[SerializeField]
public AnimationClipAsset playerThrowClip;
[SerializeField]
public AnimationClipAsset playerJumpStartClip;
[SerializeField]
public AnimationClipAsset playerJumpLoopClip;
[SerializeField]
public AnimationClipAsset playerJumpEndClip;
#endregion
#region Animator
public Animator playerAnimator { get; private set; }
public Animator BagAnimator { get; private set; }
public Animator silhoPlayerAnimator { get; private set; }
public Animator silhoBagAnimator { get; private set; }
#endregion
#region silhouette
public GameObject silhouettePlayer;
public GameObject silhouetteBag;
#endregion
public static PlayerAnimations Instance { get; private set; }
protected override void awake()
{
if (Instance != null && Instance != this)
RemoveScript<PlayerAnimations>();
else
Instance = this;
playerAnimator = GetComponent<Animator>();
if (!playerAnimator)
Debug.LogError("Player Animator is MISSING!");
BagAnimator = GetComponentInChildren<Animator>();
if (!BagAnimator)
Debug.LogError("Bag Animator is MISSING!");
if(!silhouettePlayer)
silhoPlayerAnimator = silhouettePlayer.GetComponent<Animator>();
else
Debug.LogError("Silho Player is MISSING!");
if (!silhoPlayerAnimator)
Debug.LogError("Silho Player Animator is MISSING!");
if(!silhouetteBag)
silhoBagAnimator = silhouetteBag.GetComponent<Animator>();
else
Debug.LogError("Silho bag is MISSING!");
if (!silhoBagAnimator)
Debug.LogError("Silho Player Animator is MISSING!");
}
protected override void onDestroy()
{
if (Instance == this)
Instance = null;
}
}

View File

@ -0,0 +1,3 @@
Name: SC_PlayerAnimations
ID: 159045981
Type: 9

View File

@ -1,6 +1,7 @@
using SHADE; using SHADE;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using SHADE_Scripting.Audio;
using static Item; using static Item;
public class PlayerController : Script public class PlayerController : Script
@ -32,7 +33,7 @@ public class PlayerController : Script
private float delayTimer = 0.0f; private float delayTimer = 0.0f;
[Tooltip("The current state fo the raccoon")] [Tooltip("The current state fo the raccoon")]
public RaccoonStates currentState = RaccoonStates.IDLE; public RaccoonStates currentState;
//Movement variables============================================================ //Movement variables============================================================
[Tooltip("Max vel for walking")] [Tooltip("Max vel for walking")]
@ -98,17 +99,17 @@ public class PlayerController : Script
//rigidbody check //rigidbody check
rb = GetComponent<RigidBody>(); rb = GetComponent<RigidBody>();
if (!rb) if (!rb)
Debug.LogError("RigidBody is NULL!"); Debug.LogError("RigidBody is MISSING!");
//Transform check //Transform check
tranform = GetComponent<Transform>(); tranform = GetComponent<Transform>();
if(!tranform) if(!tranform)
Debug.LogError("tranform is NULL!"); Debug.LogError("tranform is MISSING!");
stateMachine = AddScript<StateMachine>(); stateMachine = AddScript<StateMachine>();
Dictionary<Type, BaseState> dictionary = new Dictionary<Type, BaseState>(); Dictionary<Type, BaseState> dictionary = new Dictionary<Type, BaseState>();
dictionary.Add(typeof(PlayerIdleState), new PlayerIdleState(stateMachine)); dictionary.Add(typeof(PlayerIdleState), new PlayerIdleState(stateMachine, holdItem));
dictionary.Add(typeof(PlayerWalkState), new PlayerWalkState(stateMachine)); dictionary.Add(typeof(PlayerWalkState), new PlayerWalkState(stateMachine, holdItem));
dictionary.Add(typeof(PlayerRunState), new PlayerRunState(stateMachine)); dictionary.Add(typeof(PlayerRunState), new PlayerRunState(stateMachine));
dictionary.Add(typeof(PlayerJumpState), new PlayerJumpState(stateMachine)); dictionary.Add(typeof(PlayerJumpState), new PlayerJumpState(stateMachine));
dictionary.Add(typeof(PlayerFallState), new PlayerFallState(stateMachine)); dictionary.Add(typeof(PlayerFallState), new PlayerFallState(stateMachine));
@ -131,6 +132,14 @@ public class PlayerController : Script
silhouetteBagRend = silhouetteBag.GetComponent<Renderable>(); silhouetteBagRend = silhouetteBag.GetComponent<Renderable>();
silhouetteBagRend.Material.SetProperty<float>("data.offset", 0.1f); silhouetteBagRend.Material.SetProperty<float>("data.offset", 0.1f);
} }
AudioHandler.audioClipHandlers["footsteps"] = Audio.CreateAudioClip("event:/Raccoon/raccoon_footsteps");
}
protected override void start()
{
currentState = RaccoonStates.IDLE;
stateMachine.SetState(typeof(PlayerIdleState));
} }
protected override void lateUpdate() protected override void lateUpdate()

View File

@ -50,6 +50,7 @@ public class PauseMenu : Script
if (canvas) if (canvas)
canvas.SetActive(false); canvas.SetActive(false);
Application.FixDeltaTime = Time.DefaultFixDeltaTime; Application.FixDeltaTime = Time.DefaultFixDeltaTime;
AnimationSystem.TimeScale = AnimationSystem.DefaultTimeScale;
} }
}); });
} }
@ -106,6 +107,7 @@ public class PauseMenu : Script
if (canvas) if (canvas)
canvas.SetActive(true); canvas.SetActive(true);
Application.FixDeltaTime = 0; Application.FixDeltaTime = 0;
AnimationSystem.TimeScale = 0;
} }
} }

View File

@ -15,17 +15,14 @@ public abstract class BaseState
} }
public virtual void OnEnter() public virtual void OnEnter()
{ {}
}
public abstract void update(); public abstract void update();
public abstract void fixedUpdate(); public abstract void fixedUpdate();
public virtual void OnExit() public virtual void OnExit()
{ {}
}
public string GetStateName() public string GetStateName()
{ {
@ -37,11 +34,6 @@ public abstract class BaseState
return animationName; return animationName;
} }
public virtual float GetAnimPercent()
{
return 1.0f;
}
public virtual void onCollisionEnter(CollisionInfo info) public virtual void onCollisionEnter(CollisionInfo info)
{ {
} }

View File

@ -1,4 +1,5 @@
#version 450 #version 450
#extension GL_EXT_nonuniform_qualifier : require
struct DirectionalLightStruct struct DirectionalLightStruct
{ {
@ -63,8 +64,6 @@ float CalcShadowValue (sampler2D shadowMap, vec4 worldSpaceFragPos, mat4 lightPV
// Perform perspective division and convert to 0 to 1 range // Perform perspective division and convert to 0 to 1 range
vec3 converted = (fragPosLightPOV.xyz / fragPosLightPOV.w) * vec3(0.5f) + vec3(0.5f); vec3 converted = (fragPosLightPOV.xyz / fragPosLightPOV.w) * vec3(0.5f) + vec3(0.5f);
// float sampledDepth = texture(shadowMap, converted.xy).r;
// float sampledDepth = texture(shadowMap, converted.xy).z;
vec2 moments = texture(shadowMap, converted.xy).xy; vec2 moments = texture(shadowMap, converted.xy).xy;
if (converted.x < 0.0f || converted.x > 1.0f || converted.y < 0.0f || converted.y > 1.0f) if (converted.x < 0.0f || converted.x > 1.0f || converted.y < 0.0f || converted.y > 1.0f)
@ -74,9 +73,12 @@ float CalcShadowValue (sampler2D shadowMap, vec4 worldSpaceFragPos, mat4 lightPV
float worldNormalDotLight = dot (normalize (worldNormal), normalize(lightDir)); float worldNormalDotLight = dot (normalize (worldNormal), normalize(lightDir));
if (worldNormalDotLight < 0.0f) if (worldNormalDotLight <= 0.0f)
return 0.7f; return 0.7f;
// if (worldNormalDotLight <= 0.01f)
// return 0.7f;
if (fragPosLightPOV.z > moments.x && fragPosLightPOV.w > 0.0f) if (fragPosLightPOV.z > moments.x && fragPosLightPOV.w > 0.0f)
{ {
float p = step (fragPosLightPOV.z, moments.x); float p = step (fragPosLightPOV.z, moments.x);
@ -95,6 +97,7 @@ float CalcShadowValue (sampler2D shadowMap, vec4 worldSpaceFragPos, mat4 lightPV
return 0.0f; return 0.0f;
} }
// return min (worldNormalDotLight + 0.7f, 1.0f);
return 1.0f; return 1.0f;
} }
@ -121,18 +124,21 @@ void main()
// light layer index // light layer index
uint lightLayer = lightLayerAndNormal.x; uint lightLayer = lightLayerAndNormal.x;
// Normals are stored in 2 32-bit uints (only first 48 bits are used) where they can be unpacked in 3 floats so we unpack them here.
vec3 worldNormal = vec3 (unpackHalf2x16 (lightLayerAndNormal.y).xy, unpackHalf2x16 (lightLayerAndNormal.z).x); vec3 worldNormal = vec3 (unpackHalf2x16 (lightLayerAndNormal.y).xy, unpackHalf2x16 (lightLayerAndNormal.z).x);
vec3 fragColor = vec3 (0.0f); vec3 fragColor = vec3 (0.0f);
vec4 shadowMapColor = vec4 (1.0f); vec4 shadowMapColor = vec4 (1.0f);
// Shadow multiplier
float shadowValue = 1.0f;
for (int i = 0; i < lightCounts.ambientLights; ++i) for (int i = 0; i < lightCounts.ambientLights; ++i)
{ {
if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0) if ((lightLayer & AmbLightData.aLightData[i].cullingMask) != 0)
{ {
// Just do some add // Just do some add
//fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (0.5f);
fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength); fragColor += pixelDiffuse.rgb * AmbLightData.aLightData[i].ambientColor.rgb * vec3 (AmbLightData.aLightData[i].strength);
} }
} }
@ -153,12 +159,16 @@ void main()
// If the shadow map is enabled (test the bit) // If the shadow map is enabled (test the bit)
if ((DirLightData.dLightData[i].shadowData & uint(1)) == 1) if ((DirLightData.dLightData[i].shadowData & uint(1)) == 1)
{ {
// calculate shadow map here uint shadowMapIndex = (DirLightData.dLightData[i].shadowData >> 8);
fragColor.rgb *= CalcShadowValue (shadowMaps[0], positionWorld, DirLightData.dLightData[i].pvMatrix, worldNormal, DirLightData.dLightData[i].directionWorld.xyz).xxx; shadowValue = min (shadowValue, CalcShadowValue (shadowMaps[nonuniformEXT(shadowMapIndex)], positionWorld, DirLightData.dLightData[i].pvMatrix, worldNormal, DirLightData.dLightData[i].directionWorld.xyz));
} }
} }
} }
// calculate shadow map here
if (shadowValue != 0.0f)
fragColor.rgb *= shadowValue;
float ssaoVal = imageLoad (ssaoBlurredImage, globalThread).r; float ssaoVal = imageLoad (ssaoBlurredImage, globalThread).r;
fragColor *= ssaoVal; fragColor *= ssaoVal;
@ -167,12 +177,4 @@ void main()
// store result into result image // store result into result image
imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f)); imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), vec4(fragColor.rgb, 1.0f));
// vec2 normTexCoords = vec2 (gl_GlobalInvocationID.xy) / vec2 (1024.0f);
// vec4 shadowMapVal = texture(shadowMaps[0], normTexCoords);
// if (normTexCoords.x > 1.0f || normTexCoords.y > 1.0f)
// shadowMapVal = vec4(0.0f);
// imageStore(targetImage, ivec2(gl_GlobalInvocationID.xy), shadowMapVal.xxxx);
} }

View File

@ -77,7 +77,7 @@ void main()
worldSpacePosition = In.worldPos; worldSpacePosition = In.worldPos;
outEntityID = In2.eid; outEntityID = In2.eid;
lightLayerIndices = uvec4 (In2.lightLayerIndex, 0, 0, 1); lightLayerIndices = uvec4 (In2.lightLayerIndex, packHalf2x16 (In.worldNormal.xy), packHalf2x16 (vec2 (In.worldNormal.z, 1.0f)), 1);
// float vpHeight = float (In2.screenSpacePos.y) - MatProp.data[In2.materialIndex].highlightPosition; // float vpHeight = float (In2.screenSpacePos.y) - MatProp.data[In2.materialIndex].highlightPosition;
// bring the frame of reference to the object's screen space pos // bring the frame of reference to the object's screen space pos

View File

@ -24,7 +24,7 @@ echo "Q - vswhere"
echo --------------------------------------------------- echo ---------------------------------------------------
echo. echo.
choice /C ABCDEFGHIJKLMNOPQ /T 10 /D A choice /C ABCDEFGHIJKLMNOPQ
set _e=%ERRORLEVEL% set _e=%ERRORLEVEL%
if %_e%==1 goto VMA if %_e%==1 goto VMA

View File

@ -179,6 +179,9 @@ namespace Sandbox
// Link up SHDebugDraw // Link up SHDebugDraw
SHDebugDraw::Init(SHSystemManager::GetSystem<SHDebugDrawSystem>()); SHDebugDraw::Init(SHSystemManager::GetSystem<SHDebugDrawSystem>());
auto clip = SHResourceManager::LoadOrGet<SHRawAnimation>(77816045);
auto rig = SHResourceManager::LoadOrGet<SHRig>(77816045);
} }
void SBApplication::Update(void) void SBApplication::Update(void)

View File

@ -2,10 +2,10 @@
\file SHAnimationClip.cpp \file SHAnimationClip.cpp
\author Tng Kah Wei, kahwei.tng, 390009620 \author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu \par email: kahwei.tng\@digipen.edu
\date Nov 20, 2022 \date Feb 27, 2023
\brief Contains the function definitions of the SHAnimationClip class. \brief Contains the function definitions of the SHAnimationClip class.
Copyright (C) 2022 DigiPen Institute of Technology. Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited. of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/ *//*************************************************************************************/
@ -13,61 +13,26 @@ of DigiPen Institute of Technology is prohibited.
#include "SHpch.h" #include "SHpch.h"
// Primary Header // Primary Header
#include "SHAnimationClip.h" #include "SHAnimationClip.h"
#include "SHRawAnimation.h"
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
SHAnimationClip::SHAnimationClip(const SHAnimAsset& asset) SHAnimationClip::SHAnimationClip(Handle<SHRawAnimation> rawAnimHandle, int firstFrame, int lastFrame)
: rawAnim { rawAnimHandle }
, startFrameIndex { firstFrame }
, endFrameIndex { lastFrame }
, duration { 0.0f }
, startTimeStamp { 0.0f }
{ {
// Populate keyframes if (!rawAnim)
int maxFrames = 0; return;
totalTime = 0.0f;
for (const auto& channel : asset.nodeChannels)
{
// Create a channel
Channel newChannel;
newChannel.PositionKeyFrames.reserve(channel.positionKeys.size());
newChannel.RotationKeyFrames.reserve(channel.rotationKeys.size());
newChannel.ScaleKeyFrames.reserve(channel.scaleKeys.size());
// Populate Keyframes const float SECS_PER_TICK = 1.0f / static_cast<float>(rawAnim->GetTicksPerSecond());
for (const auto& posKey : channel.positionKeys) const int ONE_PAST_LAST_FRAME = lastFrame + 1;
{ duration = static_cast<float>(ONE_PAST_LAST_FRAME - firstFrame) * SECS_PER_TICK;
newChannel.PositionKeyFrames.emplace_back(SHAnimationKeyFrame<SHVec3>{ posKey.time, posKey.value}); startTimeStamp = static_cast<float>(firstFrame) * SECS_PER_TICK;
}
for (const auto& rotKey : channel.rotationKeys)
{
newChannel.RotationKeyFrames.emplace_back(SHAnimationKeyFrame<SHQuaternion>{ rotKey.time, rotKey.value});
}
for (const auto& scaleKey : channel.scaleKeys)
{
newChannel.ScaleKeyFrames.emplace_back(SHAnimationKeyFrame<SHVec3>{ scaleKey.time, scaleKey.value });
}
newChannel.MaxFrames = std::max({ newChannel.PositionKeyFrames.size(), newChannel.RotationKeyFrames.size(), newChannel.ScaleKeyFrames.size() });
// Compute max frames
maxFrames = std::max(maxFrames, newChannel.MaxFrames);
// Compute total time
totalTime = std::max({ totalTime, newChannel.PositionKeyFrames.back().TimeStamp, newChannel.RotationKeyFrames.back().TimeStamp, newChannel.ScaleKeyFrames.back().TimeStamp });
// Insert the channel
channels.emplace_back(std::move(newChannel));
}
// Compute fps
ticksPerSecond = static_cast<int>(maxFrames / totalTime);
} }
/*-----------------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
} }

View File

@ -2,10 +2,10 @@
\file SHAnimationClip.h \file SHAnimationClip.h
\author Tng Kah Wei, kahwei.tng, 390009620 \author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu \par email: kahwei.tng\@digipen.edu
\date Dec 12, 2022 \date Feb 27, 2023
\brief Contains the definition of the SHAnimationClip struct and related types. \brief Contains the definition of the SHAnimationClip struct and related types.
Copyright (C) 2022 DigiPen Institute of Technology. Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited. of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/ *//*************************************************************************************/
@ -14,71 +14,52 @@ of DigiPen Institute of Technology is prohibited.
// Project Includes // Project Includes
#include "SH_API.h" #include "SH_API.h"
#include "Math/SHMatrix.h" #include "Math/SHMatrix.h"
#include "Assets/Asset Types/Models/SHAnimationAsset.h" #include "Resource/SHHandle.h"
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHRawAnimation;
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Defines a single key frame in an animation for a specific type of data. /// Represents a snippet of 3D animation that is stored in a SHRawAnimation object.
/// </summary>
template<typename T>
struct SHAnimationKeyFrame
{
float TimeStamp;
T Data;
};
/// <summary>
/// Represents a animation clip of a 3D animation that is made for a specific model
/// rig.
/// </summary> /// </summary>
class SH_API SHAnimationClip class SH_API SHAnimationClip
{ {
public: public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Defines the animations of a single bone in a rig.
/// </summary>
struct Channel
{
std::vector<SHAnimationKeyFrame<SHVec3>> PositionKeyFrames;
std::vector<SHAnimationKeyFrame<SHQuaternion>> RotationKeyFrames;
std::vector<SHAnimationKeyFrame<SHVec3>> ScaleKeyFrames;
int MaxFrames;
};
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Constructs an SHAnimation Clip from a specified SHAnimAsset. /// Constructs an animation clip that contains the following parameters.
/// </summary> /// </summary>
/// <param name="asset">Animation asset to load.</param> /// <param name="rawAnimHandle">Handle to the raw animation data.</param>
explicit SHAnimationClip(const SHAnimAsset& asset); /// <param name="firstFrame">First frame to be played.</param>
/// <param name="lastFrame">Last frame to be played.</param>
SHAnimationClip(Handle<SHRawAnimation> rawAnimHandle, int firstFrame, int lastFrame);
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
const std::vector<Channel>& GetChannels() const noexcept { return channels; } inline Handle<SHRawAnimation> GetRawAnimation() const noexcept { return rawAnim; }
int GetTicksPerSecond() const noexcept { return ticksPerSecond; } inline int GetStartFrameIndex() const noexcept { return startFrameIndex; }
float GetTotalTime() const noexcept { return totalTime; } inline int GetEndFrameIndex() const noexcept { return endFrameIndex; }
inline float GetTotalDuration() const noexcept { return duration; }
inline float GetStartTimeStamp() const noexcept { return startTimeStamp; }
private: private:
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
std::vector<Channel> channels; Handle<SHRawAnimation> rawAnim;
int ticksPerSecond; int startFrameIndex; // First Frame
float totalTime; int endFrameIndex; // Last Frame (inclusive)
float duration; // Total playback time
/*---------------------------------------------------------------------------------*/ float startTimeStamp; // Starting time stamp of the raw anim
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
}; };
} }

View File

@ -0,0 +1,228 @@
/************************************************************************************//*!
\file SHAnimationController.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Feb 22, 2023
\brief Contains the definition of SHAnimationController's functions.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#include "SHpch.h"
#include "SHAnimationController.h"
#include "SHAnimationSystem.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "SHAnimationClip.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* AnimParam Functions */
/*-----------------------------------------------------------------------------------*/
SHAnimationController::AnimParam::AnimParam(Type type)
: ParamType { type }
, Value { 0.0f }
{}
/*-----------------------------------------------------------------------------------*/
/* Transition - Usage Functions */
/*-----------------------------------------------------------------------------------*/
bool SHAnimationController::Transition::EvaluateCondition(const AnimParam& testParam) const noexcept
{
// Don't match, instant fail
if (testParam.ParamType != Param.ParamType)
return false;
// Evaluate them accordingly
switch (Param.ParamType)
{
case AnimParam::Type::Bool:
case AnimParam::Type::Trigger:
return evaluateCondition<bool>(testParam.Value != 0.0f);
case AnimParam::Type::Float:
return evaluateCondition<float>(testParam.Value);
break;
case AnimParam::Type::Int:
return evaluateCondition<int>(static_cast<int>(testParam.Value));
break;
}
return false;
}
/*-----------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimationController::Update(InstanceData& instData, float dt)
{
// Is there a valid node
if (!instData.CurrentNode)
return;
// Update the current playback
instData.ClipPlaybackTime += dt;
// Check if we finished playing
const float CLIP_CURR_PLAYED_TIME = instData.ClipPlaybackTime - instData.CurrentNode->Clip->GetStartTimeStamp();
if (CLIP_CURR_PLAYED_TIME > instData.CurrentNode->Clip->GetTotalDuration())
{
// Clamp
instData.ClipPlaybackTime = instData.CurrentNode->Clip->GetStartTimeStamp() + instData.CurrentNode->Clip->GetTotalDuration();
// Go to next state
bool stateChanged = false;
for (const auto& transition : instData.CurrentNode->Transitions)
{
// Check for no condition special case
if (transition.Condition == Transition::ConditionType::None)
{
changeNode(instData, transition.Target);
stateChanged = true;
break;
}
else
{
// Check if we have the parameter
if (!instData.Params.contains(transition.ParamName))
continue;
// If evaluation success, we transition
AnimParam& param = instData.Params[transition.ParamName];
if (transition.EvaluateCondition(param))
{
changeNode(instData, transition.Target);
stateChanged = true;
// If trigger, we need to unset it
if (param.ParamType == AnimParam::Type::Trigger)
{
param.Value = false;
}
break;
}
}
}
// Handle if there is no next state, we repeat
if (!stateChanged)
{
instData.ClipPlaybackTime = instData.CurrentNode->Clip->GetStartTimeStamp();
}
}
}
/*-----------------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------------*/
Handle<SHAnimationController::Node> SHAnimationController::CreateNode()
{
// Get system
auto system = SHSystemManager::GetSystem<SHAnimationSystem>();
if (system == nullptr)
throw std::runtime_error("[SHAnimationController] No SHAnimationSystem found!");
// Construct
auto node = system->GetResourceHub().Create<Node>();
nodes.emplace_back(node);
// If there is no start node, this is the first node so make it the starting node
if (!StartingNode)
StartingNode = node;
return node;
}
void SHAnimationController::DestroyNode(Handle<Node> node)
{
// Remove from storage
auto iter = std::find(nodes.begin(), nodes.end(), node);
if (iter == nodes.end())
throw std::invalid_argument("[SHAnimationController] Attempted to delete a node that doesn't belong.");
// Remove if it is a start node
if (StartingNode == node)
StartingNode = {};
// Remove from nodes
nodes.erase(iter);
// Clear node
node.Free();
}
void SHAnimationController::AddTransition(Handle<Node> source, const Transition& transition)
{
if (!source)
{
SHLOG_ERROR("[SHAnimationController] Attempted to add transition from an invalid node.");
return;
}
if (!transition.Target)
{
SHLOG_ERROR("[SHAnimationController] Attempted to add transition to an invalid node.");
return;
}
if (transition.Condition != Transition::ConditionType::None && !parameters.contains(transition.ParamName))
{
SHLOG_ERROR("[SHAnimationController] Attempted to add a conditional transition for an invalid parameter.");
return;
}
source->Transitions.emplace_back(transition);
}
void SHAnimationController::AddParameter(const std::string& name, AnimParam::Type type)
{
if (name.empty())
{
SHLOG_ERROR("[SHAnimationController] Attempted to add a parameter with no name.");
return;
}
if (parameters.contains(name))
{
SHLOG_ERROR("[SHAnimationController] Attempted to add a parameter with the same name.");
return;
}
// Insert
parameters.emplace(name, type);
}
void SHAnimationController::RemoveParameter(const std::string& name)
{
if (!parameters.contains(name))
{
SHLOG_ERROR("[SHAnimationController] Attempted to reemove a parameter that does not exist.");
return;
}
parameters.erase(name);
}
void SHAnimationController::SetTrigger(InstanceData& instData, const std::string& paramName)
{
// Invalid param
if (!parameters.contains(paramName))
return;
// Not a trigger
if (parameters[paramName] != AnimParam::Type::Trigger)
return;
// Set the flag
instData.Params[paramName].Value = true;
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimationController::changeNode(InstanceData& instData, Handle<Node> newNode)
{
instData.CurrentNode = newNode;
instData.ClipPlaybackTime = 0.0f;
}
}

View File

@ -0,0 +1,252 @@
/************************************************************************************//*!
\file SHAnimationController.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Feb 22, 2023
\brief Contains the definition of SHAnimationController.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
// STL Includes
#include <variant>
#include <vector>
#include <optional>
// Project Includes
#include "SH_API.h"
#include "Resource/SHHandle.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHAnimationClip;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/// <summary>
/// Object that controls the animation that is played by an animator through the use
/// of an internal state machine.
/// This should never be modified once it has been attached to a SHAnimatorComponent!
/// </summary>
class SH_API SHAnimationController
{
public:
/*---------------------------------------------------------------------------------*/
/* Forward Declarations */
/*---------------------------------------------------------------------------------*/
struct Node;
/*---------------------------------------------------------------------------------*/
/* Type Definition */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Describes a parameter for the AnimationController that can be used to control
/// the flow of animations.
/// </summary>
struct SH_API AnimParam
{
/*-------------------------------------------------------------------------------*/
/* Type Definition */
/*-------------------------------------------------------------------------------*/
/// <summary>
/// Type of animation parameter.
/// </summary>
enum class Type
{
Bool,
Trigger, // Variant of bool that can only be set to true and will be unset when consumed.
Float,
Int
};
using ValueType = float;
/*-------------------------------------------------------------------------------*/
/* Constructor */
/*-------------------------------------------------------------------------------*/
/// <summary>
/// Constructs an AnimParam with the default value set for the Value field based
/// on the specified type.
/// </summary>
/// <param name="type">Type of AnimParam.</param>
explicit AnimParam(Type type = Type::Int);
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
Type ParamType;
ValueType Value;
};
/// <summary>
/// Describes a transition between nodes of the animation controller.
/// </summary>
struct Transition
{
/*-------------------------------------------------------------------------------*/
/* Type Definition */
/*-------------------------------------------------------------------------------*/
/// <summary>
/// Types of conditions for the transition.
/// </summary>
enum class ConditionType
{
None,
Equals,
NotEquals,
LessThan,
LessThanOrEqual,
GreaterThan,
GreaterThanOrEqual
};
/*-------------------------------------------------------------------------------*/
/* Data Members */
/*-------------------------------------------------------------------------------*/
Handle<Node> Target;
ConditionType Condition = ConditionType::None;
AnimParam Param;
std::string ParamName;
/*-------------------------------------------------------------------------------*/
/* Usage Functions */
/*-------------------------------------------------------------------------------*/
/// <summary>
/// Checks the condition of this Transition against an animation paramter.
/// </summary>
/// <param name="testParam">Parameter to test with.</param>
/// <returns>Whether the condition passed.</returns>
bool EvaluateCondition(const AnimParam& testParam) const noexcept;
private:
/*-------------------------------------------------------------------------------*/
/* Helper Functions */
/*-------------------------------------------------------------------------------*/
template<typename T>
bool evaluateCondition(T value) const noexcept;
};
/// <summary>
/// Describes a node in the animation controller.
/// </summary>
struct Node
{
std::string Name = "Unnamed Node";
Handle<SHAnimationClip> Clip;
std::vector<Transition> Transitions;
};
/// <summary>
/// Describes a node in the animation controller.
/// </summary>
struct InstanceData
{
Handle<Node> CurrentNode;
std::unordered_map<std::string, AnimParam> Params;
float ClipPlaybackTime;
};
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
Handle<Node> StartingNode;
/*---------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Runs a single update for the animation controller.
/// </summary>
void Update(InstanceData& instData, float dt);
/*---------------------------------------------------------------------------------*/
/* Usage Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Creates a node in the state machine. Created nodes must be destroyed using
/// DestroyNode().
/// </summary>
/// <returns>Node that was created.</returns>
Handle<Node> CreateNode();
/// <summary>
/// Destroys the node that was created in the state machine.
/// </summary>
/// <param name="node">Node to destroy.</param>
void DestroyNode(Handle<Node> node);
/// <summary>
/// Links two nodes together with a Transition. This performs some additional
/// checking to ensure parameters are valid.
/// </summary>
/// <param name="source">Source node to transition from.</param>
/// <param name="transition">Describes the transition to add.</param>
void AddTransition(Handle<Node> source, const Transition& transition);
/// <summary>
/// Registers a parameter to the animation controller.
/// </summary>
/// <param name="name">Name of the parameter.</param>
/// <param name="type">Type of the parameter.</param>
void AddParameter(const std::string& name, AnimParam::Type type);
/// <summary>
/// Removes a parameter from the animation controller.
/// </summary>
/// <param name="name">Name of the parameter.</param>
void RemoveParameter(const std::string& name);
/// <summary>
/// Sets the parameter of the for the string. Does nothing if an invalid param name
/// is provided. Type of the parameter is not checked.
/// </summary>
/// <typeparam name="T">
/// Type of parameter. Only bool, int, floats are supported.
/// </typeparam>
/// <param name="instData">Data of the instance to update.</param>
/// <param name="paramName">Name of the parameter.</param>
/// <param name="value">Value to set the parameter to.</param>
template<typename T>
void SetParameter(InstanceData& instData, const std::string& paramName, T value);
/// <summary>
/// Gets the parameter of the for the string. Types are checked and will not return
/// a value if there is nothing.
/// </summary>
/// <typeparam name="T">
/// Type of parameter. Only bool, int, floats are supported.
/// </typeparam>
/// <param name="instData">Data of the instance to update.</param>
/// <param name="paramName">Name of the parameter.</param>
/// <returns>The value of the parameter or nothing if invalid.</returns>
template<typename T>
std::optional<T> GetParameter(InstanceData& instData, const std::string& paramName);
/// <summary>
/// Sets the flag for a trigger parameter. Does nothing if an invalid param name is
/// provided or if the param name refers to a parameter that is not a trigger.
/// </summary>
/// <param name="instData">Data of the instance to update.</param>
/// <param name="paramName">Name of the parameter.</param>
void SetTrigger(InstanceData& instData, const std::string& paramName);
/*---------------------------------------------------------------------------------*/
/* Getters */
/*---------------------------------------------------------------------------------*/
const std::unordered_map<std::string, AnimParam::Type>& GetParams() const noexcept { return parameters; }
const std::vector<Handle<Node>>& GetNodes() const noexcept { return nodes; }
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
// State machine
std::vector<Handle<Node>> nodes;
std::unordered_map<std::string, AnimParam::Type> parameters;
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
void changeNode(InstanceData& instData, Handle<Node> newNode);
};
}
#include "SHAnimationController.hpp"

View File

@ -0,0 +1,121 @@
/************************************************************************************//*!
\file SHAnimationController.hpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 1, 2023
\brief Contains the definition of template functions SHAnimationController.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
#include "SHAnimationController.h"
namespace SHADE
{
template<typename T>
bool SHAnimationController::Transition::evaluateCondition(T value) const noexcept
{
// Get the value
const T PARAM_VAL = [&]()
{
if constexpr (std::is_floating_point_v<T>)
return Param.Value;
else
return Param.Value != 0.0f;
}();
// Handle condition type
switch (Condition)
{
case SHAnimationController::Transition::ConditionType::None:
return true;
case SHAnimationController::Transition::ConditionType::Equals:
if constexpr (std::is_floating_point_v<T>)
{
static constexpr T EPSILON = static_cast<T>(0.001);
return std::abs(std::abs(value) - std::abs(PARAM_VAL)) < EPSILON;
}
else
{
return value == PARAM_VAL;
}
break;
case SHAnimationController::Transition::ConditionType::NotEquals:
if constexpr (std::is_floating_point_v<T>)
{
static constexpr T EPSILON = static_cast<T>(0.001);
return std::abs(std::abs(value) - std::abs(PARAM_VAL)) > EPSILON;
}
else
{
return value != PARAM_VAL;
}
break;
case SHAnimationController::Transition::ConditionType::LessThan:
return PARAM_VAL < value;
case SHAnimationController::Transition::ConditionType::LessThanOrEqual:
return PARAM_VAL <= value;
case SHAnimationController::Transition::ConditionType::GreaterThan:
return PARAM_VAL > value;
case SHAnimationController::Transition::ConditionType::GreaterThanOrEqual:
return PARAM_VAL >= value;
}
// Neither of the existing cases
return false;
}
template<typename T>
void SHAnimationController::SetParameter(InstanceData& instData, const std::string& paramName, T value)
{
static_assert(std::is_same_v<T, bool> || std::is_same_v<T, float> || std::is_same_v<T, int>, "Only works with bool, float or ints.");
// Invalid param
if (parameters.find(paramName) == parameters.end())
return;
// Set the value
instData.Params[paramName].Value = value;
}
template<typename T>
std::optional<T> SHAnimationController::GetParameter(InstanceData& instData, const std::string& paramName)
{
static_assert(std::is_same_v<T, bool> || std::is_same_v<T, float> || std::is_same_v<T, int>, "Only works with bool, float or ints.");
// Invalid param
if (parameters.find(paramName) == parameters.end())
return {};
// Check if the type matches
const auto TYPE = parameters[paramName];
if constexpr (std::is_same_v<T, bool>)
{
if (TYPE != AnimParam::Type::Bool && TYPE != AnimParam::Type::Trigger)
return {};
}
else if constexpr (std::is_same_v<T, float>)
{
if (parameters[paramName] != AnimParam::Type::Float)
return {};
}
else if constexpr (std::is_same_v<T, int>)
{
if (parameters[paramName] != AnimParam::Type::Int)
return {};
}
// Return the correct value
auto paramIter = instData.Params.find(paramName);
if (paramIter != instData.Params.end())
{
return paramIter->second.Value;
}
else
{
return T(); // Default constructed value
}
}
}

View File

@ -32,6 +32,7 @@ namespace SHADE
void SHAnimationSystem::UpdateRoutine::Execute(double dt) noexcept void SHAnimationSystem::UpdateRoutine::Execute(double dt) noexcept
{ {
auto& animators = SHComponentManager::GetDense<SHAnimatorComponent>(); auto& animators = SHComponentManager::GetDense<SHAnimatorComponent>();
dt *= reinterpret_cast<SHAnimationSystem*>(system)->TimeScale;
for (auto& animator : animators) for (auto& animator : animators)
{ {
animator.Update(dt); animator.Update(dt);

View File

@ -15,6 +15,7 @@ of DigiPen Institute of Technology is prohibited.
#include "SH_API.h" #include "SH_API.h"
#include "ECS_Base/System/SHSystem.h" #include "ECS_Base/System/SHSystem.h"
#include "ECS_Base/System/SHSystemRoutine.h" #include "ECS_Base/System/SHSystemRoutine.h"
#include "Resource/SHResourceLibrary.h"
namespace SHADE namespace SHADE
{ {
@ -41,6 +42,23 @@ namespace SHADE
void Execute(double dt) noexcept override final; void Execute(double dt) noexcept override final;
}; };
/*---------------------------------------------------------------------------------*/
/* Constants */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Default time scale used by the system.
/// </summary>
static constexpr double DEFAULT_TIME_SCALE = 1.0;
/*---------------------------------------------------------------------------------*/
/* Public Data Members */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Used by the system to multiply the given delta time to scale the animation
/// speed.
/// </summary>
double TimeScale = DEFAULT_TIME_SCALE;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -51,5 +69,16 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
virtual void Init(void) override final; virtual void Init(void) override final;
virtual void Exit(void) override final; virtual void Exit(void) override final;
/*---------------------------------------------------------------------------------*/
/* Getters */
/*---------------------------------------------------------------------------------*/
SHResourceHub& GetResourceHub() { return resources; }
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
SHResourceHub resources;
}; };
} }

View File

@ -33,18 +33,62 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::Play() void SHAnimatorComponent::Play()
{ {
isPlaying = false; isPlaying = true;
playOnce = false;
} }
void SHAnimatorComponent::Play(Handle<SHAnimationClip> clip) void SHAnimatorComponent::Play(Handle<SHAnimationClip> clip)
{ {
// Ignore if nothing is specified
if (!clip)
{
SHLOG_WARNING("[SHAnimatorComponent] Attempted to play an null SHAnimationClip. Use Stop() if stopping animation instead.");
return;
}
// Remove animation controller as we switch to manual play mode
animController = {};
animInstanceData.CurrentNode = {};
animInstanceData.Params.clear();
animInstanceData.ClipPlaybackTime = 0.0f;
// Set accordingly
currClip = clip; currClip = clip;
currPlaybackTime = 0.0f; currPlaybackTime = 0.0f;
Play(); auto RAW_ANIM = clip->GetRawAnimation();
// Set up if valid
if (currClip && RAW_ANIM)
{
// Calculate secs for the clip
secsPerTick = 1.0f / RAW_ANIM->GetTicksPerSecond();
currPlaybackTime = currClip->GetStartTimeStamp();
// Start playback
Play();
// Set to initial pose
if (rig && rig->GetRootNode())
{
updateCurrentAnimatorState(currClip, 0.0f);
}
}
}
void SHAnimatorComponent::PlayOneShot(Handle<SHAnimationClip> clip)
{
Play(clip);
playOnce = true;
} }
void SHAnimatorComponent::PlayFromStart() void SHAnimatorComponent::PlayFromStart()
{ {
if (!currClip)
{
SHLOG_WARNING("[SHAnimatorComponent] Attempted to restart a clip but there is no existing clip. Ignored.");
return;
}
isPlaying = true; isPlaying = true;
currPlaybackTime = 0.0f; currPlaybackTime = 0.0f;
} }
@ -56,10 +100,47 @@ namespace SHADE
void SHAnimatorComponent::Stop() void SHAnimatorComponent::Stop()
{ {
if (!currClip)
{
SHLOG_WARNING("[SHAnimatorComponent] Attempted to stop a clip but there is no existing clip. Ignored.");
return;
}
isPlaying = false; isPlaying = false;
currPlaybackTime = 0.0f; currPlaybackTime = 0.0f;
} }
/*-----------------------------------------------------------------------------------*/
/* Update Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::Update(float dt)
{
// Reset matrices
std::fill(boneMatrices.begin(), boneMatrices.end(), SHMatrix::Identity);
// Do not do anything if is not playing or there's nothing to animate
if (!isPlaying || !rig || !rig->GetRootNode())
return;
// Update the animation controller if any, this will set the currClip
if (animController)
{
updateAnimController(dt);
// Only update the animation state if there is a clip
if (animInstanceData.CurrentNode && animInstanceData.CurrentNode->Clip)
{
updateCurrentAnimatorState(animInstanceData.CurrentNode->Clip, animInstanceData.ClipPlaybackTime);
}
}
// Otherwise, a single clip was provided, then we'll use it
else if (currClip)
{
updateManualClipState(dt);
updateCurrentAnimatorState(currClip, currPlaybackTime);
}
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Setter Functions */ /* Setter Functions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -79,60 +160,118 @@ namespace SHADE
} }
} }
void SHAnimatorComponent::SetClip(Handle<SHAnimationClip> newClip) void SHAnimatorComponent::SetAnimationController(Handle<SHAnimationController> ac)
{ {
// No change // No change
if (currClip == newClip) if (animController == ac)
return; return;
// Set parameters // Set the controller
currClip = newClip; animController = ac;
secsPerTick = 1.0f / currClip->GetTicksPerSecond();
// Set to initial pose // If valid, we want to initialize it
if (rig && rig->GetRootNode() && currClip) if (animController)
{ {
updatePoseWithClip(0.0f); // Parameters
animInstanceData.Params.clear();
for (auto param : animController->GetParams())
{
animInstanceData.Params.emplace(param.first, SHAnimationController::AnimParam(param.second));
}
// First Node
animInstanceData.CurrentNode = animController->StartingNode;
// Playback Time
animInstanceData.ClipPlaybackTime = 0.0f;
// Get set of unique SHRawAnimation used by the animController
std::unordered_set<Handle<SHRawAnimation>> rawAnims;
for (auto node : animController->GetNodes())
{
// Ensure no null handles
if (!node)
continue;
const Handle<SHAnimationClip> CLIP = node->Clip;
if (!CLIP)
continue;
const Handle<SHRawAnimation> RAW_ANIM = CLIP->GetRawAnimation();
if (!RAW_ANIM)
continue;
// Store
rawAnims.emplace(RAW_ANIM);
}
} }
} }
/*-----------------------------------------------------------------------------------*/ void SHAnimatorComponent::SetTrigger(const std::string& paramName)
/* Update Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::Update(float dt)
{ {
//Reset matrices if (!animController)
std::fill(boneMatrices.begin(), boneMatrices.end(), SHMatrix::Identity);
// Nothing to animate
if (!currClip || !isPlaying || !rig || !rig->GetRootNode())
return; return;
// Update time on the playback return animController->SetTrigger(animInstanceData, paramName);
currPlaybackTime += dt; }
if (currPlaybackTime > currClip->GetTotalTime())
/*-----------------------------------------------------------------------------------*/
/* Helper Functions - Update */
/*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::updateAnimController(float dt)
{
// No animation controller
if (!animInstanceData.CurrentNode)
return;
// Update the animation controller
animController->Update(animInstanceData, dt);
// Get current clip
currClip = animInstanceData.CurrentNode->Clip;
if (currClip && currClip->GetRawAnimation())
{ {
currPlaybackTime = currPlaybackTime - currClip->GetTotalTime(); secsPerTick = 1.0f / currClip->GetRawAnimation();
} }
}
void SHAnimatorComponent::updateManualClipState(float dt)
{
currPlaybackTime += dt;
const float CLIP_CURR_PLAYED_TIME = currPlaybackTime - currClip->GetStartTimeStamp();
if (CLIP_CURR_PLAYED_TIME > currClip->GetTotalDuration())
{
if (playOnce)
{
playOnce = false;
isPlaying = false;
currPlaybackTime = currClip->GetStartTimeStamp() + currClip->GetTotalDuration();
}
else
{
currPlaybackTime = currClip->GetStartTimeStamp();
}
}
}
void SHAnimatorComponent::updateCurrentAnimatorState(Handle<SHAnimationClip> clip, float playbackTime)
{
// Nothing to animate
if (!clip || !isPlaying || !rig || !rig->GetRootNode())
return;
// Check that we have animation data
if (!clip->GetRawAnimation())
return;
// Play the clip // Play the clip
updatePoseWithClip(currPlaybackTime); updatePoseWithClip(clip, playbackTime);
} }
void SHAnimatorComponent::updatePoseWithClip(Handle<SHAnimationClip> clip, float poseTime)
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimatorComponent::updatePoseWithClip(float poseTime)
{ {
updatePoseWithClip(poseTime, rig->GetRootNode(), SHMatrix::Identity); updatePoseWithClip(poseTime, clip->GetRawAnimation(), rig->GetRootNode(), SHMatrix::Identity);
} }
void SHAnimatorComponent::updatePoseWithClip(float poseTime, Handle<SHRigNode> node, const SHMatrix& parentMatrix) void SHAnimatorComponent::updatePoseWithClip(float poseTime, Handle<SHRawAnimation> rawAnimData, Handle<SHRigNode> node, const SHMatrix& parentMatrix)
{ {
// Check if there is a channel for this node // Check if there is a channel for this node
SHMatrix transformMatrix = node->TransformMatrix; SHMatrix transformMatrix = node->TransformMatrix;
const int BONE_IDX = rig->GetNodeIndex(node); const int BONE_IDX = rig->GetNodeIndex(node);
const auto& CHANNELS = currClip->GetChannels(); const auto& CHANNELS = rawAnimData->GetChannels();
if (BONE_IDX < CHANNELS.size()) if (BONE_IDX < CHANNELS.size())
{ {
const auto& CHANNEL = CHANNELS[BONE_IDX]; const auto& CHANNEL = CHANNELS[BONE_IDX];
@ -149,16 +288,15 @@ namespace SHADE
// Apply transformations to this node // Apply transformations to this node
const int BONE_MTX_IDX = rig->GetNodeIndex(node); const int BONE_MTX_IDX = rig->GetNodeIndex(node);
std::optional<SHVec3> position;
if (BONE_MTX_IDX >= 0) if (BONE_MTX_IDX >= 0)
{ {
boneMatrices[BONE_MTX_IDX] = node->OffsetMatrix * transformMatrix; boneMatrices[BONE_MTX_IDX] = node->OffsetMatrix * transformMatrix;
} }
// Apply pose to children // Apply pose to children
for (auto& child : node->Children) for (auto child : node->Children)
{ {
updatePoseWithClip(poseTime, child, transformMatrix); updatePoseWithClip(poseTime, rawAnimData, child, transformMatrix);
} }
} }
} }

View File

@ -22,7 +22,8 @@ of DigiPen Institute of Technology is prohibited.
#include "Math/SHMatrix.h" #include "Math/SHMatrix.h"
#include "Math/Vector/SHVec3.h" #include "Math/Vector/SHVec3.h"
#include "Math/SHQuaternion.h" #include "Math/SHQuaternion.h"
#include "SHAnimationClip.h" #include "SHRawAnimation.h"
#include "SHAnimationController.h"
namespace SHADE namespace SHADE
{ {
@ -32,7 +33,6 @@ namespace SHADE
class SHRig; class SHRig;
struct SHRigNode; struct SHRigNode;
class SHAnimationClip; class SHAnimationClip;
class SHVkBuffer;
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
@ -52,12 +52,20 @@ namespace SHADE
/// </summary> /// </summary>
void Play(); void Play();
/// <summary> /// <summary>
/// Plays the specified animation clip from the start. /// Plays the specified animation clip from the start. This will unset any
/// SHAnimationControllers that have been set.
/// </summary> /// </summary>
/// <param name="clip"></param> /// <param name="clip">Animation clip to play.</param>
void Play(Handle<SHAnimationClip> clip); void Play(Handle<SHAnimationClip> clip);
/// <summary> /// <summary>
/// Plays the currently loaded animation clip from the start. /// Plays the specified animation clip from the start one time only. This will unset
/// any SHAnimationControllers that have been set.
/// </summary>
/// <param name="clip">Animation clip to play.</param>
void PlayOneShot(Handle<SHAnimationClip> clip);
/// <summary>
/// Plays the currently loaded animation clip from the start. Note that this only
/// works when using manual playback mode.
/// </summary> /// </summary>
void PlayFromStart(); void PlayFromStart();
/// <summary> /// <summary>
@ -65,10 +73,22 @@ namespace SHADE
/// </summary> /// </summary>
void Pause(); void Pause();
/// <summary> /// <summary>
/// Stops the animation and resets the play time back to 0. /// Stops the animation and resets the play time back to 0. Note that this only
/// works when using manual playback mode. This is not supported when using an
/// Animation Controller.
/// </summary> /// </summary>
void Stop(); void Stop();
/*---------------------------------------------------------------------------------*/
/* Update Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Updates the current state of the animation if one is specified based on the
/// current animation clip and frames. This will update the bone matrices.
/// </summary>
/// <param name="dt">Time passed since the last frame.</param>
void Update(float dt);
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Setter Functions */ /* Setter Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -78,12 +98,44 @@ namespace SHADE
/// <param name="newRig">Rig to use.</param> /// <param name="newRig">Rig to use.</param>
void SetRig(Handle<SHRig> newRig); void SetRig(Handle<SHRig> newRig);
/// <summary> /// <summary>
/// Sets the animation clip of this animator without playing it. /// Sets the animation controller to use for this animator.
/// This will set the pose of the model to it's initial pose.
/// If the clip is the same as the current clip, nothing happens.
/// </summary> /// </summary>
/// <param name="newClip">Clip to use.</param> /// <param name="newRig">Animation controller to use.</param>
void SetClip(Handle<SHAnimationClip> newClip); void SetAnimationController(Handle<SHAnimationController> ac);
/*---------------------------------------------------------------------------------*/
/* Parameter Functions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Sets the parameter of the for the string. Does nothing if an invalid param name
/// is provided. Type of the parameter is not checked. Also does nothing if no
/// animation controller is specified.
/// </summary>
/// <typeparam name="T">
/// Type of parameter. Only bool, int, floats are supported.
/// </typeparam>
/// <param name="paramName">Name of the parameter.</param>
/// <param name="value">Value to set the parameter to.</param>
template<typename T>
void SetParameter(const std::string& paramName, T value);
/// <summary>
/// Gets the parameter of the for the string. Types are checked and will not return
/// a value if there is nothing. Returns nothing if there is no animation controller
/// specified either.
/// </summary>
/// <typeparam name="T">
/// Type of parameter. Only bool, int, floats are supported.
/// </typeparam>
/// <param name="paramName">Name of the parameter.</param>
/// <returns>The value of the parameter or nothing if invalid.</returns>
template<typename T>
std::optional<T> GetParameter(const std::string& paramName);
/// <summary>
/// Sets the flag for a trigger parameter. Does nothing if an invalid param name is
/// provided or if the param name refers to a parameter that is not a trigger.
/// </summary>
/// <param name="paramName">Name of the parameter.</param>
void SetTrigger(const std::string& paramName);
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Getter Functions */ /* Getter Functions */
@ -99,38 +151,42 @@ namespace SHADE
/// <returns>Handle to the currently set rig.</returns> /// <returns>Handle to the currently set rig.</returns>
Handle<SHRig> GetRig() const noexcept { return rig; } Handle<SHRig> GetRig() const noexcept { return rig; }
/// <summary> /// <summary>
/// <summary>
/// Retrieve the currently set animation clip.
/// </summary>
/// <returns>Handle to the currently set animation clip.</returns>
Handle<SHAnimationClip> GetCurrentClip() const noexcept { return currClip; }
/// <summary>
/// Checks if an animation is currently playing. /// Checks if an animation is currently playing.
/// </summary> /// </summary>
/// <returns>True if an animation clip is currently playing.</returns> /// <returns>True if an animation clip is currently playing.</returns>
bool IsPlaying() const { return isPlaying; } bool IsPlaying() const { return isPlaying; }
/*---------------------------------------------------------------------------------*/
/* Update Functions */
/*---------------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Updates the current state of the animation if one is specified based on the /// Retrieves the current node for the Animation Controller. This returns a null
/// current animation clip and frames. This will update the bone matrices. /// if there is no Animation Controller currently set.
/// </summary> /// </summary>
/// <param name="dt">Time passed since the last frame.</param> /// <returns>Handle to the current Animation Controller node.</returns>
void Update(float dt); Handle<SHAnimationController::Node> GetCurrentNode() const noexcept { return animInstanceData.CurrentNode; }
/// <summary>
/// Retrieves the currently set animation controller.
/// </summary>
/// <returnsHandle to the currently set animtion controller.</returns>
Handle<SHAnimationController> GetAnimationController() const noexcept { return animController; }
private: private:
/*---------------------------------------------------------------------------------*/
/* Type Definition */
/*---------------------------------------------------------------------------------*/
using ChannelMap = std::unordered_map<std::string, const SHRawAnimation::Channel*>;
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
// Resources // Resources
Handle<SHRig> rig; Handle<SHRig> rig;
// Playback Tracking for Animation Controller Mode
Handle<SHAnimationController> animController;
SHAnimationController::InstanceData animInstanceData;
// Playback Tracking for Manual Mode
Handle<SHAnimationClip> currClip; Handle<SHAnimationClip> currClip;
// Playback Tracking
float currPlaybackTime = 0.0f; float currPlaybackTime = 0.0f;
bool playOnce = false;
// Shared Tracking
bool isPlaying = true; bool isPlaying = true;
// Useful Cached Data
float secsPerTick = 0.0f; float secsPerTick = 0.0f;
// Buffer // Buffer
std::vector<SHMatrix> boneMatrices; std::vector<SHMatrix> boneMatrices;
@ -138,8 +194,11 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void updatePoseWithClip(float poseTime); void updateAnimController(float dt);
void updatePoseWithClip(float poseTime, Handle<SHRigNode> node, const SHMatrix& parentMatrix); void updateManualClipState(float dt);
void updateCurrentAnimatorState(Handle<SHAnimationClip> clip, float playbackTime);
void updatePoseWithClip(Handle<SHAnimationClip> clip, float poseTime);
void updatePoseWithClip(float poseTime, Handle<SHRawAnimation> rawAnimData, Handle<SHRigNode> node, const SHMatrix& parentMatrix);
template<typename T> template<typename T>
T getInterpolatedValue(const std::vector<SHAnimationKeyFrame<T>>& keyframes, float poseTime); T getInterpolatedValue(const std::vector<SHAnimationKeyFrame<T>>& keyframes, float poseTime);

View File

@ -15,13 +15,31 @@ of DigiPen Institute of Technology is prohibited.
// Project Includes // Project Includes
#include "SHRig.h" #include "SHRig.h"
#include "Math/SHMatrix.h" #include "Math/SHMatrix.h"
#include "SHAnimationClip.h" #include "SHRawAnimation.h"
#include "Graphics/SHVkUtil.h" #include "SHAnimationController.h"
#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h"
#include "ECS_Base/Managers/SHSystemManager.h"
namespace SHADE namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/
/* Setter Functions */
/*-----------------------------------------------------------------------------------*/
template<typename T>
std::optional<T> SHAnimatorComponent::GetParameter(const std::string& paramName)
{
if (!animController)
return {};
return animController->GetParameter<T>(animInstanceData, paramName);
}
template<typename T>
void SHAnimatorComponent::SetParameter(const std::string& paramName, T value)
{
if (!animController)
return;
return animController->SetParameter(animInstanceData, paramName, value);
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/

View File

@ -0,0 +1,75 @@
/************************************************************************************//*!
\file SHRawAnimation.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Nov 20, 2022
\brief Contains the function definitions of the SHRawAnimation class.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
// Pre-compiled Header
#include "SHpch.h"
// Primary Header
#include "SHRawAnimation.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------------*/
SHRawAnimation::SHRawAnimation(const SHAnimAsset& asset)
{
// Populate keyframes
int maxFrames = 0;
totalTime = 0.0f;
for (const auto& channel : asset.nodeChannels)
{
// Create a channel
Channel newChannel;
newChannel.PositionKeyFrames.reserve(channel.positionKeys.size());
newChannel.RotationKeyFrames.reserve(channel.rotationKeys.size());
newChannel.ScaleKeyFrames.reserve(channel.scaleKeys.size());
// Populate Keyframes
for (const auto& posKey : channel.positionKeys)
{
newChannel.PositionKeyFrames.emplace_back(SHAnimationKeyFrame<SHVec3>{ posKey.time, posKey.value});
}
for (const auto& rotKey : channel.rotationKeys)
{
newChannel.RotationKeyFrames.emplace_back(SHAnimationKeyFrame<SHQuaternion>{ rotKey.time, rotKey.value});
}
for (const auto& scaleKey : channel.scaleKeys)
{
newChannel.ScaleKeyFrames.emplace_back(SHAnimationKeyFrame<SHVec3>{ scaleKey.time, scaleKey.value});
}
newChannel.MaxFrames = std::max({ newChannel.PositionKeyFrames.size(), newChannel.RotationKeyFrames.size(), newChannel.ScaleKeyFrames.size() });
// Compute max frames
maxFrames = std::max(maxFrames, newChannel.MaxFrames);
// Compute total time
totalTime = std::max({ totalTime, newChannel.PositionKeyFrames.back().TimeStamp, newChannel.RotationKeyFrames.back().TimeStamp, newChannel.ScaleKeyFrames.back().TimeStamp });
// Insert the channel
channels.emplace_back(std::move(newChannel));
// Compute fps
ticksPerSecond = static_cast<int>(maxFrames / totalTime);
}
totalFrames = maxFrames;
}
/*-----------------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
}

View File

@ -0,0 +1,85 @@
/************************************************************************************//*!
\file SHRawAnimation.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Dec 12, 2022
\brief Contains the definition of the SHRawAnimation struct and related types.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
// Project Includes
#include "SH_API.h"
#include "Math/SHMatrix.h"
#include "Assets/Asset Types/Models/SHAnimationAsset.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/// <summary>
/// Defines a single key frame in an animation for a specific type of data.
/// </summary>
template<typename T>
struct SHAnimationKeyFrame
{
float TimeStamp;
T Data;
};
/// <summary>
/// Represents the raw 3D animation data for a rigged 3D model.
/// </summary>
class SH_API SHRawAnimation
{
public:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Defines the animations of a single bone in a rig.
/// </summary>
struct Channel
{
std::vector<SHAnimationKeyFrame<SHVec3>> PositionKeyFrames;
std::vector<SHAnimationKeyFrame<SHQuaternion>> RotationKeyFrames;
std::vector<SHAnimationKeyFrame<SHVec3>> ScaleKeyFrames;
int MaxFrames;
};
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Constructs an SHAnimation Clip from a specified SHAnimAsset.
/// </summary>
/// <param name="asset">Animation asset to load.</param>
explicit SHRawAnimation(const SHAnimAsset& asset);
/*---------------------------------------------------------------------------------*/
/* Getter Functions */
/*---------------------------------------------------------------------------------*/
const std::vector<Channel>& GetChannels() const noexcept { return channels; }
int GetTicksPerSecond() const noexcept { return ticksPerSecond; }
float GetTotalTime() const noexcept { return totalTime; }
int GetTotalFrames() const noexcept { return totalFrames; }
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
std::vector<Channel> channels;
int ticksPerSecond;
float totalTime;
int totalFrames;
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
};
}

View File

@ -10,8 +10,10 @@
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#include "Math/SHMath.h"
#include "Assets/Asset Types/SHAssetData.h" #include "Assets/Asset Types/SHAssetData.h"
#include "Math/Vector/SHVec3.h"
#include "Math/Vector/SHVec4.h"
#include "Math/SHQuaternion.h"
#include <vector> #include <vector>

View File

@ -0,0 +1,36 @@
/************************************************************************************//*!
\file SHAnimClipAsset.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Feb 27, 2023
\brief Contains the definition of the SHAnimationClip struct and related types.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
#include "SH_API.h"
#include <string>
#include "Assets/SHAssetMacros.h"
#include "SHAssetData.h"
namespace SHADE
{
struct SHAnimClipAsset : SHAssetData
{
std::string name;
uint32_t firstIndex;
uint32_t lastIndex;
AssetID animRawDataAssetId; // Not serialised, only populated during runtime from parent asset
};
struct SH_API SHAnimClipContainerAsset final : SHAssetData
{
AssetID animRawDataAssetId;
std::vector<SHAnimClipAsset*> clips{};
};
}

View File

@ -0,0 +1,27 @@
/************************************************************************************//*!
\file SHAnimControllerAsset.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 1, 2023
\brief Contains the definition of the SHAnimControllerAsset struct and related
types.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
#include <string>
#include "SH_API.h"
#include "SHAssetData.h"
namespace SHADE
{
struct SH_API SHAnimControllerAsset : SHAssetData
{
std::string name;
// TODO
};
}

View File

@ -0,0 +1,129 @@
#include "SHpch.h"
#include "SHBinaryLoader.h"
#include "Assets/Asset Types/SHAnimClipContainerAsset.h"
#include <fstream>
namespace SHADE
{
SHAssetData* SHBinaryLoader::Load(AssetPath path)
{
std::ifstream file{ path, std::ios::in | std::ios::binary };
if (!file.is_open())
{
SHLOG_ERROR("[Binary Loader] Unable to open file for reading: {}", path.string());
return nullptr;
}
auto const extension = path.extension().string();
SHAssetData* result{nullptr};
if (extension == ANIM_CONTAINER_EXTENSION)
{
LoadAnimClipContainer(file, result, path);
}
file.close();
return result;
}
void SHBinaryLoader::Write(SHAssetData const* data, AssetPath path)
{
std::ofstream file{ path, std::ios::out | std::ios::binary };
if (!file.is_open())
{
SHLOG_ERROR("[Binary Loader] Unable to open file for writing: {}", path.string());
return;
}
auto const extension = path.extension().string();
if (extension == ANIM_CONTAINER_EXTENSION)
{
WriteAnimClipContainer(file, data, path);
}
file.close();
}
void SHBinaryLoader::WriteAnimClipContainer(std::ofstream& file, SHAssetData const* data, AssetPath path)
{
auto const& anim = *dynamic_cast<SHAnimClipContainerAsset const*>(data);
file.write(
reinterpret_cast<char const*>(&anim.animRawDataAssetId),
sizeof(uint32_t)
);
uint32_t const size {static_cast<uint32_t>(anim.clips.size())};
file.write(
reinterpret_cast<char const*>(&size),
sizeof(uint32_t)
);
for (auto const& clip : anim.clips)
{
uint32_t charCount {static_cast<uint32_t>(clip->name.size())};
file.write(
reinterpret_cast<char const*>(&charCount),
sizeof(uint32_t)
);
file.write(
clip->name.data(),
charCount
);
file.write(
reinterpret_cast<char const*>(&clip->firstIndex),
sizeof(uint32_t) * 2
);
}
}
void SHBinaryLoader::LoadAnimClipContainer(std::ifstream& file, SHAssetData*& result, AssetPath path)
{
auto const data = new SHAnimClipContainerAsset();
file.read(
reinterpret_cast<char*>(&data->animRawDataAssetId),
sizeof(uint32_t)
);
uint32_t size;
file.read(
reinterpret_cast<char*>(&size),
sizeof(uint32_t)
);
data->clips.resize(size);
for (auto& clip : data->clips)
{
clip = new SHAnimClipAsset;
uint32_t charCount;
file.read(
reinterpret_cast<char*>(&charCount),
sizeof(uint32_t)
);
clip->name.resize(charCount);
file.read(
clip->name.data(),
charCount
);
file.read(
reinterpret_cast<char*>(&clip->firstIndex),
sizeof(uint32_t) * 2
);
clip->animRawDataAssetId = data->animRawDataAssetId;
}
result = data;
}
}

View File

@ -0,0 +1,17 @@
#pragma once
#include "SHAssetLoader.h"
namespace SHADE
{
struct SHBinaryLoader : SHAssetLoader
{
SHAssetData* Load(AssetPath path) override;
void Write(SHAssetData const* data, AssetPath path) override;
private:
//Individual functions to write files
void WriteAnimClipContainer(std::ofstream& file,SHAssetData const* data, AssetPath path);
void LoadAnimClipContainer(std::ifstream& file,SHAssetData*& result, AssetPath path);
};
}

View File

@ -35,32 +35,32 @@ namespace SHADE
if (!file.is_open()) if (!file.is_open())
{ {
SHLOG_ERROR("[Text Loader] Unable to open text File: {}", path.string()); SHLOG_ERROR("[Text Loader] Unable to open text file for reading: {}", path.string());
return nullptr; return nullptr;
} }
std::stringstream stream; std::stringstream stream;
stream << file.rdbuf(); stream << file.rdbuf();
std::string content = stream.str(); std::string content = stream.str();
auto const extension = path.extension().string();
SHAssetData* result; SHAssetData* result;
if (path.extension().string() == SCENE_EXTENSION) if (extension == SCENE_EXTENSION)
{ {
auto data = new SHSceneAsset(); auto data = new SHSceneAsset();
data->name = path.stem().string(); data->name = path.stem().string();
data->data = std::move(content); data->data = std::move(content);
result = data; result = data;
} }
else if (path.extension().string() == PREFAB_EXTENSION) else if (extension == PREFAB_EXTENSION)
{ {
auto data = new SHPrefabAsset(); auto data = new SHPrefabAsset();
data->name = path.stem().string(); data->name = path.stem().string();
data->data = std::move(content); data->data = std::move(content);
result = data; result = data;
} }
else if (path.extension().string() == MATERIAL_EXTENSION) else if (extension == MATERIAL_EXTENSION)
{ {
auto data = new SHMaterialAsset(); auto data = new SHMaterialAsset();
data->name = path.stem().string(); data->name = path.stem().string();
@ -79,21 +79,23 @@ namespace SHADE
if (!file.is_open()) if (!file.is_open())
{ {
SHLOG_ERROR("[Text Loader] Unable to open text File: {}", path.string()); SHLOG_ERROR("[Text Loader] Unable to open text file for writing: {}", path.string());
return; return;
} }
if (path.extension().string() == SCENE_EXTENSION) auto const extension = path.extension().string();
if (extension == SCENE_EXTENSION)
{ {
auto scene = dynamic_cast<SHSceneAsset const*>(data); auto scene = dynamic_cast<SHSceneAsset const*>(data);
file << scene->data; file << scene->data;
} }
else if (path.extension().string() == PREFAB_EXTENSION) else if (extension == PREFAB_EXTENSION)
{ {
auto prefab = dynamic_cast<SHPrefabAsset const*>(data); auto prefab = dynamic_cast<SHPrefabAsset const*>(data);
file << prefab->data; file << prefab->data;
} }
else if (path.extension().string() == MATERIAL_EXTENSION) else if (extension == MATERIAL_EXTENSION)
{ {
auto material = dynamic_cast<SHMaterialAsset const*>(data); auto material = dynamic_cast<SHMaterialAsset const*>(data);
file << material->data; file << material->data;

View File

@ -11,10 +11,6 @@
#pragma once #pragma once
#include "SHAssetLoader.h" #include "SHAssetLoader.h"
#include "Assets/Asset Types/SHPrefabAsset.h"
#include "Assets/Asset Types/SHSceneAsset.h"
#include "Assets/Asset Types/SHMaterialAsset.h"
namespace SHADE namespace SHADE
{ {
struct SHTextBasedLoader : SHAssetLoader struct SHTextBasedLoader : SHAssetLoader

View File

@ -7,6 +7,7 @@
* or disclosure of this file or its contents without the prior * or disclosure of this file or its contents without the prior
* written consent of Digipen Institute of Technology is prohibited * written consent of Digipen Institute of Technology is prohibited
******************************************************************************/ ******************************************************************************/
// ReSharper disable All
#ifndef SH_ASSET_MACROS_H #ifndef SH_ASSET_MACROS_H
#define SH_ASSET_MACROS_H #define SH_ASSET_MACROS_H
@ -18,22 +19,22 @@
// FMOD Fwd Declare // FMOD Fwd Declare
namespace FMOD namespace FMOD
{ {
class Sound; class Sound;
class System; class System;
class ChannelGroup; class ChannelGroup;
class Channel; class Channel;
} }
enum FMOD_RESULT : int; enum FMOD_RESULT : int;
enum FMOD_SPEAKERMODE : int; enum FMOD_SPEAKERMODE : int;
// Typedefs // Typedefs
typedef uint32_t AssetID; typedef uint32_t AssetID;
typedef std::string AssetName; using AssetName = std::string;
typedef std::filesystem::path AssetPath; typedef std::filesystem::path AssetPath;
typedef unsigned char* AssetData; typedef unsigned char* AssetData;
typedef std::string AssetMetaVersion; typedef std::string AssetMetaVersion;
typedef std::string AssetExtension; typedef std::string AssetExtension;
typedef size_t AssetTypeMeta; typedef size_t AssetTypeMeta;
typedef FMOD::Sound* SHSound; typedef FMOD::Sound* SHSound;
@ -45,9 +46,9 @@ constexpr AssetID INVALID_ASSET_ID {0};
// Asset type enum // Asset type enum
enum class AssetType : AssetTypeMeta enum class AssetType : AssetTypeMeta
{ {
INVALID, INVALID,
SHADER, SHADER,
SHADER_BUILT_IN, SHADER_BUILT_IN,
TEXTURE, TEXTURE,
MODEL, MODEL,
SCENE, SCENE,
@ -57,7 +58,10 @@ enum class AssetType : AssetTypeMeta
SCRIPT, SCRIPT,
FONT, FONT,
AUDIO_BANK, AUDIO_BANK,
MAX_COUNT ANIM_CONTAINER,
ANIM_CLIP,
ANIM_CONTROLLER,
MAX_COUNT
}; };
constexpr size_t TYPE_COUNT{ static_cast<size_t>(AssetType::MAX_COUNT) }; constexpr size_t TYPE_COUNT{ static_cast<size_t>(AssetType::MAX_COUNT) };
@ -78,6 +82,8 @@ constexpr std::string_view FONT_COMPILER_EXE{ "FontCompiler.exe" };
constexpr std::string_view SCENE_FOLDER{ "/Scenes/" }; constexpr std::string_view SCENE_FOLDER{ "/Scenes/" };
constexpr std::string_view PREFAB_FOLDER{ "/Prefabs/" }; constexpr std::string_view PREFAB_FOLDER{ "/Prefabs/" };
constexpr std::string_view MATERIAL_FOLDER{ "/Materials/" }; constexpr std::string_view MATERIAL_FOLDER{ "/Materials/" };
constexpr std::string_view ANIM_CLIP_FOLDER{ "/Animation Clips/" };
constexpr std::string_view ANIM_CONTROLLER_FOLDER{ "/Animation Controllers/" };
// ASSET EXTENSIONS // ASSET EXTENSIONS
@ -94,20 +100,26 @@ constexpr std::string_view PREFAB_EXTENSION {".shprefab"};
constexpr std::string_view MATERIAL_EXTENSION {".shmat"}; constexpr std::string_view MATERIAL_EXTENSION {".shmat"};
constexpr std::string_view TEXTURE_EXTENSION {".shtex"}; constexpr std::string_view TEXTURE_EXTENSION {".shtex"};
constexpr std::string_view MODEL_EXTENSION{ ".shmodel" }; constexpr std::string_view MODEL_EXTENSION{ ".shmodel" };
constexpr std::string_view ANIM_CONTAINER_EXTENSION{ ".shanimcontainer" };
constexpr std::string_view ANIM_CONTROLLER_EXTENSION{ ".shanimcontroller" };
constexpr std::string_view FILLER_EXTENSION{"dummy"};
constexpr std::string_view EXTENSIONS[] = { constexpr std::string_view EXTENSIONS[] = {
AUDIO_EXTENSION, AUDIO_EXTENSION,
SHADER_EXTENSION, SHADER_EXTENSION,
SHADER_BUILT_IN_EXTENSION, SHADER_BUILT_IN_EXTENSION,
TEXTURE_EXTENSION, TEXTURE_EXTENSION,
MODEL_EXTENSION, MODEL_EXTENSION,
SCENE_EXTENSION, SCENE_EXTENSION,
PREFAB_EXTENSION, PREFAB_EXTENSION,
MATERIAL_EXTENSION, MATERIAL_EXTENSION,
"dummy", FILLER_EXTENSION,
SCRIPT_EXTENSION, SCRIPT_EXTENSION,
FONT_EXTENSION, FONT_EXTENSION,
AUDIO_BANK_EXTENSION AUDIO_BANK_EXTENSION,
ANIM_CONTAINER_EXTENSION,
ANIM_CONTROLLER_EXTENSION,
FILLER_EXTENSION
}; };
constexpr size_t EXTENSIONS_COUNT{ static_cast<size_t>(AssetType::MAX_COUNT) }; constexpr size_t EXTENSIONS_COUNT{ static_cast<size_t>(AssetType::MAX_COUNT) };
@ -120,10 +132,10 @@ constexpr std::string_view GLTF_EXTENSION{ ".gltf" };
constexpr std::string_view TTF_EXTENSION{ ".ttf" }; constexpr std::string_view TTF_EXTENSION{ ".ttf" };
constexpr std::string_view EXTERNALS[] = { constexpr std::string_view EXTERNALS[] = {
GLSL_EXTENSION, GLSL_EXTENSION,
DDS_EXTENSION, DDS_EXTENSION,
FBX_EXTENSION, FBX_EXTENSION,
GLTF_EXTENSION, GLTF_EXTENSION,
TTF_EXTENSION TTF_EXTENSION
}; };
@ -133,9 +145,9 @@ constexpr std::string_view FRAGMENT_SHADER{ "_FS" };
constexpr std::string_view COMPUTER_SHADER{ "_CS" }; constexpr std::string_view COMPUTER_SHADER{ "_CS" };
constexpr std::pair<std::string_view, SHADE::SH_SHADER_TYPE> SHADER_IDENTIFIERS[] = { constexpr std::pair<std::string_view, SHADE::SH_SHADER_TYPE> SHADER_IDENTIFIERS[] = {
std::make_pair(VERTEX_SHADER, SHADE::SH_SHADER_TYPE::VERTEX), std::make_pair(VERTEX_SHADER, SHADE::SH_SHADER_TYPE::VERTEX),
std::make_pair(FRAGMENT_SHADER, SHADE::SH_SHADER_TYPE::FRAGMENT), std::make_pair(FRAGMENT_SHADER, SHADE::SH_SHADER_TYPE::FRAGMENT),
std::make_pair(COMPUTER_SHADER, SHADE::SH_SHADER_TYPE::COMPUTE) std::make_pair(COMPUTER_SHADER, SHADE::SH_SHADER_TYPE::COMPUTE)
}; };
constexpr size_t SHADER_TYPE_MAX_COUNT{ 3 }; constexpr size_t SHADER_TYPE_MAX_COUNT{ 3 };

View File

@ -21,8 +21,13 @@
#include "Libraries/Loaders/SHShaderSourceLoader.h" #include "Libraries/Loaders/SHShaderSourceLoader.h"
#include "Libraries/Loaders/SHTextBasedLoader.h" #include "Libraries/Loaders/SHTextBasedLoader.h"
#include "Libraries/Loaders/SHFontLoader.h" #include "Libraries/Loaders/SHFontLoader.h"
#include "Libraries/Loaders/SHBinaryLoader.h"
#include "Asset Types/SHPrefabAsset.h"
#include "Asset Types/SHMaterialAsset.h"
#include "Asset Types/SHSceneAsset.h"
#include "Asset Types/SHAnimClipContainerAsset.h"
//#include "Libraries/Compilers/SHMeshCompiler.h"
#include "Libraries/Compilers/SHTextureCompiler.h" #include "Libraries/Compilers/SHTextureCompiler.h"
#include "Libraries/Compilers/SHShaderSourceCompiler.h" #include "Libraries/Compilers/SHShaderSourceCompiler.h"
@ -159,14 +164,24 @@ namespace SHADE
return AssetType::INVALID; return AssetType::INVALID;
} }
std::optional<SHADE::SHAsset> SHAssetManager::GetAsset(AssetID id) noexcept SHAsset* SHAssetManager::GetAsset(AssetID id) noexcept
{ {
if (assetCollection.contains(id)) if (assetCollection.contains(id))
{ {
return assetCollection[id]; return &assetCollection[id];
} }
return {}; return nullptr;
}
SHAsset const* SHAssetManager::GetAssetConst(AssetID id) noexcept
{
if (assetCollection.contains(id))
{
return &assetCollection[id];
}
return nullptr;
} }
AssetID SHAssetManager::GetAssetIDFromPath(AssetPath const& path) noexcept AssetID SHAssetManager::GetAssetIDFromPath(AssetPath const& path) noexcept
@ -233,8 +248,19 @@ namespace SHADE
} }
break; break;
case AssetType::ANIM_CONTAINER:
newPath += ANIM_CLIP_FOLDER;
newPath += name;
newPath += ANIM_CONTAINER_EXTENSION;
{
auto animClip = new SHAnimClipContainerAsset();
data = animClip;
}
break;
default: default:
SHLOG_ERROR("[Asset Manager] Asset type of {} not an internal asset type, cannot be created", name); SHLOG_ERROR("[Asset Manager] Asset type of {} not an internal parent asset type, cannot be created", name);
return 0; return 0;
} }
@ -249,13 +275,13 @@ namespace SHADE
auto result = assetCollection.emplace( auto result = assetCollection.emplace(
id, id,
SHAsset( SHAsset(
name, name,
id, id,
type, type,
newPath, newPath,
false false
) )
); );
assetData.emplace(id, data); assetData.emplace(id, data);
@ -266,6 +292,41 @@ namespace SHADE
return id; return id;
} }
AssetID SHAssetManager::CreateNewSubAsset(AssetType type, AssetName name, AssetID parent)
{
if (!assetData.contains(parent))
{
SHLOG_ERROR("[Asset Manager] Failed to create new sub asset, parent does not exist: {}", name);
return 0;
}
switch(type)
{
case AssetType::ANIM_CLIP:
{
auto const animContainer {dynamic_cast<SHAnimClipContainerAsset*>(assetData[parent])};
auto id = GenerateAssetID(type);
SHAsset asset{
.name = name,
.id = id,
.type = type,
.isSubAsset = true,
.parent = parent
};
auto& newClip {animContainer->clips.emplace_back()};
newClip->name = name;
assetCollection.emplace(id, asset);
assetCollection[parent].subAssets.push_back(&assetCollection[id]);
assetData.emplace(id, newClip);
return id;
}
default:
SHLOG_ERROR("[Asset Manager] Asset type of {} not an internal sub asset type, cannot be created", name);
return 0;
}
}
bool SHAssetManager::SaveAsset(AssetID id) noexcept bool SHAssetManager::SaveAsset(AssetID id) noexcept
{ {
if (assetCollection.contains(id)) if (assetCollection.contains(id))
@ -274,7 +335,8 @@ namespace SHADE
if ( if (
asset.type == AssetType::SCENE || asset.type == AssetType::SCENE ||
asset.type == AssetType::PREFAB || asset.type == AssetType::PREFAB ||
asset.type == AssetType::MATERIAL asset.type == AssetType::MATERIAL ||
asset.type == AssetType::ANIM_CONTAINER
) )
{ {
if (assetData.contains(id)) if (assetData.contains(id))
@ -467,9 +529,9 @@ namespace SHADE
//Reload data //Reload data
auto result = GetAsset(target); auto result = GetAsset(target);
if (result.has_value()) if (result)
{ {
auto const& asset{ result.value() }; auto const& asset{ *result };
auto newData = loaders[static_cast<size_t>(asset.type)]->Load(asset.path); auto newData = loaders[static_cast<size_t>(asset.type)]->Load(asset.path);
delete assetData[target]; delete assetData[target];
assetData[target] = newData; assetData[target] = newData;
@ -533,6 +595,8 @@ namespace SHADE
loaders[static_cast<size_t>(AssetType::SCRIPT)] = nullptr; loaders[static_cast<size_t>(AssetType::SCRIPT)] = nullptr;
loaders[static_cast<size_t>(AssetType::FONT)] = dynamic_cast<SHAssetLoader*>(new SHFontLoader()); loaders[static_cast<size_t>(AssetType::FONT)] = dynamic_cast<SHAssetLoader*>(new SHFontLoader());
loaders[static_cast<size_t>(AssetType::AUDIO_BANK)] = loaders[static_cast<size_t>(AssetType::SCENE)]; loaders[static_cast<size_t>(AssetType::AUDIO_BANK)] = loaders[static_cast<size_t>(AssetType::SCENE)];
loaders[static_cast<size_t>(AssetType::ANIM_CONTAINER)] = dynamic_cast<SHAssetLoader*>(new SHBinaryLoader());
loaders[static_cast<size_t>(AssetType::ANIM_CLIP)] = nullptr;
} }
/**************************************************************************** /****************************************************************************
@ -575,6 +639,25 @@ namespace SHADE
assetData.emplace(asset.id, data); assetData.emplace(asset.id, data);
} }
switch (asset.type)
{
case AssetType::ANIM_CONTAINER:
{
auto container = reinterpret_cast<SHAnimClipContainerAsset*>(data);
for (auto i{0}; i < asset.subAssets.size(); ++i)
{
assetData.emplace(
asset.subAssets[i]->id,
container->clips[i]
);
}
}
break;
default:
break;
}
return data; return data;
} }
@ -582,7 +665,6 @@ namespace SHADE
{ {
auto const& parent = assetCollection[asset.parent]; auto const& parent = assetCollection[asset.parent];
auto parentData = loaders[static_cast<size_t>(parent.type)]->Load(parent.path); auto parentData = loaders[static_cast<size_t>(parent.type)]->Load(parent.path);
if (parentData == nullptr) if (parentData == nullptr)
{ {
SHLOG_ERROR("[Asset Manager] Unable to load asset into memory: {}\n", parent.path.string()); SHLOG_ERROR("[Asset Manager] Unable to load asset into memory: {}\n", parent.path.string());
@ -590,16 +672,37 @@ namespace SHADE
else else
{ {
assetData.emplace(parent.id, parentData); assetData.emplace(parent.id, parentData);
if (parent.type == AssetType::MODEL) switch(parent.type)
{ {
auto parentModel = reinterpret_cast<SHModelAsset*>(parentData); case AssetType::MODEL:
for (auto i {0}; i < parent.subAssets.size(); ++i)
{ {
assetData.emplace( const auto parentModel = reinterpret_cast<SHModelAsset*>(parentData);
parent.subAssets[i]->id, for (auto i {0}; i < parent.subAssets.size(); ++i)
parentModel->meshes[i] {
); assetData.emplace(
parent.subAssets[i]->id,
parentModel->meshes[i]
);
}
} }
break;
case AssetType::ANIM_CONTAINER:
{
const auto parentContainer = reinterpret_cast<SHAnimClipContainerAsset*>(parentData);
for (auto i {0}; i < parent.subAssets.size(); ++i)
{
assetData.emplace(
parent.subAssets[i]->id,
parentContainer->clips[i]
);
}
}
break;
default:
SHLOG_WARNING("[Asset Manager] Parent type not supported to load sub assets, aborting...");
return nullptr;
} }
return assetData[asset.id]; return assetData[asset.id];
@ -757,6 +860,38 @@ namespace SHADE
return newAsset.id; return newAsset.id;
} }
else if(ext==ANIM_CONTAINER_EXTENSION)
{
SHAsset newAsset{
path.stem().string(),
GenerateAssetID(AssetType::ANIM_CONTAINER),
AssetType::ANIM_CONTAINER,
path,
false
};
assetCollection.emplace(newAsset.id, newAsset);
SHAnimClipContainerAsset* const data = reinterpret_cast<SHAnimClipContainerAsset*>(LoadData(newAsset));
assetData.emplace(newAsset.id, data);
for(auto& clip : data->clips)
{
SHAsset subAsset{
.name = clip->name,
.id = GenerateAssetID(AssetType::ANIM_CLIP),
.type = AssetType::ANIM_CLIP,
.isSubAsset = true,
.parent = newAsset.id
};
assetCollection.emplace(subAsset.id, subAsset);
assetCollection[newAsset.id].subAssets.push_back(&assetCollection[subAsset.id]);
assetData.emplace(subAsset.id, clip);
}
SHAssetMetaHandler::WriteMetaData(assetCollection[newAsset.id]);
}
} }
void SHAssetManager::BuildAssetCollection() noexcept void SHAssetManager::BuildAssetCollection() noexcept
@ -813,7 +948,9 @@ namespace rttr
value("Material", AssetType::MATERIAL), value("Material", AssetType::MATERIAL),
value("Mesh", AssetType::MESH), value("Mesh", AssetType::MESH),
value("Script", AssetType::SCRIPT), value("Script", AssetType::SCRIPT),
value("Font", AssetType::FONT) value("Font", AssetType::FONT),
value("Animation Container", AssetType::ANIM_CONTAINER),
value("Animation Clip", AssetType::ANIM_CLIP)
); );
} }
} }

View File

@ -50,7 +50,8 @@ namespace SHADE
* \return const& to unordered_map<AssetName, AssetID> * \return const& to unordered_map<AssetName, AssetID>
****************************************************************************/ ****************************************************************************/
static std::vector<SHAsset> GetAllAssets() noexcept; static std::vector<SHAsset> GetAllAssets() noexcept;
static std::optional<SHAsset> GetAsset(AssetID id) noexcept; static SHAsset* GetAsset(AssetID id) noexcept;
static SHAsset const* GetAssetConst(AssetID id) noexcept;
static AssetType GetType(AssetID id) noexcept; static AssetType GetType(AssetID id) noexcept;
@ -63,6 +64,7 @@ namespace SHADE
* \return resource id generated for new asset * \return resource id generated for new asset
****************************************************************************/ ****************************************************************************/
static AssetID CreateNewAsset(AssetType type, AssetName name) noexcept; static AssetID CreateNewAsset(AssetType type, AssetName name) noexcept;
static AssetID CreateNewSubAsset(AssetType type, AssetName name, AssetID parent);
static bool SaveAsset(AssetID id) noexcept; static bool SaveAsset(AssetID id) noexcept;
static bool DeleteAsset(AssetID id) noexcept; static bool DeleteAsset(AssetID id) noexcept;

View File

@ -280,7 +280,7 @@ namespace SHADE
if (arm->lookAtCameraOrigin) if (arm->lookAtCameraOrigin)
CameraLookAt(camera, camera.position + arm->GetTargetOffset()); CameraLookAt(camera, camera.position + tOffset);
} }

View File

@ -0,0 +1,951 @@
/************************************************************************************//*!
\file SHAnimationControllerEditor.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 1, 2023
\brief Contains the definition of SHAnimationControllerEditor's functions.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#include "SHpch.h"
#include "SHAnimationControllerEditor.h"
// STL Includes
#include <format>
// External Dependencies
#include <imgui.h>
#include <imnodes.h>
// Project Includes
#include "Editor/IconsMaterialDesign.h"
#include "Animation/SHAnimationController.h"
#include "Editor/SHEditorUI.h"
#include "Editor/SHEditorWidgets.hpp"
#include "Editor/Command/SHCommand.hpp"
#include "Input/SHInputManager.h"
#include "Resource/SHResourceManager.h"
#include "Editor/EditorWindow/SHEditorWindowManager.h"
#include "Editor/EditorWindow/AssetBrowser/SHAssetBrowser.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Constructors/Destructors */
/*-----------------------------------------------------------------------------------*/
SHAnimationControllerEditor::SHAnimationControllerEditor()
: SHEditorWindow("Animation Controller Editor", ImGuiWindowFlags_MenuBar)
{}
/*-----------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimationControllerEditor::Init()
{
SHEditorWindow::Init();
// Set up caches
conditionsList =
{
"None",
"=",
"!=",
"<",
"<=",
">",
">="
};
typesList =
{
"Boolean",
"Trigger",
"Float",
"Integer"
};
// Set up sample animation controller for testing
SHAnimationController controller;
auto n1 = controller.CreateNode();
auto n2 = controller.CreateNode();
auto n3 = controller.CreateNode();
n1->Name = "N1";
n2->Name = "N2";
n3->Name = "N3";
SHAnimationController::Transition t;
t.Target = n3;
n1->Transitions.emplace_back(t);
n2->Transitions.emplace_back(t);
t.Target = n1;
n3->Transitions.emplace_back(t);
Open(controller);
}
void SHAnimationControllerEditor::Update()
{
SHEditorWindow::Update();
if (Begin())
{
// Only render the node editor if there is controller data
if (controllerData.has_value())
{
// Calculate size of each portion
const float WINDOW_WIDTH = ImGui::GetWindowSize().x;
const float MAIN_PANEL_COLUMN_WIDTH = WINDOW_WIDTH * 0.7f;
const float SIDE_PANELS_COLUMN_WIDTH = (WINDOW_WIDTH - MAIN_PANEL_COLUMN_WIDTH) * 0.5f;
// Draw
drawActiveMenuBar();
ImGui::BeginTable("base_table", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable);
{
// Set up Columns
ImGui::TableSetupColumn(" Parameters", ImGuiTableColumnFlags_WidthStretch, SIDE_PANELS_COLUMN_WIDTH);
ImGui::TableSetupColumn("State Machine", ImGuiTableColumnFlags_WidthFixed, MAIN_PANEL_COLUMN_WIDTH);
ImGui::TableSetupColumn("Properties", ImGuiTableColumnFlags_WidthStretch, SIDE_PANELS_COLUMN_WIDTH);
// Header
ImGui::TableHeadersRow();
// Render menu bars
ImGui::TableNextRow();
{
ImGui::TableSetColumnIndex(0);
drawParamsMenuBar();
ImGui::TableSetColumnIndex(1);
drawNodeEditorMenuBar();
ImGui::TableSetColumnIndex(2);
drawPropertiesMenuBar();
}
// Render contents
ImGui::TableNextRow();
{
ImGui::TableSetColumnIndex(0);
drawParamsPanel();
ImGui::TableSetColumnIndex(1);
drawNodeEditor();
ImGui::TableSetColumnIndex(2);
drawPropertiesPanel();
}
}
ImGui::EndTable();
}
else
{
SHEditorUI::CenteredText("No animation controller is selected.");
}
}
ImGui::End();
}
void SHAnimationControllerEditor::Exit()
{
SHEditorWindow::Exit();
}
void SHAnimationControllerEditor::Open(SHAnimationController& controllerHandle)
{
controller = controllerHandle;
controllerData = deserialise(controller);
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
void SHAnimationControllerEditor::drawActiveMenuBar()
{
if (ImGui::BeginMenuBar())
{
// Save Button
if (ImGui::Button(std::format("{} Save", ICON_MD_SAVE).data()))
{
controller = serialise(controllerData.value()); // TODO: Actually save the resource
}
// Discard Button
if (ImGui::Button(std::format("{} Discard Changes", ICON_MD_CANCEL).data()))
{
Open(controller); // TODO: Actually load the resource
}
ImGui::EndMenuBar();
}
}
void SHAnimationControllerEditor::drawParamsMenuBar()
{
// Add Parameter Button
if (ImGui::BeginCombo("##Type", std::format("{} Add Parameter", ICON_MD_ADD).data(), ImGuiComboFlags_None))
{
// All other options
for (int i = 0; i < static_cast<int>(typesList.size()); ++i)
{
if (ImGui::Selectable(typesList[i].c_str()))
{
int count = 0;
std::string paramName = "New Param";
while (controllerData->Params.contains(paramName))
{
paramName = "New Param " + std::to_string(++count);
}
controllerData->Params.emplace(paramName, static_cast<SHAnimationController::AnimParam::Type>(i));
}
}
ImGui::EndCombo();
}
}
void SHAnimationControllerEditor::drawParamsPanel()
{
int paramId = 0;
for (const auto& param : controllerData->Params)
{
ImGui::PushID(paramId++);
if (SHEditorWidgets::InputText
(
"",
[&]() { return param.first; },
[&](const std::string& val)
{
// Remove from previous
const SHAnimationController::AnimParam::Type TYPE = param.second;
controllerData->Params.erase(param.first);
// Put into the new
controllerData->Params[val] = TYPE;
// Update all links
for (auto& link : controllerData->Links)
{
link.second.ParamName = val;
}
},
{}, ImGuiInputTextFlags_EnterReturnsTrue
))
{
ImGui::PopID();
break; // Map was modified
}
ImGui::SameLine();
if (ImGui::BeginCombo("##Type", typesList[static_cast<int>(param.second)].c_str(), ImGuiComboFlags_None))
{
// All other options
for (int i = 0; i < static_cast<int>(typesList.size()); ++i)
{
const bool IS_SELECTED = static_cast<int>(param.second) == i;
if (ImGui::Selectable(typesList[i].c_str(), IS_SELECTED))
{
SHCommandManager::PerformCommand
(
std::reinterpret_pointer_cast<SHBaseCommand>
(
std::make_shared<SHCommand<SHAnimationController::AnimParam::Type>>
(
param.second,
static_cast<SHAnimationController::AnimParam::Type>(i),
[&](SHAnimationController::AnimParam::Type val)
{
controllerData->Params[param.first] = val;
// TODO: This needs to be handled in a custom command
// For changing to boolean, we need to change inequalities to not equal, etc.
if (val == SHAnimationController::AnimParam::Type::Bool)
{
for (auto& link : controllerData->Links)
{
switch (link.second.Condition)
{
case SHAnimationController::Transition::ConditionType::GreaterThan:
case SHAnimationController::Transition::ConditionType::LessThan:
link.second.Condition = SHAnimationController::Transition::ConditionType::NotEquals;
break;
case SHAnimationController::Transition::ConditionType::GreaterThanOrEqual:
case SHAnimationController::Transition::ConditionType::LessThanOrEqual:
link.second.Condition = SHAnimationController::Transition::ConditionType::Equals;
break;
}
}
}
}
)
),
false
);
}
if (IS_SELECTED)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
ImGui::PopID();
}
}
void SHAnimationControllerEditor::drawNodeEditorMenuBar()
{
// Add Node Button
if (ImGui::Button(std::format("{} Add Node", ICON_MD_ADD).data()))
{
createNode(controllerData.value());
}
ImGui::SameLine();
// Delete Node Button
ImGui::BeginDisabled((ImNodes::NumSelectedNodes() + ImNodes::NumSelectedLinks()) < 1);
if (ImGui::Button(std::format("{} Delete Objects", ICON_MD_DELETE).data()))
{
deleteSelectedLinks();
deleteSelectedNodes();
}
ImGui::EndDisabled();
ImGui::SameLine();
// Set Starting Node Button
ImGui::BeginDisabled(ImNodes::NumSelectedNodes() != 1);
if (ImGui::Button(std::format("{} Set Starting Node", ICON_MD_HOME).data()))
{
// Get id of selected node
int selectedNode = 0;
ImNodes::GetSelectedNodes(&selectedNode);
controllerData->StartingNode = selectedNode; // We can do this as the ImNodes node index is the same
}
ImGui::EndDisabled();
}
void SHAnimationControllerEditor::drawNodeEditor()
{
static constexpr float NODE_WIDTH = 80.0f;
static constexpr float TEXT_FIELD_PADDING = 15.0f;
ImNodes::BeginNodeEditor();
{
/* Draw Nodes */
for (auto& node : controllerData->Nodes)
{
// Draw the node
ImNodes::BeginNode(node.Index);
{
// Title
ImNodes::BeginNodeTitleBar();
{
// Starting node marker
if (node.Index == controllerData->StartingNode)
{
const float INDENT = NODE_WIDTH * 0.6f;
ImGui::Indent(INDENT);
ImGui::Text(ICON_MD_HOME);
ImGui::Unindent(INDENT);
}
if (node.EditingName)
{
if (ImGui::Button(ICON_MD_DONE))
{
node.EditingName = false;
}
ImGui::SameLine();
ImGui::SetNextItemWidth(std::max(ImGui::CalcTextSize(node.Name.c_str()).x + TEXT_FIELD_PADDING, NODE_WIDTH));
SHEditorUI::InputTextField("", node.Name);
}
else
{
if (ImGui::Button(ICON_MD_EDIT))
{
node.EditingName = true;
}
ImGui::SameLine();
ImGui::Text(node.Name.c_str());
}
}
ImNodes::EndNodeTitleBar();
// Body
const auto CLIP_NAME = SHResourceManager::GetAssetName<SHAnimationClip>(node.Clip).value_or("");
ImGui::SetNextItemWidth(NODE_WIDTH);
SHEditorWidgets::DragDropReadOnlyField<AssetID>
(
"Clip", CLIP_NAME,
[&]()
{
return SHResourceManager::GetAssetID<SHAnimationClip>(node.Clip).value_or(0);
},
[&](AssetID id)
{
if (SHAssetManager::GetType(id) != AssetType::ANIM_CLIP)
return;
node.Clip = SHResourceManager::LoadOrGet<SHAnimationClip>(id);
SHResourceManager::FinaliseChanges();
},
SHDragDrop::DRAG_RESOURCE, {}, NODE_WIDTH
);
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
{
if (node.Clip)
{
AssetID assetID = SHResourceManager::GetAssetID<SHAnimationClip>(node.Clip).value_or(0);
SHEditorWindowManager::GetEditorWindow<SHAssetBrowser>()->SetScrollTo(assetID);
}
}
// Input Nodes
for (auto inputAttrib : node.InputAttribs)
{
drawInputNode(inputAttrib.Raw, ImNodesPinShape_CircleFilled);
}
// Render an extra input
drawInputNode(getExtraInputAttrib(node.Index).Raw, ImNodesPinShape_Circle);
// Output Nodes
for (auto outputAttrib : node.OutputAttribs)
{
drawOutputNode(outputAttrib.Raw, node.Index, ImNodesPinShape_TriangleFilled);
}
// Render an extra output
drawOutputNode(getExtraOutputAttrib(node.Index).Raw, node.Index, ImNodesPinShape_Triangle);
}
ImNodes::EndNode();
}
// Draw links
for (auto link : controllerData->Links)
{
ImNodes::Link(link.first, link.second.SourceAttrib.Raw, link.second.DestAttrib.Raw);
}
}
ImNodes::MiniMap(0.2f, ImNodesMiniMapLocation_BottomRight);
ImNodes::EndNodeEditor();
int sourceAttrib, destAttrib;
if (ImNodes::IsLinkCreated(&sourceAttrib, &destAttrib))
{
// Get the two indices
NodeAttributeIndex sourceAttribIndex, destAttribIndex;
sourceAttribIndex.Raw = static_cast<uint16_t>(sourceAttrib);
destAttribIndex.Raw = static_cast<uint16_t>(destAttrib);
// Ensure that we can access the nodes
if (controllerData->IndexToNodeMap.contains(sourceAttribIndex.OwnerNodeIndex) &&
controllerData->IndexToNodeMap.contains(destAttribIndex.OwnerNodeIndex))
{
// Retrieve the nodes
auto inputNodeIter = controllerData->IndexToNodeMap[sourceAttribIndex.OwnerNodeIndex];
auto outputNodeIter = *controllerData->IndexToNodeMap[destAttribIndex.OwnerNodeIndex];
// Create link
createLink
(
controllerData.value(),
controllerData->IndexToNodeMap[sourceAttribIndex.OwnerNodeIndex],
controllerData->IndexToNodeMap[destAttribIndex.OwnerNodeIndex]
);
}
}
// Delete
if (SHInputManager::GetKeyUp(SHInputManager::SH_KEYCODE::DEL))
{
deleteSelectedLinks();
deleteSelectedNodes();
}
}
void SHAnimationControllerEditor::drawPropertiesMenuBar()
{
// Set Starting Node Button
const int SELECTED_LINKS_COUNT = ImNodes::NumSelectedLinks();
ImGui::BeginDisabled(SELECTED_LINKS_COUNT < 1);
if (ImGui::Button(std::format("{} Reset Conditions", ICON_MD_SETTINGS_BACKUP_RESTORE).data()))
{
std::vector<int> selectedLinks(SELECTED_LINKS_COUNT);
ImNodes::GetSelectedLinks(selectedLinks.data());
for (auto& link : selectedLinks)
{
// Get LinkData
NodeLinkIndex nodeLinkIndex;
nodeLinkIndex.Raw = link;
if (!controllerData->Links.contains(nodeLinkIndex.Raw))
continue;
LinkData& linkData = controllerData->Links[nodeLinkIndex.Raw];
// Ensure that the link is valid
if (!controllerData->IndexToNodeMap.contains(nodeLinkIndex.SourceAttribute.OwnerNodeIndex) ||
!controllerData->IndexToNodeMap.contains(nodeLinkIndex.DestinationAttribute.OwnerNodeIndex))
{
continue;
}
linkData.ParamName = "";
linkData.Condition = SHAnimationController::Transition::ConditionType::None;
}
}
ImGui::EndDisabled();
}
void SHAnimationControllerEditor::drawPropertiesPanel()
{
const int SELECTED_LINKS_COUNT = ImNodes::NumSelectedLinks();
if (SELECTED_LINKS_COUNT > 0)
{
std::vector<int> selectedLinks(SELECTED_LINKS_COUNT);
ImNodes::GetSelectedLinks(selectedLinks.data());
// Go through all links and display them
int index = 0;
for (int link : selectedLinks)
{
// Get LinkData
NodeLinkIndex nodeLinkIndex;
nodeLinkIndex.Raw = link;
if (!controllerData->Links.contains(nodeLinkIndex.Raw))
continue;
LinkData& linkData = controllerData->Links[nodeLinkIndex.Raw];
// Ensure that the link is valid
if (!controllerData->IndexToNodeMap.contains(nodeLinkIndex.SourceAttribute.OwnerNodeIndex) ||
!controllerData->IndexToNodeMap.contains(nodeLinkIndex.DestinationAttribute.OwnerNodeIndex))
{
continue;
}
// Create name of the link
std::ostringstream oss;
oss << controllerData->IndexToNodeMap[nodeLinkIndex.SourceAttribute.OwnerNodeIndex]->Name
<< " " << ICON_MD_ARROW_RIGHT_ALT << " "
<< controllerData->IndexToNodeMap[nodeLinkIndex.DestinationAttribute.OwnerNodeIndex]->Name;
ImGui::PushID(index++);
// Display each link
if (SHEditorUI::CollapsingHeader(oss.str()))
{
const bool IS_PARAM_SET = !linkData.ParamName.empty();
// Anim Parameter
ImGui::Text("Parameter");
ImGui::SameLine();
if (ImGui::BeginCombo("##Parameter", IS_PARAM_SET ? linkData.ParamName.c_str() : "None", ImGuiComboFlags_None))
{
// Initial "None" option
if (ImGui::Selectable("None", !IS_PARAM_SET))
{
SHCommandManager::PerformCommand
(
std::reinterpret_pointer_cast<SHBaseCommand>
(
std::make_shared<SHCommand<std::string>>
(
linkData.ParamName,
std::string{},
[&](const std::string& val) { linkData.ParamName = val; }
)
),
false
);
}
if (!IS_PARAM_SET)
{
ImGui::SetItemDefaultFocus();
}
// All other options
for (const auto& param : controllerData->Params)
{
const bool IS_SELECTED = param.first == linkData.ParamName;
if (ImGui::Selectable(param.first.c_str(), IS_SELECTED))
{
SHCommandManager::PerformCommand
(
std::reinterpret_pointer_cast<SHBaseCommand>
(
std::make_shared<SHCommand<std::string>>
(
linkData.ParamName,
param.first,
[&](const std::string& val) { linkData.ParamName = val; }
)
),
false
);
}
if (IS_SELECTED)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
// Properties for an Animation Parameter
if (IS_PARAM_SET && controllerData->Params.contains(linkData.ParamName))
{
const SHAnimationController::AnimParam::Type PARAM_TYPE = controllerData->Params[linkData.ParamName];
if (PARAM_TYPE != SHAnimationController::AnimParam::Type::Trigger)
{
// Comparison Type
const auto& CURR_COMPARISON = conditionsList[static_cast<int>(linkData.Condition)];
ImGui::Text("Condition Type");
ImGui::SameLine();
if (ImGui::BeginCombo("##ConditionType", CURR_COMPARISON.c_str(), ImGuiComboFlags_None))
{
// We only show equal and not equal for bool
const int LAST_ELEM = PARAM_TYPE == SHAnimationController::AnimParam::Type::Bool ? static_cast<int>(SHAnimationController::Transition::ConditionType::NotEquals)
: static_cast<int>(conditionsList.size() - 1);
// Comparisons
for (int i = 0; i <= LAST_ELEM; ++i)
{
const bool IS_SELECTED = i == static_cast<int>(linkData.Condition);
if (ImGui::Selectable(conditionsList[i].c_str(), IS_SELECTED))
{
SHCommandManager::PerformCommand
(
std::reinterpret_pointer_cast<SHBaseCommand>
(
std::make_shared<SHCommand<SHAnimationController::Transition::ConditionType>>
(
linkData.Condition,
static_cast<SHAnimationController::Transition::ConditionType>(i),
[&](SHAnimationController::Transition::ConditionType val) { linkData.Condition = val; }
)
),
false
);
}
if (IS_SELECTED)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
// Parameter Value
if (linkData.Condition != SHAnimationController::Transition::ConditionType::None)
{
switch (PARAM_TYPE)
{
case SHAnimationController::AnimParam::Type::Bool:
SHEditorWidgets::CheckBox
(
"Required State",
[&]() { return linkData.ParamThresholdValue != 0.0f; },
[&](bool val) { linkData.ParamThresholdValue = static_cast<float>(val); }
);
break;
case SHAnimationController::AnimParam::Type::Float:
SHEditorWidgets::DragFloat
(
"Threshold",
[&]() { return linkData.ParamThresholdValue; },
[&](float val) { linkData.ParamThresholdValue = val; }
);
break;
case SHAnimationController::AnimParam::Type::Int:
SHEditorWidgets::DragInt
(
"Threshold",
[&]() { return static_cast<int>(linkData.ParamThresholdValue); },
[&](int val) { linkData.ParamThresholdValue = static_cast<float>(val); }
);
break;
}
}
}
}
}
ImGui::PopID();
}
}
else
{
ImGui::Text("Select an object to view properties.");
}
}
SHAnimationControllerEditor::NodeAttributeIndex SHAnimationControllerEditor::getExtraInputAttrib(uint32_t nodeIndex)
{
NodeAttributeIndex extraInputAttrib;
extraInputAttrib.OwnerNodeIndex = nodeIndex;
extraInputAttrib.AttributeIndex = std::numeric_limits<int8_t>::lowest();
return extraInputAttrib;
}
SHAnimationControllerEditor::NodeAttributeIndex SHAnimationControllerEditor::getExtraOutputAttrib(uint32_t nodeIndex)
{
NodeAttributeIndex extraOutputAttrib;
extraOutputAttrib.OwnerNodeIndex = nodeIndex;
extraOutputAttrib.AttributeIndex = std::numeric_limits<int8_t>::max();
return extraOutputAttrib;
}
void SHAnimationControllerEditor::drawInputNode(int id, ImNodesPinShape_ pinShape)
{
ImNodes::BeginInputAttribute(id, pinShape);
ImGui::Text("Input");
ImNodes::EndInputAttribute();
}
void SHAnimationControllerEditor::drawOutputNode(int id, int parentNodeId, ImNodesPinShape_ pinShape)
{
static char const* TITLE = "Output";
static float RIGHT_PADDING = 20.0f;
ImNodes::BeginOutputAttribute(id, ImNodesPinShape_TriangleFilled);
ImGui::Indent(ImNodes::GetNodeDimensions(parentNodeId).x - ImGui::CalcTextSize(TITLE).x - RIGHT_PADDING);
ImGui::Text(TITLE);
ImNodes::EndOutputAttribute();
}
void SHAnimationControllerEditor::deleteSelectedNodes()
{
const int NUM_SELECTED_NODES= ImNodes::NumSelectedNodes();
if (NUM_SELECTED_NODES > 0)
{
std::vector<int> selectedNodes(NUM_SELECTED_NODES);
ImNodes::GetSelectedNodes(selectedNodes.data());
for (auto nodeId : selectedNodes)
{
deleteNode(controllerData.value(), nodeId);
}
}
}
void SHAnimationControllerEditor::deleteSelectedLinks()
{
const int NUM_SELECTED_LINKS = ImNodes::NumSelectedLinks();
if (NUM_SELECTED_LINKS > 0)
{
std::vector<int> selectedLinks(NUM_SELECTED_LINKS);
ImNodes::GetSelectedLinks(selectedLinks.data());
for (auto linkId : selectedLinks)
{
deleteLink(controllerData.value(), linkId);
}
}
}
std::list<SHAnimationControllerEditor::Node>::iterator SHAnimationControllerEditor::createNode(AnimControllerData& data)
{
const NodeIndex NEW_NODE_IDX = data.NextNodeIndex++;
Node localNode;
localNode.Index = NEW_NODE_IDX;
data.Nodes.emplace_back(std::move(localNode));
// Update the node map
auto nodeIter = --data.Nodes.end();
data.IndexToNodeMap[NEW_NODE_IDX] = nodeIter;
return nodeIter;
}
SHAnimationControllerEditor::LinkMap::iterator SHAnimationControllerEditor::createLink(AnimControllerData& data, std::list<Node>::iterator sourceNode, std::list<Node>::iterator destNode)
{
// Update source node's output attributes
NodeAttributeIndex attribIndex;
attribIndex.OwnerNodeIndex = sourceNode->Index;
attribIndex.AttributeIndex = static_cast<int8_t>(sourceNode->OutputAttribs.size() + 1);
sourceNode->OutputAttribs.emplace_back(attribIndex);
// Update target node's input attributes
attribIndex.OwnerNodeIndex = destNode->Index;
attribIndex.AttributeIndex = static_cast<int8_t>(-(destNode->InputAttribs.size() + 1));
destNode->InputAttribs.emplace_back(attribIndex);
// Create link
LinkData link;
link.SourceNode = sourceNode;
link.TargetNode = destNode;
link.SourceAttrib = sourceNode->OutputAttribs.back();
link.DestAttrib = destNode->InputAttribs.back();
NodeLinkIndex linkIdx;
linkIdx.SourceAttribute = link.SourceAttrib;
linkIdx.DestinationAttribute = link.DestAttrib;
const auto EMPLACE_DATA = data.Links.emplace(linkIdx.Raw, std::move(link));
sourceNode->Transitions.emplace_back(linkIdx);
return EMPLACE_DATA.first;
}
void SHAnimationControllerEditor::deleteLink(AnimControllerData& data, LinkIndex link)
{
const NodeLinkIndex LINK_IDX { link };
// Error check, don't do anything if they don't exist
if (!data.IndexToNodeMap.contains(LINK_IDX.SourceAttribute.OwnerNodeIndex) ||
!data.IndexToNodeMap.contains(LINK_IDX.DestinationAttribute.OwnerNodeIndex))
return;
// Get source node and attributes
auto& sourceNode = *data.IndexToNodeMap[LINK_IDX.SourceAttribute.OwnerNodeIndex];
auto& destNode = *data.IndexToNodeMap[LINK_IDX.DestinationAttribute.OwnerNodeIndex];
// Remove attributes
std::erase(sourceNode.OutputAttribs, LINK_IDX.SourceAttribute);
std::erase(destNode.InputAttribs, LINK_IDX.DestinationAttribute);
// Remove link
std::erase(sourceNode.Transitions, LINK_IDX);
data.Links.erase(link);
}
void SHAnimationControllerEditor::deleteNode(AnimControllerData& data, NodeIndex nodeIndex)
{
// Get node to delete
if (!data.IndexToNodeMap.contains(nodeIndex))
return;
auto nodeToDeleteIter = data.IndexToNodeMap[nodeIndex];
// Remove all links to other nodes
for (auto link : nodeToDeleteIter->Transitions)
{
deleteLink(data, link.Raw);
}
// Remove all links from other nodes
for (auto node : data.Nodes)
{
for (NodeLinkIndex link : node.Transitions)
{
if (link.DestinationAttribute.OwnerNodeIndex == nodeIndex)
{
deleteLink(data, link.Raw);
}
}
}
// Then finally, delete this node
data.IndexToNodeMap.erase(nodeIndex);
data.Nodes.erase(nodeToDeleteIter);
// If the starting node was this node, we need to reassign
if (data.StartingNode == nodeIndex)
{
data.StartingNode = data.Nodes.empty() ? data.NextNodeIndex : data.Nodes.front().Index;
}
}
/*-----------------------------------------------------------------------------------*/
/* Static Helper Functions */
/*-----------------------------------------------------------------------------------*/
SHAnimationControllerEditor::AnimControllerData SHAnimationControllerEditor::deserialise(const SHAnimationController& controller)
{
AnimControllerData data;
// Maps controller nodes to data nodes
std::unordered_map<Handle<SHAnimationController::Node>, std::list<Node>::iterator> nodeMap;
// Load anim parameters
data.Params = controller.GetParams();
// Load nodes and links
for (auto node : controller.GetNodes())
{
auto localNode = createNode(data);
localNode->Name = node->Name;
localNode->Clip = node->Clip;
nodeMap.emplace(node, localNode);
}
// Load links
for (auto node : controller.GetNodes())
{
// Get the corresponding data node
auto dataNodeIter = nodeMap[node];
for (auto transition : node->Transitions)
{
// Invalid node check
if (!nodeMap.contains(transition.Target))
continue;
// Get the target node
auto targetNodeIter = nodeMap[transition.Target];
// Create link
auto& linkData = createLink(data, dataNodeIter, targetNodeIter)->second;
linkData.Condition = transition.Condition;
linkData.ParamName = transition.ParamName;
linkData.ParamThresholdValue = transition.Param.Value;
}
}
// Mark starting node
if (nodeMap.contains(controller.StartingNode))
{
data.StartingNode = nodeMap[controller.StartingNode]->Index;
}
return data;
}
SHAnimationController SHAnimationControllerEditor::serialise(const AnimControllerData& data)
{
SHAnimationController controller;
// Maps data nodes to controller nodes
std::unordered_map<NodeIndex, Handle<SHAnimationController::Node>> nodeMap;
// Create all nodes first
for (const auto& node : data.Nodes)
{
auto newNode = controller.CreateNode();
newNode->Name = node.Name;
newNode->Clip = node.Clip;
nodeMap[node.Index] = newNode;
}
// Create links
for (const auto& node : data.Nodes)
{
// Get controller node
auto controllerNode = nodeMap[node.Index];
for (auto link : node.Transitions)
{
// Ignore invalid link
if (!nodeMap.contains(link.SourceAttribute.OwnerNodeIndex) || !nodeMap.contains(link.DestinationAttribute.OwnerNodeIndex))
continue;
// Get link data
const LinkData& LINK_DATA = data.Links.at(link.Raw);
SHAnimationController::Transition transition;
transition.Target = nodeMap[link.DestinationAttribute.OwnerNodeIndex];
if (data.Params.contains(LINK_DATA.ParamName))
{
transition.Condition = LINK_DATA.Condition;
transition.ParamName = LINK_DATA.ParamName;
transition.Param.ParamType = data.Params.at(LINK_DATA.ParamName);
transition.Param.Value = LINK_DATA.ParamThresholdValue;
}
controllerNode->Transitions.emplace_back(std::move(transition));
}
}
// Starting Node
if (nodeMap.contains(data.StartingNode))
{
controller.StartingNode = nodeMap[data.StartingNode];
}
// Parameters
for (auto param : data.Params)
{
controller.AddParameter(param.first, param.second);
}
return controller;
}
}

View File

@ -0,0 +1,151 @@
/************************************************************************************//*!
\file SHAnimationControllerEditor.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 1, 2023
\brief Contains the definition of SHAnimationControllerEditor.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
// STL Includes
#include <vector>
#include <optional>
// External Dependencies
#include <imnodes.h>
// Project Includes
#include "Resource/SHHandle.h"
#include "Editor/EditorWindow/SHEditorWindow.h"
#include "Animation/SHAnimationController.h"
namespace SHADE
{
/// <summary>
/// Editor for modifying the Animation Controller state machine.
/// </summary>
class SHAnimationControllerEditor final : public SHEditorWindow
{
public:
/*---------------------------------------------------------------------------------*/
/* Constructors/Destructors */
/*---------------------------------------------------------------------------------*/
SHAnimationControllerEditor();
~SHAnimationControllerEditor() = default;
/*---------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*---------------------------------------------------------------------------------*/
void Init() override;
void Update() override;
void Exit() override;
/*---------------------------------------------------------------------------------*/
/* Usage Functions */
/*---------------------------------------------------------------------------------*/
void Open(SHAnimationController& controller);
private:
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
using NodeIndex = uint8_t;
using LinkIndex = int32_t;
union NodeAttributeIndex
{
uint16_t Raw;
struct
{
NodeIndex OwnerNodeIndex;
int8_t AttributeIndex; // Negative is input, positive is output
};
bool operator==(NodeAttributeIndex rhs) const noexcept { return Raw == rhs.Raw; }
};
union NodeLinkIndex
{
LinkIndex Raw;
struct
{
NodeAttributeIndex SourceAttribute;
NodeAttributeIndex DestinationAttribute;
};
bool operator==(NodeLinkIndex rhs) const noexcept { return Raw != rhs.Raw; }
};
struct Node
{
NodeIndex Index;
std::string Name = "Unnamed Node";
Handle<SHAnimationClip> Clip;
std::vector<NodeAttributeIndex> InputAttribs;
std::vector<NodeAttributeIndex> OutputAttribs;
std::vector<NodeLinkIndex> Transitions;
bool EditingName = false;
};
struct LinkData
{
// Source/Dest Data
std::list<Node>::iterator SourceNode;
std::list<Node>::iterator TargetNode;
NodeAttributeIndex SourceAttrib;
NodeAttributeIndex DestAttrib;
// Conditional Data
SHAnimationController::Transition::ConditionType Condition = SHAnimationController::Transition::ConditionType::None;
std::string ParamName;
SHAnimationController::AnimParam::ValueType ParamThresholdValue;
};
using LinkMap = std::unordered_map<LinkIndex, LinkData>;
struct AnimControllerData
{
NodeIndex StartingNode = 0;
std::list<Node> Nodes;
std::unordered_map<std::string, SHAnimationController::AnimParam::Type> Params;
LinkMap Links;
int NextNodeIndex = 0; // Index to use for newly created nodes
std::unordered_map<NodeIndex, std::list<Node>::iterator> IndexToNodeMap;
};
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
SHAnimationController controller;
std::optional<AnimControllerData> controllerData;
// Persistent Cached Data
std::vector<std::string> conditionsList;
std::vector<std::string> typesList;
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
void drawActiveMenuBar();
void drawParamsMenuBar();
void drawParamsPanel();
void drawNodeEditorMenuBar();
void drawNodeEditor();
void drawPropertiesMenuBar();
void drawPropertiesPanel();
NodeAttributeIndex getExtraInputAttrib(uint32_t nodeIndex);
NodeAttributeIndex getExtraOutputAttrib(uint32_t nodeIndex);
void drawInputNode(int id, ImNodesPinShape_ pinShape);
void drawOutputNode(int id, int parentNodeId, ImNodesPinShape_ pinShape);
void deleteSelectedNodes();
void deleteSelectedLinks();
/*---------------------------------------------------------------------------------*/
/* Static Helper Functions */
/*---------------------------------------------------------------------------------*/
static std::list<Node>::iterator createNode(AnimControllerData& data);
static LinkMap::iterator createLink(AnimControllerData& data, std::list<Node>::iterator sourceNode, std::list<Node>::iterator destNode);
static void deleteLink(AnimControllerData& data, LinkIndex link);
static void deleteNode(AnimControllerData& data, NodeIndex nodeIndex);
static AnimControllerData deserialise(const SHAnimationController& controller);
static SHAnimationController serialise(const AnimControllerData& data);
};
}

View File

@ -22,7 +22,11 @@
#include "Assets/Asset Types/SHPrefabAsset.h" #include "Assets/Asset Types/SHPrefabAsset.h"
#include "Serialization/SHSerialization.h" #include "Serialization/SHSerialization.h"
#include <Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h> #include <Editor/EditorWindow/HierarchyPanel/SHHierarchyPanel.h>
#include "Assets/Asset Types/SHAnimClipContainerAsset.h"
#include "Assets/Asset Types/Models/SHModelAsset.h"
#include "Serialization/Prefab/SHPrefabManager.h" #include "Serialization/Prefab/SHPrefabManager.h"
#include "Editor/EditorWindow/RawAnimationInspector/SHRawAnimInspector.h"
namespace SHADE namespace SHADE
{ {
@ -367,11 +371,12 @@ namespace SHADE
{ {
switch (asset->type) switch (asset->type)
{ {
case AssetType::INVALID: break; case AssetType::INVALID: break;
case AssetType::SHADER: break; case AssetType::SHADER: break;
case AssetType::SHADER_BUILT_IN: break; case AssetType::SHADER_BUILT_IN: break;
case AssetType::TEXTURE: break; case AssetType::TEXTURE: break;
case AssetType::MESH: break; case AssetType::MODEL: break;
case AssetType::MESH: break;
case AssetType::SCENE: case AssetType::SCENE:
{ {
if(editor->LoadScene(asset->id)) if(editor->LoadScene(asset->id))
@ -382,7 +387,7 @@ namespace SHADE
} }
} }
break; break;
case AssetType::PREFAB: break; case AssetType::PREFAB: break;
case AssetType::MATERIAL: case AssetType::MATERIAL:
if (auto matInspector = SHEditorWindowManager::GetEditorWindow<SHMaterialInspector>()) if (auto matInspector = SHEditorWindowManager::GetEditorWindow<SHMaterialInspector>())
{ {
@ -395,6 +400,12 @@ namespace SHADE
scriptEngine->OpenFile(asset->path); scriptEngine->OpenFile(asset->path);
} }
break; break;
case AssetType::ANIM_CONTAINER:
if (auto animInspector = SHEditorWindowManager::GetEditorWindow<SHRawAnimInspector>())
{
animInspector->Open(asset->id);
}
break;
case AssetType::MAX_COUNT: break; case AssetType::MAX_COUNT: break;
default:; default:;
} }
@ -480,6 +491,48 @@ namespace SHADE
isAssetBeingCreated = false; isAssetBeingCreated = false;
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
{
auto const models {SHAssetManager::GetAllRecordOfType(AssetType::MODEL)};
ImGui::RadioButton("Animation Clip Container", true);
ImGui::SameLine();
static char const* const modelPrompt = "Select a model with animations";
char const* currentItem = modelPrompt;
AssetID selected {0};
if (ImGui::BeginCombo("##combo", currentItem, ImGuiComboFlags_None))
{
for (auto const& model : models)
{
bool isSelected = currentItem == model.name;
if (ImGui::Selectable(model.name.data(), isSelected))
{
auto const data {SHAssetManager::GetConstData<SHModelAsset>(model.id)};
if (!data->anims.empty())
{
const auto animContainerId = SHAssetManager::CreateNewAsset(AssetType::ANIM_CONTAINER, model.name + "Anims");
auto data = SHAssetManager::GetData<SHAnimClipContainerAsset>(animContainerId);
data->animRawDataAssetId = model.id;
SHAssetManager::SaveAsset(animContainerId);
if (auto animInspector = SHEditorWindowManager::GetEditorWindow<SHRawAnimInspector>())
{
animInspector->Open(animContainerId);
}
QueueRefresh();
isAssetBeingCreated = false;
ImGui::CloseCurrentPopup();
}
}
if (isSelected)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
}
ImGui::EndPopup(); ImGui::EndPopup();
} }
//if (ImGui::BeginMenu("Create Asset")) //if (ImGui::BeginMenu("Create Asset"))

View File

@ -454,7 +454,8 @@ namespace SHADE
{ {
if(auto entityTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid)) if(auto entityTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid))
{ {
editorCam->SetPosition(entityTransform->GetWorldPosition() + SHVec3(0.5f)); SHVec3 scale = entityTransform->GetLocalScale();
editorCam->SetPosition(entityTransform->GetWorldPosition() + scale * 0.5f);
camSystem->CameraLookAt(*editorCam, entityTransform->GetWorldPosition()); camSystem->CameraLookAt(*editorCam, entityTransform->GetWorldPosition());
camSystem->UpdateEditorCamera(SHFrameRateController::GetRawDeltaTime()); camSystem->UpdateEditorCamera(SHFrameRateController::GetRawDeltaTime());
} }

View File

@ -30,6 +30,7 @@
#include "../SHEditorWindowManager.h" #include "../SHEditorWindowManager.h"
#include "../AssetBrowser/SHAssetBrowser.h" #include "../AssetBrowser/SHAssetBrowser.h"
#include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h" #include "Graphics/MiddleEnd/TrajectoryRendering/SHTrajectoryRenderableComponent.h"
#include "Animation/SHAnimationClip.h"
namespace SHADE namespace SHADE
{ {
@ -273,8 +274,8 @@ namespace SHADE
} }
if (rbType == SHRigidBodyComponent::Type::DYNAMIC || rbType == SHRigidBodyComponent::Type::KINEMATIC) //Dynamic or Kinematic only fields if (rbType == SHRigidBodyComponent::Type::DYNAMIC || rbType == SHRigidBodyComponent::Type::KINEMATIC) //Dynamic or Kinematic only fields
{ {
SHEditorWidgets::DragFloat("Drag", [component] {return component->GetDrag(); }, [component](float const& value) {component->SetDrag(value); }, "Drag"); SHEditorWidgets::DragFloat("Drag", [component] {return component->GetDrag(); }, [component](float const& value) {component->SetDrag(value); }, "Drag", 0.1f, 0.0001f, std::numeric_limits<float>::infinity());
SHEditorWidgets::DragFloat("Angular Drag", [component] {return component->GetAngularDrag(); }, [component](float const& value) {component->SetAngularDrag(value); }, "Angular Drag"); SHEditorWidgets::DragFloat("Angular Drag", [component] {return component->GetAngularDrag(); }, [component](float const& value) {component->SetAngularDrag(value); }, "Angular Drag", 0.1f, 0.0001f, std::numeric_limits<float>::infinity());
SHEditorWidgets::CheckBox("Interpolate", [component] {return component->IsInterpolating(); }, [component](bool const& value) {component->SetInterpolate(value); }, "Interpolate"); SHEditorWidgets::CheckBox("Interpolate", [component] {return component->IsInterpolating(); }, [component](bool const& value) {component->SetInterpolate(value); }, "Interpolate");
@ -377,7 +378,8 @@ namespace SHADE
( (
"Radius", "Radius",
[sphereShape] { return sphereShape->GetRelativeRadius(); }, [sphereShape] { return sphereShape->GetRelativeRadius(); },
[sphereShape](float const& value) { sphereShape->SetRelativeRadius(value); } [sphereShape](float const& value) { sphereShape->SetRelativeRadius(value); }, "Collider Radius", 0.1f,
0.0001f, std::numeric_limits<float>::infinity()
); );
} }
else if (collisionShape->GetType() == SHCollisionShape::Type::CAPSULE) else if (collisionShape->GetType() == SHCollisionShape::Type::CAPSULE)
@ -388,13 +390,15 @@ namespace SHADE
( (
"Radius", "Radius",
[capsuleShape] { return capsuleShape->GetRelativeRadius(); }, [capsuleShape] { return capsuleShape->GetRelativeRadius(); },
[capsuleShape](float const& value) { capsuleShape->SetRelativeRadius(value); } [capsuleShape](float const& value) { capsuleShape->SetRelativeRadius(value); }, "Collider Radius", 0.1f,
0.0001f, std::numeric_limits<float>::infinity()
); );
SHEditorWidgets::DragFloat SHEditorWidgets::DragFloat
( (
"Height", "Height",
[capsuleShape] { return capsuleShape->GetRelativeHeight(); }, [capsuleShape] { return capsuleShape->GetRelativeHeight(); },
[capsuleShape](float const& value) { capsuleShape->SetRelativeHeight(value); } [capsuleShape](float const& value) { capsuleShape->SetRelativeHeight(value); }, "Collider Height", 0.1f,
0.0001f, std::numeric_limits<float>::infinity()
); );
} }
@ -639,23 +643,29 @@ namespace SHADE
if (ImGui::CollapsingHeader(componentType.get_name().data())) if (ImGui::CollapsingHeader(componentType.get_name().data()))
{ {
DrawContextMenu(component); DrawContextMenu(component);
/* Animation Rig */
Handle<SHRig> const& rig = component->GetRig(); Handle<SHRig> const& rig = component->GetRig();
const auto RIG_NAME = rig ? SHResourceManager::GetAssetName<SHRig>(rig).value_or("") : ""; const auto RIG_NAME = rig ? SHResourceManager::GetAssetName<SHRig>(rig).value_or("") : "";
SHEditorWidgets::DragDropReadOnlyField<AssetID>("Rig", RIG_NAME, [component]() SHEditorWidgets::DragDropReadOnlyField<AssetID>
{ (
Handle<SHRig> const& rig = component->GetRig(); "Rig", RIG_NAME, [component]()
return SHResourceManager::GetAssetID<SHRig>(rig).value_or(0);
},
[component](AssetID const& id)
{
if (SHAssetManager::GetType(id) != AssetType::MODEL)
{ {
SHLOG_WARNING("Attempted to assign non mesh asset to Renderable Mesh property!") Handle<SHRig> const& rig = component->GetRig();
return; return SHResourceManager::GetAssetID<SHRig>(rig).value_or(0);
} },
component->SetRig(SHResourceManager::LoadOrGet<SHRig>(id)); [component](AssetID const& id)
SHResourceManager::FinaliseChanges(); {
}, SHDragDrop::DRAG_RESOURCE); if (SHAssetManager::GetType(id) != AssetType::MODEL)
{
SHLOG_WARNING("Attempted to assign non mesh rig asset to Animator Rig property!")
return;
}
component->SetRig(SHResourceManager::LoadOrGet<SHRig>(id));
SHResourceManager::FinaliseChanges();
},
SHDragDrop::DRAG_RESOURCE
);
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
{ {
if (Handle<SHRig> const& rig = component->GetRig()) if (Handle<SHRig> const& rig = component->GetRig())
@ -664,28 +674,34 @@ namespace SHADE
SHEditorWindowManager::GetEditorWindow<SHAssetBrowser>()->SetScrollTo(assetID); SHEditorWindowManager::GetEditorWindow<SHAssetBrowser>()->SetScrollTo(assetID);
} }
} }
Handle<SHAnimationClip> const& clip = component->GetCurrentClip();
const auto CLIP_NAME = clip ? SHResourceManager::GetAssetName<SHAnimationClip>(clip).value_or("") : ""; /* Animation Controller */
SHEditorWidgets::DragDropReadOnlyField<AssetID>("Clip", CLIP_NAME, Handle<SHAnimationController> animController = component->GetAnimationController();
[component]() const auto AC_NAME = animController ? SHResourceManager::GetAssetName<SHAnimationController>(animController).value_or("") : "";
{ SHEditorWidgets::DragDropReadOnlyField<AssetID>
Handle<SHAnimationClip> const& clip = component->GetCurrentClip(); (
return SHResourceManager::GetAssetID<SHAnimationClip>(clip).value_or(0); "Animation Controller", AC_NAME, [component]()
},
[component](AssetID const& id)
{
if (SHAssetManager::GetType(id) != AssetType::MODEL)
{ {
SHLOG_WARNING("Attempted to assign non mesh asset to Renderable Mesh property!") Handle<SHAnimationController> ac = component->GetAnimationController();
return; return SHResourceManager::GetAssetID<SHAnimationController>(ac).value_or(0);
} },
component->SetClip(SHResourceManager::LoadOrGet<SHAnimationClip>(id)); [component](AssetID const& id)
}, SHDragDrop::DRAG_RESOURCE); {
if (SHAssetManager::GetType(id) != AssetType::ANIM_CONTROLLER)
{
SHLOG_WARNING("Attempted to assign non animation controller asset to Animator Animation Controller property!")
return;
}
component->SetAnimationController(SHResourceManager::LoadOrGet<SHAnimationController>(id));
SHResourceManager::FinaliseChanges();
},
SHDragDrop::DRAG_RESOURCE
);
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
{ {
if (Handle<SHAnimationClip> const& clip = component->GetCurrentClip()) if (Handle<SHAnimationController> ac = component->GetAnimationController())
{ {
AssetID assetID = SHResourceManager::GetAssetID<SHAnimationClip>(clip).value_or(0); AssetID assetID = SHResourceManager::GetAssetID<SHAnimationController>(ac).value_or(0);
SHEditorWindowManager::GetEditorWindow<SHAssetBrowser>()->SetScrollTo(assetID); SHEditorWindowManager::GetEditorWindow<SHAssetBrowser>()->SetScrollTo(assetID);
} }
} }

View File

@ -26,6 +26,8 @@
#include "SHEditorComponentView.h" #include "SHEditorComponentView.h"
#include "AudioSystem/SHAudioListenerComponent.h" #include "AudioSystem/SHAudioListenerComponent.h"
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderableComponent.h"
#include "Camera/SHCameraSystem.h"
#include "FRC/SHFramerateController.h"
namespace SHADE namespace SHADE
{ {
@ -106,6 +108,7 @@ namespace SHADE
{ {
if (editor && !editor->selectedEntities.empty()) if (editor && !editor->selectedEntities.empty())
{ {
DrawMenuBar();
EntityID const& eid = editor->selectedEntities[0]; EntityID const& eid = editor->selectedEntities[0];
SHEntity* entity = SHEntityManager::GetEntityByID(eid); SHEntity* entity = SHEntityManager::GetEntityByID(eid);
SHSceneNode* entityNode = SHSceneManager::GetCurrentSceneGraph().GetNode(eid); SHSceneNode* entityNode = SHSceneManager::GetCurrentSceneGraph().GetNode(eid);
@ -114,6 +117,7 @@ namespace SHADE
ImGui::End(); ImGui::End();
return; return;
} }
ImGui::TextColored(ImGuiColors::green, "EID: %zu", eid); ImGui::TextColored(ImGuiColors::green, "EID: %zu", eid);
SHEditorWidgets::CheckBox("##IsActive", [entityNode]()->bool {return entityNode->IsActive(); }, [entityNode](bool const& active) {entityNode->SetActive(active); }); SHEditorWidgets::CheckBox("##IsActive", [entityNode]()->bool {return entityNode->IsActive(); }, [entityNode](bool const& active) {entityNode->SetActive(active); });
ImGui::SameLine(); ImGui::SameLine();
@ -222,4 +226,36 @@ namespace SHADE
{ {
SHEditorWindow::Exit(); SHEditorWindow::Exit();
} }
void SHEditorInspector::DrawMenuBar()
{
if(ImGui::BeginMenuBar())
{
EntityID const& eid = editor->selectedEntities[0];
SHEntity* entity = SHEntityManager::GetEntityByID(eid);
SHSceneNode* entityNode = SHSceneManager::GetCurrentSceneGraph().GetNode(eid);
if (!entity || !entityNode)
{
ImGui::EndMenuBar();
return;
}
if (ImGui::SmallButton("Look At"))
{
editor->selectedEntities.clear();
editor->selectedEntities.push_back(eid);
if (auto camSystem = SHSystemManager::GetSystem<SHCameraSystem>())
{
if (auto editorCam = camSystem->GetEditorCamera())
{
if (auto entityTransform = SHComponentManager::GetComponent_s<SHTransformComponent>(eid))
{
editorCam->SetPosition(entityTransform->GetWorldPosition() + SHVec3(0.5f));
camSystem->CameraLookAt(*editorCam, entityTransform->GetWorldPosition());
camSystem->UpdateEditorCamera(SHFrameRateController::GetRawDeltaTime());
}
}
}
}
ImGui::EndMenuBar();
}
}
} }

View File

@ -25,6 +25,6 @@ namespace SHADE
void Exit() override; void Exit() override;
private: private:
void DrawMenuBar();
}; };
} }

View File

@ -358,6 +358,7 @@ namespace SHADE
void SHEditorMenuBar::DrawPhysicsSettings() noexcept void SHEditorMenuBar::DrawPhysicsSettings() noexcept
{ {
ImGui::SetNextWindowSize({400.0f, 0.0f});
if (ImGui::BeginMenu("Physics Settings")) if (ImGui::BeginMenu("Physics Settings"))
{ {
if (auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>()) if (auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>())

View File

@ -0,0 +1,278 @@
/************************************************************************************//*!
\file SHRawAnimInspector.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 1, 2023
\brief Contains the definition of SHRawAnimInspector's functions.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#include "SHpch.h"
#include "SHRawAnimInspector.h"
// STL Includes
#include <format>
// External Dependencies
#include <imgui.h>
#include <misc/cpp/imgui_stdlib.h>
// Project Includes
#include "Editor/IconsMaterialDesign.h"
#include "Animation/SHAnimationClip.h"
#include "Resource/SHResourceManager.h"
#include "Editor/EditorWindow/SHEditorWindowManager.h"
#include "Editor/SHEditorUI.h"
#include "Assets/SHAssetManager.h"
#include "Editor/SHEditorWidgets.hpp"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* SHAnimClipCreatePrompt - Constructors/Destructors */
/*-----------------------------------------------------------------------------------*/
SHAnimClipCreatePrompt::SHAnimClipCreatePrompt()
: SHPopUpWindow("Create Animation Clip", true, 0, 0) {}
/*---------------------------------------------------------------------------------*/
/* SHAnimClipCreatePrompt - Lifecycle Functions */
/*---------------------------------------------------------------------------------*/
void SHAnimClipCreatePrompt::Init(
SHAsset* contAsset,
SHAnimClipContainerAsset* cont,
Handle<SHRawAnimation> rawAnim,
std::function<void(AssetID)> onClose
)
{
containerAsset = contAsset;
container = cont;
rawAnimation = rawAnim;
// Set default parameters
if (rawAnimation)
{
newAssetName.clear();
firstIndex = 0;
lastIndex = rawAnimation->GetTotalFrames();
}
// Assign callback
this->onClose = onClose;
}
void SHAnimClipCreatePrompt::Draw()
{
if (Begin())
{
// Properties
SHEditorUI::InputTextField("Name", newAssetName);
SHEditorUI::PushID(0);
SHEditorUI::InputUnsignedInt("First Frame Index", firstIndex);
SHEditorUI::PopID();
SHEditorUI::PushID(1);
SHEditorUI::InputUnsignedInt("Last Frame Index", lastIndex);
SHEditorUI::PopID();
// Invalid values
const bool INVALID_CONFIG = newAssetName.empty() || firstIndex > lastIndex;
// Buttons
ImGui::BeginDisabled(INVALID_CONFIG);
{
if (ImGui::Button("Save"))
{
// Generate new asset
const AssetID NEW_ASSET_ID = SHAssetManager::CreateNewSubAsset(AssetType::ANIM_CLIP, newAssetName, containerAsset->id);
auto animClip = SHAssetManager::GetData<SHAnimClipAsset>(NEW_ASSET_ID);
animClip->name = newAssetName;
animClip->firstIndex = firstIndex;
animClip->lastIndex = lastIndex;
animClip->animRawDataAssetId = SHResourceManager::GetAssetID<SHRawAnimation>(rawAnimation).value_or(0);
SHAssetManager::SaveAsset(containerAsset->id);
// Close
isOpen = false;
if (onClose)
onClose(NEW_ASSET_ID);
ImGui::CloseCurrentPopup();
}
}
ImGui::EndDisabled();
ImGui::SameLine();
if (ImGui::Button("Cancel"))
{
// Close
isOpen = false;
if (onClose)
onClose(INVALID_ASSET_ID);
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}
/*-----------------------------------------------------------------------------------*/
/* Cosntructors/Destructors */
/*-----------------------------------------------------------------------------------*/
SHRawAnimInspector::SHRawAnimInspector()
: SHEditorWindow("Animation Editor", ImGuiWindowFlags_MenuBar)
{}
/*-----------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*-----------------------------------------------------------------------------------*/
void SHRawAnimInspector::Init()
{
SHEditorWindow::Init();
SHEditorWindowManager::CreatePopupWindow<SHAnimClipCreatePrompt>();
}
void SHRawAnimInspector::Update()
{
SHEditorWindow::Update();
// Draw
if (Begin())
{
// Ignore if no asset
if (container)
{
drawMenuBar();
// Button to add a new clip
if (ImGui::Button(std::format("{} Create Animation Clip", ICON_MD_ADD).data()))
{
auto prompt = SHEditorWindowManager::GetPopupWindow<SHAnimClipCreatePrompt>();
prompt->Init(containerAsset, container, currRawAnim, [this](AssetID createdAssetId)
{
if (createdAssetId != INVALID_ASSET_ID)
{
childAnimClips.emplace_back(SHResourceManager::LoadOrGet<SHAnimationClip>(createdAssetId));
}
});
prompt->isOpen = true;
}
// Render all animation clips
if (SHEditorUI::CollapsingHeader("Existing Animation Clips"))
{
ImGui::Indent();
int i = 0;
for (auto animClip : childAnimClips)
{
ImGui::PushID(i++);
bool changed = false;
std::optional<std::string> animClipName = SHResourceManager::GetAssetName<SHAnimationClip>(animClip);
int firstIndex = animClip->GetStartFrameIndex();
int endIndex = animClip->GetEndFrameIndex();
ImGui::Separator();
ImGui::Text(animClipName.has_value() ? animClipName.value().c_str() : "");
changed |= SHEditorWidgets::SliderInt
(
"Start", 0, currRawAnim->GetTotalFrames(),
[&]() { return firstIndex; },
[&](int i) { firstIndex = i; }
);
changed |= SHEditorWidgets::SliderInt
(
"End", 0, currRawAnim->GetTotalFrames(),
[&]() { return endIndex; },
[&](int i) { endIndex = i; }
);
// If there's a change we need to commit changes
if (changed && firstIndex < endIndex)
{
// Update runtime asset
*animClip = SHAnimationClip(currRawAnim, firstIndex, endIndex);
// Update serialized asset
auto assetId = SHResourceManager::GetAssetID(animClip);
if (assetId.has_value())
{
auto const animAsset = SHAssetManager::GetData<SHAnimClipAsset>(assetId.value());
animAsset->firstIndex = firstIndex;
animAsset->lastIndex = endIndex;
SHAssetManager::SaveAsset(containerAsset->id);
}
}
ImGui::PopID();
}
// Extra separator if there is more than one
if (!childAnimClips.empty())
ImGui::Separator();
ImGui::Unindent();
}
}
else
{
SHEditorUI::CenteredText("Double click on a model file to inspect its animations here.");
}
}
ImGui::End();
}
void SHRawAnimInspector::Exit()
{
SHEditorWindow::Exit();
}
/*-----------------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------------*/
void SHRawAnimInspector::Open(AssetID assetId)
{
containerAsset = SHAssetManager::GetAsset(assetId);
container = SHAssetManager::GetData<SHAnimClipContainerAsset>(assetId);
// Load anim clips
if (container)
{
currRawAnim = SHResourceManager::LoadOrGet<SHRawAnimation>(container->animRawDataAssetId);
childAnimClips = getChildAnimClips(assetId);
}
else
{
childAnimClips.clear();
}
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
void SHRawAnimInspector::drawMenuBar()
{
if (ImGui::BeginMenuBar())
{
if (ImGui::Button(std::format("{} Save", ICON_MD_SAVE).data()))
{
}
const std::string& ASSET_NAME = SHResourceManager::GetAssetName<SHRawAnimation>(currRawAnim).value_or("Unnamed Asset");
ImGui::Text(ASSET_NAME.c_str());
ImGui::EndMenuBar();
}
}
std::vector<Handle<SHAnimationClip>> SHRawAnimInspector::getChildAnimClips(AssetID containerId)
{
auto const containerAsset {*SHAssetManager::GetAsset(containerId)};
std::vector<Handle<SHAnimationClip>> animClips;
for (auto const& asset : containerAsset.subAssets)
{
animClips.emplace_back(SHResourceManager::LoadOrGet<SHAnimationClip>(asset->id));
}
return animClips;
}
}

View File

@ -0,0 +1,110 @@
/************************************************************************************//*!
\file SHRawAnimInspector.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 2, 2023
\brief Contains the definition of SHRawAnimInspector.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
// Project Includes
#include "Assets/SHAssetMacros.h"
#include "Editor/EditorWindow/SHEditorWindow.h"
#include "Resource/SHHandle.h"
#include "Animation/SHRawAnimation.h"
#include "Assets/SHAsset.h"
#include "Assets/Asset Types/SHAnimClipContainerAsset.h"
#include "Editor/EditorWindow/SHPopUpWindow.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
struct SHAnimClipAsset;
class SHRawAnimation;
class SHAnimationClip;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/// <summary>
/// Prompt for creating an animation clip. Init() must be called to pass in the correct
/// SHRawAnimation that the created clip will use.
/// </summary>
class SHAnimClipCreatePrompt : public SHPopUpWindow
{
public:
/*---------------------------------------------------------------------------------*/
/* Constructors/Destructors */
/*---------------------------------------------------------------------------------*/
SHAnimClipCreatePrompt();
/*---------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*---------------------------------------------------------------------------------*/
void Init(
SHAsset* contAsset,
SHAnimClipContainerAsset* cont,
Handle<SHRawAnimation> rawAnim,
std::function<void(AssetID)> onClose = nullptr
);
void Draw() override;
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
std::string newAssetName;
uint32_t firstIndex = 0;
uint32_t lastIndex = 0;
Handle<SHRawAnimation> rawAnimation;
SHAsset* containerAsset{nullptr};
SHAnimClipContainerAsset* container{nullptr};
std::function<void(AssetID)> onClose;
};
/// <summary>
/// Editor for generating SHAnimationClips from a single SHRawAnimation object.
/// </summary>
class SHRawAnimInspector final : public SHEditorWindow
{
public:
/*---------------------------------------------------------------------------------*/
/* Constructors/Destructors */
/*---------------------------------------------------------------------------------*/
SHRawAnimInspector();
~SHRawAnimInspector() = default;
/*---------------------------------------------------------------------------------*/
/* Lifecycle Functions */
/*---------------------------------------------------------------------------------*/
void Init() override;
void Update() override;
void Exit() override;
/*---------------------------------------------------------------------------------*/
/* Usage Functions */
/*---------------------------------------------------------------------------------*/
void Open(AssetID assetId);
private:
/*---------------------------------------------------------------------------------*/
/* Data Members */
/*---------------------------------------------------------------------------------*/
SHAsset* containerAsset{nullptr};
SHAnimClipContainerAsset* container {nullptr};
Handle<SHRawAnimation> currRawAnim;
std::vector<Handle<SHAnimationClip>> childAnimClips;
/*---------------------------------------------------------------------------------*/
/* Helper Functions */
/*---------------------------------------------------------------------------------*/
void drawMenuBar();
std::vector<Handle<SHAnimationClip>> getChildAnimClips(AssetID containerId);
};
}

View File

@ -1,10 +1,12 @@
#pragma once #pragma once
#include "MenuBar/SHEditorMenuBar.h" //Menu Bar #include "MenuBar/SHEditorMenuBar.h" // Menu Bar
#include "HierarchyPanel/SHHierarchyPanel.h" //Hierarchy Panel #include "HierarchyPanel/SHHierarchyPanel.h" // Hierarchy Panel
#include "Inspector/SHEditorInspector.h" //Inspector #include "Inspector/SHEditorInspector.h" // Inspector
#include "Profiling/SHEditorProfiler.h" //Profiler #include "Profiling/SHEditorProfiler.h" // Profiler
#include "ViewportWindow/SHEditorViewport.h" //Editor Viewport #include "ViewportWindow/SHEditorViewport.h" // Editor Viewport
#include "AssetBrowser/SHAssetBrowser.h" //Asset Browser #include "AssetBrowser/SHAssetBrowser.h" // Asset Browser
#include "MaterialInspector/SHMaterialInspector.h" //Material Inspector #include "MaterialInspector/SHMaterialInspector.h" // Material Inspector
#include "ColliderTagPanel/SHColliderTagPanel.h" //Collider Tag Panel #include "ColliderTagPanel/SHColliderTagPanel.h" // Collider Tag Panel
#include "InputBindings/SHInputBindingsPanel.h" //Input Bindings #include "InputBindings/SHInputBindingsPanel.h" // Input Bindings
#include "EditorWindow/Animation/SHAnimationControllerEditor.h" // Animation Controller Editor
#include "EditorWindow/RawAnimationInspector/SHRawAnimInspector.h" // Raw Animation Inspector

View File

@ -39,6 +39,7 @@
//|| Library Includes || //|| Library Includes ||
//#==============================================================# //#==============================================================#
#include <imgui.h> #include <imgui.h>
#include <imnodes.h>
#include <SDL.h> #include <SDL.h>
#include <rttr/registration> #include <rttr/registration>
#include <ImGuizmo.h> #include <ImGuizmo.h>
@ -97,6 +98,10 @@ namespace SHADE
SHLOG_CRITICAL("Failed to create ImGui Context") SHLOG_CRITICAL("Failed to create ImGui Context")
} }
} }
if (ImNodes::CreateContext() == nullptr)
{
SHLOG_CRITICAL("Failed to create ImNodes Context")
}
#ifdef SHEDITOR #ifdef SHEDITOR
editorConfig = &SHConfigurationManager::LoadEditorConfig(); editorConfig = &SHConfigurationManager::LoadEditorConfig();
@ -108,11 +113,14 @@ namespace SHADE
SHEditorWindowManager::CreateEditorWindow<SHAssetBrowser>(); SHEditorWindowManager::CreateEditorWindow<SHAssetBrowser>();
SHEditorWindowManager::CreateEditorWindow<SHMaterialInspector>(); SHEditorWindowManager::CreateEditorWindow<SHMaterialInspector>();
SHEditorWindowManager::CreateEditorWindow<SHColliderTagPanel>(); SHEditorWindowManager::CreateEditorWindow<SHColliderTagPanel>();
SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>();
SHEditorWindowManager::CreateEditorWindow<SHInputBindingsPanel>(); SHEditorWindowManager::CreateEditorWindow<SHInputBindingsPanel>();
SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
SHEditorWindowManager::CreateEditorWindow<SHAnimationControllerEditor>();
SHEditorWindowManager::CreateEditorWindow<SHRawAnimInspector>();
SHEditorWindowManager::CreateEditorWindow<SHHierarchyPanel>();
SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>(); SHEditorWindowManager::CreateEditorWindow<SHEditorViewport>();
SHEditorWindowManager::CreateEditorWindow<SHEditorInspector>();
//Add popup windows //Add popup windows
SHEditorWindowManager::CreatePopupWindow<SHSceneSavePrompt>(); SHEditorWindowManager::CreatePopupWindow<SHSceneSavePrompt>();
@ -340,6 +348,7 @@ namespace SHADE
{ {
window->Init(); window->Init();
} }
ImNodes::DestroyContext();
ImGui_ImplVulkan_Shutdown(); ImGui_ImplVulkan_Shutdown();
ImGui_ImplSDL2_Shutdown(); ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext(); ImGui::DestroyContext();
@ -669,6 +678,12 @@ namespace SHADE
SaveScene(); SaveScene();
} }
} }
if(editorState == State::PLAY && ImGui::IsKeyReleased(ImGuiKey_LeftAlt))
{
SHInputManager::SetMouseCentering(!SHInputManager::GetMouseCentering());
SHWindow::SetMouseVisible(!SHWindow::GetMouseVisible());
}
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z)) if (ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z))
{ {
SHCommandManager::RedoCommand(); SHCommandManager::RedoCommand();

View File

@ -137,6 +137,15 @@ namespace SHADE
{ {
ImGui::Text(title.c_str()); ImGui::Text(title.c_str());
} }
void SHEditorUI::CenteredText(const std::string& text)
{
const auto WINDOW_SIZE = ImGui::GetWindowSize();
const auto TEXT_SIZE = ImGui::CalcTextSize(text.c_str());
ImGui::SetCursorPosX((WINDOW_SIZE.x - TEXT_SIZE.x) * 0.5f);
ImGui::SetCursorPosY((WINDOW_SIZE.y - TEXT_SIZE.y) * 0.5f);
ImGui::Text(text.c_str());
}
bool SHEditorUI::SmallButton(const std::string& title) bool SHEditorUI::SmallButton(const std::string& title)
{ {
return ImGui::SmallButton(title.c_str()); return ImGui::SmallButton(title.c_str());
@ -369,9 +378,9 @@ namespace SHADE
// Attempt to get the asset's data for rendering editor // Attempt to get the asset's data for rendering editor
auto asset = SHAssetManager::GetAsset(value); auto asset = SHAssetManager::GetAsset(value);
std::string assetName; std::string assetName;
if (asset.has_value()) if (asset)
{ {
assetName = asset.value().name; assetName = asset->name;
} }
// Editor // Editor
@ -382,9 +391,9 @@ namespace SHADE
{ {
// Check if type matches // Check if type matches
auto draggedAsset = SHAssetManager::GetAsset(*payload); auto draggedAsset = SHAssetManager::GetAsset(*payload);
if (draggedAsset.has_value() && draggedAsset.value().type == type) if (draggedAsset && draggedAsset->type == type)
{ {
value = draggedAsset.value().id; value = draggedAsset->id;
changed = true; changed = true;
} }
SHDragDrop::EndTarget(); SHDragDrop::EndTarget();

View File

@ -90,7 +90,7 @@ namespace SHADE
/// <returns>True if the header is open, false otherwise.</returns> /// <returns>True if the header is open, false otherwise.</returns>
static bool CollapsingHeader(const std::string& title, bool* isHovered = nullptr); static bool CollapsingHeader(const std::string& title, bool* isHovered = nullptr);
static void SameLine(); static void SameLine();
static void Separator(); static void Separator();
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - Queries */ /* ImGui Wrapper Functions - Queries */
@ -98,9 +98,9 @@ namespace SHADE
static bool IsItemHovered(); static bool IsItemHovered();
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* ImGui Wrapper Functions - Menu */ /* ImGui Wrapper Functions - Menu */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
static bool BeginMenu(const std::string& label); static bool BeginMenu(const std::string& label);
static bool BeginMenu(const std::string& label, const char* icon); static bool BeginMenu(const std::string& label, const char* icon);
static void EndMenu(); static void EndMenu();
static void BeginTooltip(); static void BeginTooltip();
@ -150,6 +150,12 @@ namespace SHADE
/// <param name="title">Text to display.</param> /// <param name="title">Text to display.</param>
static void Text(const std::string& title); static void Text(const std::string& title);
/// <summary> /// <summary>
/// Renders a text widget that is vertically and horizontally centered in the current
/// window.
/// </summary>
/// <param name="text">Text to display.</param>
static void CenteredText(const std::string& text);
/// <summary>
/// Creates a small inline button widget. /// Creates a small inline button widget.
/// <br/> /// <br/>
/// Wraps up ImGui::SmallButton(). /// Wraps up ImGui::SmallButton().
@ -164,8 +170,8 @@ namespace SHADE
/// </summary> /// </summary>
/// <param name="title">Text to display.</param> /// <param name="title">Text to display.</param>
/// <returns>True if button was pressed.</returns> /// <returns>True if button was pressed.</returns>
static bool Button(const std::string& title); static bool Button(const std::string& title);
static bool Selectable(const std::string& label); static bool Selectable(const std::string& label);
static bool Selectable(const std::string& label, const char* icon); static bool Selectable(const std::string& label, const char* icon);
/// <summary> /// <summary>
/// Creates a checkbox widget for boolean input. /// Creates a checkbox widget for boolean input.

View File

@ -418,12 +418,16 @@ namespace SHADE
} }
template<typename T> template<typename T>
static bool DragDropReadOnlyField(std::string const& label, std::string_view const& fieldVTextValue, std::function<T (void)> const& get, std::function<void(T const&)> const& set, SHDragDrop::DragDropTag const& dragDropTag, std::string_view const& tooltip = {}) static bool DragDropReadOnlyField(std::string const& label, std::string_view const& fieldVTextValue, std::function<T (void)> const& get, std::function<void(T const&)> const& set, SHDragDrop::DragDropTag const& dragDropTag, std::string_view const& tooltip = {}, float customWidth = -1.0f)
{ {
std::string text = fieldVTextValue.data(); std::string text = fieldVTextValue.data();
ImGui::BeginGroup(); ImGui::BeginGroup();
ImGui::PushID(label.data()); ImGui::PushID(label.data());
TextLabel(label); TextLabel(label);
if (customWidth > 0.0f)
{
ImGui::SetNextItemWidth(customWidth);
}
bool changed = ImGui::InputText("##inputText", &text, ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_AutoSelectAll, nullptr, nullptr); bool changed = ImGui::InputText("##inputText", &text, ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_AutoSelectAll, nullptr, nullptr);
if(SHDragDrop::BeginTarget()) if(SHDragDrop::BeginTarget())
{ {

View File

@ -186,7 +186,7 @@ namespace SHADE
.flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount, .flags = vk::DescriptorBindingFlagBits::eVariableDescriptorCount,
}; };
// For global data (generic data and textures) // For global data (generic data and textures). NOT USED.
Handle<SHVkDescriptorSetLayout> shadowMapDescLayout = logicalDevice->CreateDescriptorSetLayout({ shadowMapBinding }); Handle<SHVkDescriptorSetLayout> shadowMapDescLayout = logicalDevice->CreateDescriptorSetLayout({ shadowMapBinding });
SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, shadowMapDescLayout->GetVkHandle(), "[Descriptor Set Layout] Shadow Maps"); SET_VK_OBJ_NAME(logicalDevice, vk::ObjectType::eDescriptorSetLayout, shadowMapDescLayout->GetVkHandle(), "[Descriptor Set Layout] Shadow Maps");

View File

@ -865,32 +865,30 @@ namespace SHADE
std::string depthResourceName = "ShadowMap_Depth " + std::to_string(EVENT_DATA->lightEntity); std::string depthResourceName = "ShadowMap_Depth " + std::to_string(EVENT_DATA->lightEntity);
std::string shadowMapResourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity); std::string shadowMapResourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity);
std::string shadowMapBlurredResourceName = "ShadowMap Blurred" + std::to_string(EVENT_DATA->lightEntity); std::string shadowMapBlurredResourceName = "ShadowMap Blurred" + std::to_string(EVENT_DATA->lightEntity);
Handle<SHSubpass> gBufferWriteSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_WRITE_SUBPASS);
Handle<SHSubpass> gBufferWriteVfxSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_WRITE_VFX_SUBPASS); // we need to wait for the device to finish using the graph first
device->WaitIdle();
if (EVENT_DATA->enableShadow) if (EVENT_DATA->enableShadow)
{ {
// When the light first enables shadow rendering, we need to prepare the relevant objects to render shadows; namely renderpasses and subpasses, pipelines and descriptor sets // When the light first enables shadow rendering, we need to prepare the relevant objects to render shadows; namely renderpasses and subpasses, pipelines and descriptor sets
if (EVENT_DATA->firstEnable) if (EVENT_DATA->firstEnable)
{ {
// we need to wait for the device to finish using the graph first Handle<SHSubpass> gBufferWriteSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_WRITE_SUBPASS);
device->WaitIdle(); Handle<SHSubpass> gBufferWriteVfxSubpass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data())->GetSubpass(SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_WRITE_VFX_SUBPASS);
// Create new renderer for the light component and give it to the light component // Create new renderer for the light component and give it to the light component
Handle<SHRenderer> newRenderer = resourceManager.Create<SHRenderer>(device, swapchain->GetNumImages(), descPool, SHRenderer::PROJECTION_TYPE::ORTHOGRAPHIC); Handle<SHRenderer> newRenderer = resourceManager.Create<SHRenderer>(device, swapchain->GetNumImages(), descPool, SHRenderer::PROJECTION_TYPE::ORTHOGRAPHIC);
lightComp->SetRenderer(newRenderer); lightComp->SetRenderer(newRenderer);
// assign shadow map index to light component
lightComp->SetShadowMapIndex(lightingSubSystem->GetNumShadowMaps());
// Add the shadow map resource to the graph // Add the shadow map resource to the graph
renderGraph->AddResource(depthResourceName, { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH }, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eD32Sfloat); renderGraph->AddResource(depthResourceName, { SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH }, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eD32Sfloat);
renderGraph->AddResource(shadowMapResourceName, { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eR32G32B32A32Sfloat); renderGraph->AddResource(shadowMapResourceName, { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eR32G32B32A32Sfloat);
renderGraph->AddResource(shadowMapBlurredResourceName, { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eR32G32B32A32Sfloat); renderGraph->AddResource(shadowMapBlurredResourceName, { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, false, SHLightingSubSystem::SHADOW_MAP_WIDTH, SHLightingSubSystem::SHADOW_MAP_HEIGHT, vk::Format::eR32G32B32A32Sfloat);
// link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer. // link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer.
auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName, { depthResourceName.c_str(), shadowMapResourceName.c_str(), shadowMapBlurredResourceName.c_str() }, SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data()); auto shadowMapNode = renderGraph->AddNodeAfter(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName, { depthResourceName.c_str(), shadowMapResourceName.c_str(), shadowMapBlurredResourceName.c_str() }, SHGraphicsConstants::RenderGraphEntityNames::GBUFFER_PASS.data());
@ -929,6 +927,10 @@ namespace SHADE
// add the shadow map and the blurred version to the lighting system // add the shadow map and the blurred version to the lighting system
uint32_t const NEW_SHADOW_MAP_INDEX = lightingSubSystem->AddShadowMap(renderGraph->GetRenderGraphResource(shadowMapBlurredResourceName), EVENT_DATA->lightEntity); uint32_t const NEW_SHADOW_MAP_INDEX = lightingSubSystem->AddShadowMap(renderGraph->GetRenderGraphResource(shadowMapBlurredResourceName), EVENT_DATA->lightEntity);
// assign shadow map index to light component
lightComp->SetShadowMapIndex(NEW_SHADOW_MAP_INDEX);
// Get deferred composite node compute and modify descriptor set // Get deferred composite node compute and modify descriptor set
auto nodeCompute = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data()); auto nodeCompute = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_PASS.data())->GetNodeCompute(SHGraphicsConstants::RenderGraphEntityNames::DEFERRED_COMPOSITE_COMPUTE.data());
nodeCompute->ModifyWriteDescImageComputeResource(SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, lightingSubSystem->GetViewSamplerLayout(NEW_SHADOW_MAP_INDEX), NEW_SHADOW_MAP_INDEX); nodeCompute->ModifyWriteDescImageComputeResource(SHGraphicsConstants::DescriptorSetBindings::SHADOW_MAP_IMAGE_SAMPLER_DATA, lightingSubSystem->GetViewSamplerLayout(NEW_SHADOW_MAP_INDEX), NEW_SHADOW_MAP_INDEX);
@ -942,7 +944,8 @@ namespace SHADE
else else
{ {
// get the shadow map node // get the shadow map node
renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName)->SetDynamicActive(false); if (auto node = renderGraph->GetNode(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName))
node->SetDynamicActive(false);
} }
return eventPtr->handle; return eventPtr->handle;
@ -963,12 +966,12 @@ namespace SHADE
std::string shadowMapBlurredResourceName = "ShadowMap Blurred" + std::to_string(EVENT_DATA->lightEntity); std::string shadowMapBlurredResourceName = "ShadowMap Blurred" + std::to_string(EVENT_DATA->lightEntity);
// Remove render graph node // Remove render graph node
//renderGraph->RemoveNode(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName); renderGraph->RemoveNode(SHGraphicsConstants::RenderGraphEntityNames::SHADOW_MAP_PASS.data() + shadowMapResourceName);
// Remove render graph resource // Remove render graph resource
//renderGraph->RemoveResource(depthResourceName); renderGraph->RemoveResource(depthResourceName);
//renderGraph->RemoveResource(shadowMapResourceName); renderGraph->RemoveResource(shadowMapResourceName);
//renderGraph->RemoveResource(shadowMapBlurredResourceName); renderGraph->RemoveResource(shadowMapBlurredResourceName);
// Register light component shadow map index into light system as recyclable // Register light component shadow map index into light system as recyclable
lightingSubSystem->RemoveShadowMap (EVENT_DATA->lightEntity); lightingSubSystem->RemoveShadowMap (EVENT_DATA->lightEntity);

View File

@ -120,21 +120,17 @@ namespace SHADE
{ {
lightData.castShadows = flag; lightData.castShadows = flag;
// If the flag is true // Create new event and broadcast it
if (flag) SHLightShadowEvent newEvent;
{ newEvent.lightEntity = GetEID();
// Create new event and broadcast it
SHLightShadowEvent newEvent;
newEvent.lightEntity = GetEID();
// If shadow map index is invalid, that means light is enabling shadow for the first time. // If shadow map index is invalid, that means light is enabling shadow for the first time.
newEvent.firstEnable = (lightData.shadowMapIndex == SHLightData::INVALID_SHADOW_MAP_INDEX); newEvent.firstEnable = (lightData.shadowMapIndex == SHLightData::INVALID_SHADOW_MAP_INDEX);
// pass the flag to the event // pass the flag to the event
newEvent.enableShadow = flag; newEvent.enableShadow = flag;
SHEventManager::BroadcastEvent<SHLightShadowEvent>(newEvent, SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT); SHEventManager::BroadcastEvent<SHLightShadowEvent>(newEvent, SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT);
}
} }

View File

@ -62,15 +62,13 @@ namespace SHADE
// write view projection matrix if renderer is available // write view projection matrix if renderer is available
auto lightRenderer = lightComp->GetRenderer(); auto lightRenderer = lightComp->GetRenderer();
if (lightRenderer) if (lightRenderer)
{
lightPtr->pvMatrix = lightRenderer->GetCPUCameraData().viewProjectionMatrix; lightPtr->pvMatrix = lightRenderer->GetCPUCameraData().viewProjectionMatrix;
// Boolean to cast shadows in first 8 bits (1 byte) // Boolean to cast shadows in first 8 bits (1 byte)
lightPtr->shadowData = lightData.castShadows; lightPtr->shadowData = lightData.castShadows;
// Next 24 bits for shadow map index // Next 24 bits for shadow map index
lightPtr->shadowData |= (lightData.shadowMapIndex << 8); lightPtr->shadowData |= (lightData.shadowMapIndex << 8);
}
break; break;
} }
case SH_LIGHT_TYPE::POINT: case SH_LIGHT_TYPE::POINT:
@ -526,7 +524,7 @@ namespace SHADE
if (auto renderer = light.GetRenderer()) if (auto renderer = light.GetRenderer())
{ {
//SHMatrix orthoMatrix = SHMatrix::OrthographicRH() //SHMatrix orthoMatrix = SHMatrix::OrthographicRH()
renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(15.0f, 15.0f, 1.0f, 80.0f)); renderer->UpdateDataManual(frameIndex, GetViewMatrix(&light), SHMatrix::OrthographicLH(20.0f, 20.0f, 1.0f, 80.0f));
} }
auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type); auto enumValue = SHUtilities::ConvertEnum(light.GetLightData().type);
@ -636,7 +634,7 @@ namespace SHADE
shadowMapImageSamplers.emplace_back(NEW_IMAGE_VIEW, shadowMapSampler, vk::ImageLayout::eShaderReadOnlyOptimal); shadowMapImageSamplers.emplace_back(NEW_IMAGE_VIEW, shadowMapSampler, vk::ImageLayout::eShaderReadOnlyOptimal);
// Add to container of shadow maps // Add to container of shadow maps
shadowMapIndexing.emplace(lightEntity, static_cast<uint32_t> (shadowMaps.size())); shadowMapIndexing.emplace(lightEntity, static_cast<uint32_t> (shadowMaps.size() - 1u));
usedIndex = static_cast<uint32_t>(shadowMapImageSamplers.size()) - 1u; usedIndex = static_cast<uint32_t>(shadowMapImageSamplers.size()) - 1u;
} }

View File

@ -22,19 +22,32 @@ namespace SHADE
} }
void SHTrajectoryRenderableComponent::ClearPositions(void) noexcept void SHTrajectoryRenderableComponent::SimulateTrajectory(EntityID eid, SHVec3 force, float timestep, uint32_t maxSteps) noexcept
{ {
positions.clear(); entityToSimulate = eid;
simulationForce = force;
simulationTimestep = timestep;
simulationMaxSteps = maxSteps;
} }
bool SHTrajectoryRenderableComponent::HasPositions(void) const noexcept float SHTrajectoryRenderableComponent::GetSimulationTimestep(void) const noexcept
{ {
return !positions.empty(); return simulationTimestep;
} }
std::vector<SHVec3> SHTrajectoryRenderableComponent::GetPositions(void) const noexcept void SHTrajectoryRenderableComponent::ResetSimulationInfo(void) noexcept
{ {
return positions; entityToSimulate = MAX_EID;
}
uint32_t SHTrajectoryRenderableComponent::GetSimulationMaxSteps(void) const noexcept
{
return simulationMaxSteps;
}
SHVec3 SHTrajectoryRenderableComponent::GetSimulationForce(void) const noexcept
{
return simulationForce;
} }
Handle<SHMesh> SHTrajectoryRenderableComponent::GetMesh(void) const noexcept Handle<SHMesh> SHTrajectoryRenderableComponent::GetMesh(void) const noexcept
@ -67,16 +80,16 @@ namespace SHADE
return colorEvolveRate; return colorEvolveRate;
} }
EntityID SHTrajectoryRenderableComponent::GetEntityToSimulate(void) const noexcept
{
return entityToSimulate;
}
void SHTrajectoryRenderableComponent::SetMesh(Handle<SHMesh> newMesh) noexcept void SHTrajectoryRenderableComponent::SetMesh(Handle<SHMesh> newMesh) noexcept
{ {
mesh = newMesh; mesh = newMesh;
} }
void SHTrajectoryRenderableComponent::SetPositions(std::vector<SHVec3> const& inPositions) noexcept
{
positions = inPositions;
}
void SHTrajectoryRenderableComponent::SetStartColor(SHVec3 color) noexcept void SHTrajectoryRenderableComponent::SetStartColor(SHVec3 color) noexcept
{ {
startColor = color; startColor = color;

View File

@ -17,9 +17,6 @@ namespace SHADE
//! Mesh used to render the trajectory //! Mesh used to render the trajectory
Handle<SHMesh> mesh; Handle<SHMesh> mesh;
//! positions to plot for rendering. Will be cleared every frame.
std::vector<SHVec3> positions;
//! Starting color of the trajectory //! Starting color of the trajectory
SHVec3 startColor; SHVec3 startColor;
@ -35,32 +32,48 @@ namespace SHADE
//! evolving rate of the color //! evolving rate of the color
float colorEvolveRate; float colorEvolveRate;
//! Used for the trajectory simulation. Indicates the time to pass before
//! plotting a point in the simulation
float simulationTimestep;
//! Entity to simulate trajectory of
EntityID entityToSimulate;
//! Force to use during simulation of
SHVec3 simulationForce;
//! max points to be plotted in the simulation before stopping.
//! Note that the plotting might still be halted if the simulation
//! detects a raycast hit with a collider.
uint32_t simulationMaxSteps;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PRIVATE MEMBER FUNCTIONS */ /* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void SetMesh(Handle<SHMesh> newMesh) noexcept; void SetMesh(Handle<SHMesh> newMesh) noexcept;
void SetPositions (std::vector<SHVec3> const& inPositions) noexcept;
void SetStartColor(SHVec3 startColor) noexcept; void SetStartColor(SHVec3 startColor) noexcept;
void SetEndColor (SHVec3 endColor) noexcept; void SetEndColor (SHVec3 endColor) noexcept;
void SetStartAlpha(float a) noexcept; void SetStartAlpha(float a) noexcept;
void SetEndAlpha (float a) noexcept; void SetEndAlpha (float a) noexcept;
void SetColorEvolveRate(float rate) noexcept; void SetColorEvolveRate(float rate) noexcept;
std::vector<SHVec3> GetPositions (void) const noexcept; Handle<SHMesh> GetMesh (void) const noexcept;
Handle<SHMesh> GetMesh (void) const noexcept; SHVec3 const& GetStartColor (void) const noexcept;
SHVec3 const& GetStartColor (void) const noexcept; SHVec3 const& GetEndColor (void) const noexcept;
SHVec3 const& GetEndColor (void) const noexcept; float GetStartAlpha (void) const noexcept;
float GetStartAlpha (void) const noexcept; float GetEndAlpha (void) const noexcept;
float GetEndAlpha (void) const noexcept; float GetColorEvolveRate (void) const noexcept;
float GetColorEvolveRate (void) const noexcept; EntityID GetEntityToSimulate (void) const noexcept;
SHVec3 GetSimulationForce (void) const noexcept;
uint32_t GetSimulationMaxSteps (void) const noexcept;
float GetSimulationTimestep (void) const noexcept;
void ResetSimulationInfo (void) noexcept;
void OnCreate(void) override final; void OnCreate(void) override final;
void OnDestroy(void) override final; void OnDestroy(void) override final;
void ClearPositions(void) noexcept; void SimulateTrajectory (EntityID eid, SHVec3 force, float timestep, uint32_t maxSteps) noexcept;
bool HasPositions(void) const noexcept;
RTTR_ENABLE() RTTR_ENABLE()

View File

@ -11,6 +11,8 @@
#include "Graphics/RenderGraph/SHSubpass.h" #include "Graphics/RenderGraph/SHSubpass.h"
#include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h" #include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h"
#include "Graphics/MiddleEnd/Interface/SHRenderer.h" #include "Graphics/MiddleEnd/Interface/SHRenderer.h"
#include "Physics/System/SHPhysicsSystem.h"
#include "ECS_Base/Managers/SHSystemManager.h"
namespace SHADE namespace SHADE
{ {
@ -74,83 +76,90 @@ namespace SHADE
void SHTrajectoryRenderingSubSystem::Run(uint32_t frameIndex) noexcept void SHTrajectoryRenderingSubSystem::Run(uint32_t frameIndex) noexcept
{ {
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
auto& comps = SHComponentManager::GetDense<SHTrajectoryRenderableComponent>(); auto& comps = SHComponentManager::GetDense<SHTrajectoryRenderableComponent>();
for (auto& comp : comps) for (auto& comp : comps)
{ {
//std::vector<SHVec3> test{}; if (EntityID entityToSimulate = comp.GetEntityToSimulate(); entityToSimulate != MAX_EID)
//test.resize(10);
//float x = 0.0f;
//for (auto& vec : test)
//{
// vec = SHVec3(x, 5.0f, 0.0f);
// x += 0.5f;
//}
//comp.SetPositions (test);
// If has positions, feed data to buffer.
if (comp.HasPositions())
{ {
auto meshHandle = comp.GetMesh(); std::vector<SHVec3> positions{};
std::vector<SHQuaternion> quats{};
// dont do anything if no mesh physicsSystem->SimulateBody
if (!meshHandle) (positions, quats,
continue; SHPhysicsSystem::SimulateBodyInfo
SHTransformComponent* transform = SHComponentManager::GetComponent_s<SHTransformComponent>(comp.GetEID());
if (transform)
{
// convenient variable
SHVec3 const& startColor = comp.GetStartColor();
SHVec3 const& endColor = comp.GetEndColor();
float colorEvolveRate = comp.GetColorEvolveRate();
// trs to be reused
SHMatrix trs = transform->GetTRS();
// starting color of trajectory
SHVec4 currentColor = comp.GetStartColor();
// Start from 0 and slowly evolve to 1
float lerpValue = 0.0f;
// Will be used for baseInstance later
uint32_t oldTransformDataSize = transformData.size();
auto const& positions = comp.GetPositions();
for (auto& pos : positions)
{ {
// modify position and reuse matrix .bodyEID = entityToSimulate,
trs.m[3][0] = pos.x; .force = comp.GetSimulationForce(),
trs.m[3][1] = pos.y; .continuousForce = false,
trs.m[3][2] = pos.z; .timeStep = comp.GetSimulationTimestep(),
.maxSteps = static_cast<int>(comp.GetSimulationMaxSteps()),
transformData.push_back(trs);
colorData.push_back(currentColor);
// evolve lerp value and clamp to 1
lerpValue = std::min (1.0f, lerpValue + colorEvolveRate);
// evolve color
currentColor = SHVec3::Lerp(startColor, endColor, lerpValue);
currentColor.w = SHMath::Lerp (comp.GetStartAlpha(), comp.GetEndAlpha(), lerpValue);
} }
);
// add draw data for this trajectory comp.ResetSimulationInfo();
drawData.push_back(vk::DrawIndexedIndirectCommand
// If has positions, feed data to buffer.
if (!positions.empty())
{
auto meshHandle = comp.GetMesh();
// dont do anything if no mesh
if (!meshHandle)
continue;
SHTransformComponent* transform = SHComponentManager::GetComponent_s<SHTransformComponent>(comp.GetEID());
if (transform)
{
// convenient variable
SHVec3 const& startColor = comp.GetStartColor();
SHVec3 const& endColor = comp.GetEndColor();
float colorEvolveRate = comp.GetColorEvolveRate();
// trs to be reused
SHMatrix trs = transform->GetTRS();
// starting color of trajectory
SHVec4 currentColor = comp.GetStartColor();
// Start from 0 and slowly evolve to 1
float lerpValue = 0.0f;
// Will be used for baseInstance later
uint32_t oldTransformDataSize = transformData.size();
for (auto& pos : positions)
{ {
.indexCount = meshHandle->IndexCount, // modify position and reuse matrix
.instanceCount = static_cast<uint32_t>(transformData.size()) - oldTransformDataSize, trs.m[3][0] = pos.x;
.firstIndex = meshHandle->FirstIndex, trs.m[3][1] = pos.y;
.vertexOffset = meshHandle->FirstVertex, trs.m[3][2] = pos.z;
.firstInstance = oldTransformDataSize
}); transformData.push_back(trs);
colorData.push_back(currentColor);
// evolve lerp value and clamp to 1
lerpValue = std::min(1.0f, lerpValue + colorEvolveRate);
// evolve color
currentColor = SHVec3::Lerp(startColor, endColor, lerpValue);
currentColor.w = SHMath::Lerp(comp.GetStartAlpha(), comp.GetEndAlpha(), lerpValue);
}
// add draw data for this trajectory
drawData.push_back(vk::DrawIndexedIndirectCommand
{
.indexCount = meshHandle->IndexCount,
.instanceCount = static_cast<uint32_t>(transformData.size()) - oldTransformDataSize,
.firstIndex = meshHandle->FirstIndex,
.vertexOffset = meshHandle->FirstVertex,
.firstInstance = oldTransformDataSize
});
}
} }
} }
// clear at the end of every frame since data is already in buffers
comp.ClearPositions();
} }
if (!transformData.empty()) if (!transformData.empty())

View File

@ -194,9 +194,9 @@ namespace SHADE
// In reality, the check for variable descriptor sets do not exists in spirv-reflect. Fortunately, when a shader // In reality, the check for variable descriptor sets do not exists in spirv-reflect. Fortunately, when a shader
// defines a boundless descriptor binding in the shader, the information reflected makes the array dimensions // defines a boundless descriptor binding in the shader, the information reflected makes the array dimensions
// contain a 1 element of value 1. Knowing that having an array [1] doesn't make sense, we can use this to // contain a 1 element of value 0. Knowing that having an array [1] doesn't make sense, we can use this to
// signify a variable sized binding. // signify a variable sized binding.
if (reflectedBinding->array.dims[0] == 1) if (reflectedBinding->array.dims_count == 1 && reflectedBinding->array.dims[0] == 0)
{ {
// variable binding has to be the last in the set // variable binding has to be the last in the set
if (i == set->binding_count - 1) if (i == set->binding_count - 1)

View File

@ -111,7 +111,6 @@ namespace SHADE
renderGraphStorage->graphResources->at(resourceName).Free(); renderGraphStorage->graphResources->at(resourceName).Free();
renderGraphStorage->graphResources->erase (resourceName); renderGraphStorage->graphResources->erase (resourceName);
resourceHdl.Free ();
/* /*
* IMPORTANT NOTES * IMPORTANT NOTES
* *
@ -134,8 +133,11 @@ namespace SHADE
// Get handle to node since it exists // Get handle to node since it exists
auto nodeHdl = nodes[nodeIndexing[nodeName]]; auto nodeHdl = nodes[nodeIndexing[nodeName]];
nodes.erase(nodes.begin() + nodeIndexing[nodeName]);
nodeHdl.Free(); nodeHdl.Free();
nodeIndexing.erase(nodeName);
ReindexNodes();
} }
} }

View File

@ -118,7 +118,7 @@ namespace SHADE
if (layouts.size() == descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE) + 1) if (layouts.size() == descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE) + 1)
{ {
Handle<SHVkDescriptorSetLayout> computeResourceLayout = {}; Handle<SHVkDescriptorSetLayout> computeResourceLayout = {};
computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)]; computeResourceLayout = layouts[descMappings.at(SHPredefinedDescriptorTypes::RENDER_GRAPH_NODE_COMPUTE_RESOURCE)];
// create compute resources // create compute resources
computeResource = graphStorage->resourceHub->Create<ComputeResource>(); computeResource = graphStorage->resourceHub->Create<ComputeResource>();

View File

@ -276,6 +276,7 @@ namespace SHADE
localInvInertia[i] = 1.0f / localInvInertia[i]; localInvInertia[i] = 1.0f / localInvInertia[i];
// Build raycast layer from colliders. If none exist....then this never stops simulating technically. // Build raycast layer from colliders. If none exist....then this never stops simulating technically.
// I'm too lazy to handle that case, so I'll just throw an error. // I'm too lazy to handle that case, so I'll just throw an error.
uint16_t raycastLayers = 0; uint16_t raycastLayers = 0;
@ -297,16 +298,17 @@ namespace SHADE
raycastInfo.continuous = false; raycastInfo.continuous = false;
raycastInfo.layers = raycastLayers; raycastInfo.layers = raycastLayers;
bool terminate = true; bool terminate = true;
int iterationCounter = simInfo.maxSteps;
do do
{ {
raycastInfo.distance = linearVelocity.Length(); raycastInfo.distance = linearVelocity.Length();
raycastInfo.ray.position = bodyPosition; raycastInfo.ray.position = bodyPosition;
raycastInfo.ray.direction = SHVec3::Normalise(linearVelocity); raycastInfo.ray.direction = SHVec3::Normalise(linearVelocity);
terminate = !Raycast(raycastInfo).empty(); terminate = !Raycast(raycastInfo).empty() || iterationCounter == 0;
if (terminate) if (terminate)
break; return;
// Compute world space data // Compute world space data
const SHMatrix R = SHMatrix::Rotate(bodyOrientation); const SHMatrix R = SHMatrix::Rotate(bodyOrientation);
@ -348,7 +350,7 @@ namespace SHADE
const SHQuaternion QV = SHQuaternion{ angularVelocity.x * simInfo.timeStep, angularVelocity.y * simInfo.timeStep, angularVelocity.z * simInfo.timeStep, 0.0f } * 0.5f; const SHQuaternion QV = SHQuaternion{ angularVelocity.x * simInfo.timeStep, angularVelocity.y * simInfo.timeStep, angularVelocity.z * simInfo.timeStep, 0.0f } * 0.5f;
bodyPosition += linearVelocity * simInfo.timeStep; bodyPosition += linearVelocity * simInfo.timeStep;
bodyOrientation += bodyOrientation * QV; bodyOrientation += bodyOrientation * QV * SHQuaternion::FromEuler(ANGULAR_LOCK);
bodyOrientation = SHQuaternion::Normalise(bodyOrientation); bodyOrientation = SHQuaternion::Normalise(bodyOrientation);
// Clear forces after the first frame // Clear forces after the first frame
@ -362,6 +364,8 @@ namespace SHADE
positions.emplace_back(bodyPosition); positions.emplace_back(bodyPosition);
--iterationCounter;
} while (true); } while (true);
} }

View File

@ -50,19 +50,39 @@ namespace SHADE
/** /**
* @brief * @brief
* Used to simulate the motion of a rigid body until it hits something. * Used to simulate the motion of a rigid body, ignoring collision detection and response.
* @param bodyEID
* The EntityID of the Rigid Body to simulate.
* @param force
* The force applied onto the Rigid Body.
* @param forceOffset
* The position to apply the force onto the body relative to it's local Center of Mass.
* @param torque
* The torque to apply onto the Rigid Body.
* @param continuousForce
* If the force should be applied every step throughout the simulation. Defaults to false. <br/>
* True : The force indicated is added to the body every step, therefore it has constant acceleration.
* False: The force is applied only in the first step, therefore it has constant speed.
* @param timeStep
* The timestep for each step of the simulation. Defaults to 0.016s (The default Fixed DT)
* @param maxSteps
* The number of steps to run the simulation for. Defaults to -1.
* < 0 : Runs until the object may hit something. Hit detection is done through raycasting.
* = 0 : Runs only the current step and checks if it may hit something.
* > 0 : Runs for the given number of steps or until it may hit something.
*/ */
struct SimulateBodyInfo struct SimulateBodyInfo
{ {
EntityID bodyEID = MAX_EID; EntityID bodyEID = MAX_EID;
SHVec3 force = SHVec3::Zero; SHVec3 force = SHVec3::Zero;
SHVec3 forceOffset = SHVec3::Zero; SHVec3 forceOffset = SHVec3::Zero;
SHVec3 torque = SHVec3::Zero; SHVec3 torque = SHVec3::Zero;
// Whether or not to clear the force after the first iteration // Whether or not to clear the force after the first iteration
bool continuousForce = false; bool continuousForce = false;
float timeStep = static_cast<float>(SHPhysicsConstants::DEFAULT_FIXED_DT); float timeStep = static_cast<float>(SHPhysicsConstants::DEFAULT_FIXED_DT);
int maxSteps = -1;
}; };

View File

@ -127,8 +127,8 @@ namespace SHADE
if (assetId.has_value()) if (assetId.has_value())
{ {
const auto ASSET_INFO = SHAssetManager::GetAsset(assetId.value()); const auto ASSET_INFO = SHAssetManager::GetAsset(assetId.value());
if (ASSET_INFO.has_value()) if (ASSET_INFO)
return ASSET_INFO.value().name; return ASSET_INFO->name;
} }
return {}; return {};
} }

View File

@ -21,6 +21,8 @@ of DigiPen Institute of Technology is prohibited.
#include "Assets/Asset Types/Models/SHModelAsset.h" #include "Assets/Asset Types/Models/SHModelAsset.h"
#include "Assets/Asset Types/SHTextureAsset.h" #include "Assets/Asset Types/SHTextureAsset.h"
#include "Assets/Asset Types/SHShaderAsset.h" #include "Assets/Asset Types/SHShaderAsset.h"
#include "Assets/Asset Types/SHAnimClipContainerAsset.h"
#include "Assets/Asset Types/SHAnimControllerAsset.h"
#include "Graphics/Shaders/SHVkShaderModule.h" #include "Graphics/Shaders/SHVkShaderModule.h"
#include "Graphics/MiddleEnd/Textures/SHTextureLibrary.h" #include "Graphics/MiddleEnd/Textures/SHTextureLibrary.h"
#include "Graphics/MiddleEnd/Interface/SHMeshLibrary.h" #include "Graphics/MiddleEnd/Interface/SHMeshLibrary.h"
@ -28,7 +30,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h"
#include "Assets/Asset Types/SHMaterialAsset.h" #include "Assets/Asset Types/SHMaterialAsset.h"
#include "Graphics/MiddleEnd/TextRendering/SHFont.h" #include "Graphics/MiddleEnd/TextRendering/SHFont.h"
#include "Animation/SHAnimationClip.h" #include "Animation/SHRawAnimation.h"
#include "Animation/SHRig.h" #include "Animation/SHRig.h"
namespace SHADE namespace SHADE
@ -38,6 +40,8 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
class SHMaterial; class SHMaterial;
struct SHRigNode; struct SHRigNode;
class SHAnimationClip;
class SHAnimationController;
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
@ -46,15 +50,17 @@ namespace SHADE
/// Template structs that maps a resource to their loaded asset representation type. /// Template structs that maps a resource to their loaded asset representation type.
/// </summary> /// </summary>
template<typename T = void> template<typename T = void>
struct SHResourceLoader { using AssetType = void; }; struct SHResourceLoader { using AssetType = void; };
template<> struct SHResourceLoader<SHMesh> { using AssetType = SHMeshAsset; }; template<> struct SHResourceLoader<SHMesh> { using AssetType = SHMeshAsset; };
template<> struct SHResourceLoader<SHTexture> { using AssetType = SHTextureAsset; }; template<> struct SHResourceLoader<SHTexture> { using AssetType = SHTextureAsset; };
template<> struct SHResourceLoader<SHVkShaderModule> { using AssetType = SHShaderAsset; }; template<> struct SHResourceLoader<SHVkShaderModule> { using AssetType = SHShaderAsset; };
template<> struct SHResourceLoader<SHMaterialSpec> { using AssetType = SHMaterialAsset; }; template<> struct SHResourceLoader<SHMaterialSpec> { using AssetType = SHMaterialAsset; };
template<> struct SHResourceLoader<SHMaterial> { using AssetType = SHMaterialSpec; }; template<> struct SHResourceLoader<SHMaterial> { using AssetType = SHMaterialSpec; };
template<> struct SHResourceLoader<SHFont> { using AssetType = SHFontAsset; }; template<> struct SHResourceLoader<SHFont> { using AssetType = SHFontAsset; };
template<> struct SHResourceLoader<SHAnimationClip> { using AssetType = SHModelAsset; }; template<> struct SHResourceLoader<SHRawAnimation> { using AssetType = SHModelAsset; };
template<> struct SHResourceLoader<SHRig> { using AssetType = SHModelAsset; }; template<> struct SHResourceLoader<SHRig> { using AssetType = SHModelAsset; };
template<> struct SHResourceLoader<SHAnimationClip> { using AssetType = SHAnimClipAsset; };
template<> struct SHResourceLoader<SHAnimationController> { using AssetType = SHAnimControllerAsset; };
/// <summary> /// <summary>
/// Static class responsible for loading and caching runtime resources from their /// Static class responsible for loading and caching runtime resources from their

View File

@ -25,6 +25,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Devices/SHVkLogicalDevice.h" #include "Graphics/Devices/SHVkLogicalDevice.h"
#include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h"
#include "Serialization/SHYAMLConverters.h" #include "Serialization/SHYAMLConverters.h"
#include "Animation/SHAnimationClip.h"
namespace SHADE namespace SHADE
{ {
@ -35,14 +36,16 @@ namespace SHADE
Handle<ResourceType> SHResourceManager::LoadOrGet(AssetID assetId) Handle<ResourceType> SHResourceManager::LoadOrGet(AssetID assetId)
{ {
// Check if it is an unsupported type // Check if it is an unsupported type
if (!std::is_same_v<ResourceType, SHMesh> && if (!std::is_same_v<ResourceType, SHMesh> &&
!std::is_same_v<ResourceType, SHTexture> && !std::is_same_v<ResourceType, SHTexture> &&
!std::is_same_v<ResourceType, SHVkShaderModule> && !std::is_same_v<ResourceType, SHVkShaderModule> &&
!std::is_same_v<ResourceType, SHMaterialSpec> && !std::is_same_v<ResourceType, SHMaterialSpec> &&
!std::is_same_v<ResourceType, SHFont> && !std::is_same_v<ResourceType, SHFont> &&
!std::is_same_v<ResourceType, SHMaterial> && !std::is_same_v<ResourceType, SHMaterial> &&
!std::is_same_v<ResourceType, SHAnimationClip> && !std::is_same_v<ResourceType, SHRawAnimation> &&
!std::is_same_v<ResourceType, SHRig> !std::is_same_v<ResourceType, SHRig> &&
!std::is_same_v<ResourceType, SHAnimationClip> &&
!std::is_same_v<ResourceType, SHAnimationController>
) )
{ {
static_assert(true, "Unsupported Resource Type specified for SHResourceManager."); static_assert(true, "Unsupported Resource Type specified for SHResourceManager.");
@ -159,8 +162,8 @@ namespace SHADE
if (assetId.has_value()) if (assetId.has_value())
{ {
const auto ASSET_INFO = SHAssetManager::GetAsset(assetId.value()); const auto ASSET_INFO = SHAssetManager::GetAsset(assetId.value());
if (ASSET_INFO.has_value()) if (ASSET_INFO)
return ASSET_INFO.value().name; return ASSET_INFO->name;
} }
return {}; return {};
} }
@ -355,10 +358,30 @@ namespace SHADE
loadedAssetData.emplace_back(assetId); loadedAssetData.emplace_back(assetId);
return resourceHub.Create<ResourceType>(assetData.rig, rigNodeStore); return resourceHub.Create<ResourceType>(assetData.rig, rigNodeStore);
} }
else if constexpr (std::is_same_v<ResourceType, SHRawAnimation>)
{
loadedAssetData.emplace_back(assetId);
if (assetData.anims.empty())
return {};
return resourceHub.Create<ResourceType>(*assetData.anims[0]);
}
else if constexpr (std::is_same_v<ResourceType, SHAnimationClip>) else if constexpr (std::is_same_v<ResourceType, SHAnimationClip>)
{ {
loadedAssetData.emplace_back(assetId); loadedAssetData.emplace_back(assetId);
return resourceHub.Create<ResourceType>(*assetData.anims[0]); return resourceHub.Create<ResourceType>
(
LoadOrGet<SHRawAnimation>(assetData.animRawDataAssetId),
assetData.firstIndex,
assetData.lastIndex
);
}
else if constexpr (std::is_same_v<ResourceType, SHAnimationController>)
{
loadedAssetData.emplace_back(assetId);
return resourceHub.Create<ResourceType>
(
// TODO
);
} }
} }
} }

View File

@ -44,6 +44,21 @@ namespace SHADE
return SHResourceManager::LoadOrGet<SHFont>(assetId); return SHResourceManager::LoadOrGet<SHFont>(assetId);
} }
Handle<SHAnimationClip> SHResourceManagerInterface::LoadOrGetAnimationClip(AssetID assetId)
{
return SHResourceManager::LoadOrGet<SHAnimationClip>(assetId);
}
Handle<SHAnimationController> SHResourceManagerInterface::LoadOrGetAnimationController(AssetID assetId)
{
return SHResourceManager::LoadOrGet<SHAnimationController>(assetId);
}
Handle<SHRig> SHResourceManagerInterface::LoadOrGetRig(AssetID assetId)
{
return SHResourceManager::LoadOrGet<SHRig>(assetId);
}
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Query Functions */ /* Query Functions */
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/

View File

@ -29,6 +29,9 @@ namespace SHADE
struct SHMaterialSpec; struct SHMaterialSpec;
class SHMaterial; class SHMaterial;
class SHFont; class SHFont;
class SHAnimationClip;
class SHRig;
class SHAnimationController;
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* Type Definitions */ /* Type Definitions */
@ -80,6 +83,24 @@ namespace SHADE
/// <param name="assetId">Asset ID of the resource to load.</param> /// <param name="assetId">Asset ID of the resource to load.</param>
/// <returns>Handle to the resource to retrieve.</returns> /// <returns>Handle to the resource to retrieve.</returns>
static Handle<SHFont> LoadOrGetFont(AssetID assetId); static Handle<SHFont> LoadOrGetFont(AssetID assetId);
/// <summary>
/// Wrapper for SHResourceManager::LoadOrGet<SHAnimationClip>().
/// </summary>
/// <param name="assetId">Asset ID of the resource to load.</param>
/// <returns>Handle to the resource to retrieve.</returns>
static Handle<SHAnimationClip> LoadOrGetAnimationClip(AssetID assetId);
/// <summary>
/// Wrapper for SHResourceManager::LoadOrGet<SHAnimationController>().
/// </summary>
/// <param name="assetId">Asset ID of the resource to load.</param>
/// <returns>Handle to the resource to retrieve.</returns>
static Handle<SHAnimationController> LoadOrGetAnimationController(AssetID assetId);
/// <summary>
/// Wrapper for SHResourceManager::LoadOrGet<SHRig>().
/// </summary>
/// <param name="assetId">Asset ID of the resource to load.</param>
/// <returns>Handle to the resource to retrieve.</returns>
static Handle<SHRig> LoadOrGetRig(AssetID assetId);
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Query Functions */ /* Query Functions */

View File

@ -115,7 +115,7 @@ namespace SHADE
#else #else
static constexpr int EXCESS_CHARS_COUNT = 2; static constexpr int EXCESS_CHARS_COUNT = 2;
const auto RESULT = SHExecUtilties::ExecBlockingPowerShellCommand(L"./vswhere -version \"[15.0,19.0]\" -requires Microsoft.NetCore.Component.DevelopmentTools -find Common7\\\\IDE\\\\devenv.exe | Select-Object -first 1", true, true); const auto RESULT = SHExecUtilties::ExecBlockingPowerShellCommand(L"./vswhere -version \"[15.0,21.0]\" -requires Microsoft.NetCore.Component.DevelopmentTools -find Common7\\\\IDE\\\\devenv.exe | Select-Object -last 1", true, true);
if (RESULT.StdOutput.size() < EXCESS_CHARS_COUNT) if (RESULT.StdOutput.size() < EXCESS_CHARS_COUNT)
{ {
SHLOG_ERROR("[SHVSUtilities] Unable to get path to Visual Studio installation. SHVSUtilities will not work."); SHLOG_ERROR("[SHVSUtilities] Unable to get path to Visual Studio installation. SHVSUtilities will not work.");

View File

@ -428,13 +428,13 @@ namespace YAML
struct convert<SHAnimatorComponent> struct convert<SHAnimatorComponent>
{ {
static constexpr std::string_view RIG_YAML_TAG = "Rig"; static constexpr std::string_view RIG_YAML_TAG = "Rig";
static constexpr std::string_view CLIP_YAML_TAG = "Clip"; static constexpr std::string_view AC_YAML_TAG = "AnimationController";
static YAML::Node encode(SHAnimatorComponent const& rhs) static YAML::Node encode(SHAnimatorComponent const& rhs)
{ {
YAML::Node node; YAML::Node node;
node[RIG_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHRig>(rhs.GetRig()).value_or(0); node[RIG_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHRig>(rhs.GetRig()).value_or(0);
node[CLIP_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHAnimationClip>(rhs.GetCurrentClip()).value_or(0); node[AC_YAML_TAG.data()] = SHResourceManager::GetAssetID<SHAnimationController>(rhs.GetAnimationController()).value_or(0);
return node; return node;
} }
static bool decode(YAML::Node const& node, SHAnimatorComponent& rhs) static bool decode(YAML::Node const& node, SHAnimatorComponent& rhs)
@ -443,9 +443,9 @@ namespace YAML
{ {
rhs.SetRig(SHResourceManager::LoadOrGet<SHRig>(node[RIG_YAML_TAG.data()].as<AssetID>())); rhs.SetRig(SHResourceManager::LoadOrGet<SHRig>(node[RIG_YAML_TAG.data()].as<AssetID>()));
} }
if (node[CLIP_YAML_TAG.data()].IsDefined()) if (node[AC_YAML_TAG.data()].IsDefined())
{ {
rhs.SetClip(SHResourceManager::LoadOrGet<SHAnimationClip>(node[CLIP_YAML_TAG.data()].as<AssetID>())); rhs.SetAnimationController(SHResourceManager::LoadOrGet<SHAnimationController>(node[AC_YAML_TAG.data()].as<AssetID>()));
} }
return true; return true;
} }

View File

@ -0,0 +1,70 @@
/************************************************************************************//*!
\file AnimationClipAsset.cxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 8, 2023
\brief Contains the implementation of the functions of the managed
AnimationClip class.
Note: This file is written in C++17/CLI.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
// Precompiled Headers
#include "SHpch.h"
// Primary Header
#include "AnimationClipAsset.hxx"
// External Dependencies
#include "Resource/SHResourceManagerInterface.h"
// Project Headers
#include "Utility/Convert.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Properties */
/*---------------------------------------------------------------------------------*/
Handle<SHAnimationClip> AnimationClipAsset::NativeObject::get()
try
{
return SHResourceManagerInterface::LoadOrGetAnimationClip(asset.NativeAssetID);
}
catch (const BadHandleCastException&)
{
return Handle<SHAnimationClip>();
}
AssetID AnimationClipAsset::NativeAssetID::get()
{
return asset.NativeAssetID;
}
/*---------------------------------------------------------------------------------*/
/* Constructors/Destructor */
/*---------------------------------------------------------------------------------*/
AnimationClipAsset::AnimationClipAsset(AssetID AnimationClipId)
: asset{ AnimationClipId }
{}
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
AnimationClipAsset::operator bool(AnimationClipAsset asset)
{
return asset.asset;
}
/*---------------------------------------------------------------------------------*/
/* Conversion Operators */
/*---------------------------------------------------------------------------------*/
AnimationClipAsset::operator Asset(AnimationClipAsset nativeAsset)
{
return nativeAsset.asset;
}
AnimationClipAsset::operator AnimationClipAsset(Asset asset)
{
return AnimationClipAsset(asset.NativeAssetID);
}
}

View File

@ -0,0 +1,91 @@
/************************************************************************************//*!
\file AnimationClipAsset.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 8, 2023
\brief Contains the definition of the managed AnimationClipAsset class.
Note: This file is written in C++17/CLI.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
// External Dependencies
#include "Resource/SHHandle.h"
#include "Animation/SHAnimationClip.h"
// Project Includes
#include "NativeAsset.hxx"
#include "Engine/GenericHandle.hxx"
namespace SHADE
{
/// <summary>
/// Managed counterpart of the native Animation Clip object that specifies a range of
/// animation frames that can be specified to an Animator component to play an
/// animation.
/// </summary>
public value struct AnimationClipAsset
{
public:
/*-----------------------------------------------------------------------------*/
/* Operator Overloads */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Implicit conversion operator to enable checking if a AnimationClip is valid.
/// </summary>
/// <param name="gameObj">Asset to check.</param>
/// <returns>True if the Asset is valid.</returns>
static operator bool(AnimationClipAsset asset);
internal:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Copy of the Handle to the native object.
/// </summary>
property Handle<SHAnimationClip> NativeObject
{
Handle<SHAnimationClip> get();
}
/// <summary>
/// The raw asset ID of the asset.
/// </summary>
property AssetID NativeAssetID
{
AssetID get();
}
/*-----------------------------------------------------------------------------*/
/* Constructors/Destructor */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructor for the AnimationClip.
/// </summary>
/// <param name="AnimationClipId">AssetID to the AnimationClip asset.</param>
AnimationClipAsset(AssetID AnimationClipId);
/*-----------------------------------------------------------------------------*/
/* Conversion Operators */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Conversion operator to enable casting from a AnimationClip to an Asset.
/// </summary>
/// <param name="vec">Vector3 to convert from.</param>
static explicit operator Asset(AnimationClipAsset nativeAsset);
/// <summary>
/// Conversion operator to enable casting from a Asset to a AnimationClip.
/// </summary>
/// <param name="asset"></param>
static explicit operator AnimationClipAsset(Asset asset);
protected:
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
Asset asset;
};
}

View File

@ -0,0 +1,70 @@
/************************************************************************************//*!
\file AnimationController.cxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 8, 2023
\brief Contains the implementation of the functions of the managed
AnimationController class.
Note: This file is written in C++17/CLI.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
// Precompiled Headers
#include "SHpch.h"
// Primary Header
#include "AnimationControllerAsset.hxx"
// External Dependencies
#include "Resource/SHResourceManagerInterface.h"
// Project Headers
#include "Utility/Convert.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Properties */
/*---------------------------------------------------------------------------------*/
Handle<SHAnimationController> AnimationControllerAsset::NativeObject::get()
try
{
return SHResourceManagerInterface::LoadOrGetAnimationController(asset.NativeAssetID);
}
catch (const BadHandleCastException&)
{
return Handle<SHAnimationController>();
}
AssetID AnimationControllerAsset::NativeAssetID::get()
{
return asset.NativeAssetID;
}
/*---------------------------------------------------------------------------------*/
/* Constructors/Destructor */
/*---------------------------------------------------------------------------------*/
AnimationControllerAsset::AnimationControllerAsset(AssetID AnimationControllerId)
: asset{ AnimationControllerId }
{}
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
AnimationControllerAsset::operator bool(AnimationControllerAsset asset)
{
return asset.asset;
}
/*---------------------------------------------------------------------------------*/
/* Conversion Operators */
/*---------------------------------------------------------------------------------*/
AnimationControllerAsset::operator Asset(AnimationControllerAsset nativeAsset)
{
return nativeAsset.asset;
}
AnimationControllerAsset::operator AnimationControllerAsset(Asset asset)
{
return AnimationControllerAsset(asset.NativeAssetID);
}
}

View File

@ -0,0 +1,90 @@
/************************************************************************************//*!
\file AnimationControllerAsset.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 8, 2023
\brief Contains the definition of the managed AnimationController class.
Note: This file is written in C++17/CLI.
Copyright (C) 2022 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
// External Dependencies
#include "Resource/SHHandle.h"
#include "Animation/SHAnimationController.h"
// Project Includes
#include "NativeAsset.hxx"
#include "Engine/GenericHandle.hxx"
namespace SHADE
{
/// <summary>
/// Managed counterpart of the native AnimationController object containing the
/// state machine for controlling what AnimationClips that an Animator should play.
/// </summary>
public value struct AnimationControllerAsset
{
public:
/*-----------------------------------------------------------------------------*/
/* Operator Overloads */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Implicit conversion operator to enable checking if a AnimationController is valid.
/// </summary>
/// <param name="gameObj">Asset to check.</param>
/// <returns>True if the Asset is valid.</returns>
static operator bool(AnimationControllerAsset asset);
internal:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Copy of the Handle to the native object.
/// </summary>
property Handle<SHAnimationController> NativeObject
{
Handle<SHAnimationController> get();
}
/// <summary>
/// The raw asset ID of the asset.
/// </summary>
property AssetID NativeAssetID
{
AssetID get();
}
/*-----------------------------------------------------------------------------*/
/* Constructors/Destructor */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructor for the AnimationController.
/// </summary>
/// <param name="AnimationControllerId">AssetID to the AnimationController asset.</param>
AnimationControllerAsset(AssetID AnimationControllerId);
/*-----------------------------------------------------------------------------*/
/* Conversion Operators */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Conversion operator to enable casting from a AnimationController to an Asset.
/// </summary>
/// <param name="vec">Vector3 to convert from.</param>
static explicit operator Asset(AnimationControllerAsset nativeAsset);
/// <summary>
/// Conversion operator to enable casting from a Asset to a AnimationController.
/// </summary>
/// <param name="asset"></param>
static explicit operator AnimationControllerAsset(Asset asset);
protected:
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
Asset asset;
};
}

View File

@ -0,0 +1,70 @@
/************************************************************************************//*!
\file AnimationRigAsset.cxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 8, 2023
\brief Contains the implementation of the functions of the managed
AnimationRig class.
Note: This file is written in C++17/CLI.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
// Precompiled Headers
#include "SHpch.h"
// Primary Header
#include "AnimationRigAsset.hxx"
// External Dependencies
#include "Resource/SHResourceManagerInterface.h"
// Project Headers
#include "Utility/Convert.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Properties */
/*---------------------------------------------------------------------------------*/
Handle<SHRig> AnimationRigAsset::NativeObject::get()
try
{
return SHResourceManagerInterface::LoadOrGetRig(asset.NativeAssetID);
}
catch (const BadHandleCastException&)
{
return Handle<SHRig>();
}
AssetID AnimationRigAsset::NativeAssetID::get()
{
return asset.NativeAssetID;
}
/*---------------------------------------------------------------------------------*/
/* Constructors/Destructor */
/*---------------------------------------------------------------------------------*/
AnimationRigAsset::AnimationRigAsset(AssetID AnimationRigId)
: asset{ AnimationRigId }
{}
/*---------------------------------------------------------------------------------*/
/* Operator Overloads */
/*---------------------------------------------------------------------------------*/
AnimationRigAsset::operator bool(AnimationRigAsset asset)
{
return asset.asset;
}
/*---------------------------------------------------------------------------------*/
/* Conversion Operators */
/*---------------------------------------------------------------------------------*/
AnimationRigAsset::operator Asset(AnimationRigAsset nativeAsset)
{
return nativeAsset.asset;
}
AnimationRigAsset::operator AnimationRigAsset(Asset asset)
{
return AnimationRigAsset(asset.NativeAssetID);
}
}

View File

@ -0,0 +1,90 @@
/************************************************************************************//*!
\file AnimationRigAsset.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 8, 2023
\brief Contains the definition of the managed AnimationRigAsset class.
Note: This file is written in C++17/CLI.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
// External Dependencies
#include "Resource/SHHandle.h"
#include "Animation/SHRig.h"
// Project Includes
#include "NativeAsset.hxx"
#include "Engine/GenericHandle.hxx"
namespace SHADE
{
/// <summary>
/// Managed counterpart of the native Animation Rig object that specifies how an
/// Animation Clip affects the model that this Rig is attached to.
/// </summary>
public value struct AnimationRigAsset
{
public:
/*-----------------------------------------------------------------------------*/
/* Operator Overloads */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Implicit conversion operator to enable checking if a AnimationRig is valid.
/// </summary>
/// <param name="gameObj">Asset to check.</param>
/// <returns>True if the Asset is valid.</returns>
static operator bool(AnimationRigAsset asset);
internal:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Copy of the Handle to the native object.
/// </summary>
property Handle<SHRig> NativeObject
{
Handle<SHRig> get();
}
/// <summary>
/// The raw asset ID of the asset.
/// </summary>
property AssetID NativeAssetID
{
AssetID get();
}
/*-----------------------------------------------------------------------------*/
/* Constructors/Destructor */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructor for the AnimationRig.
/// </summary>
/// <param name="AnimationRigId">AssetID to the AnimationRig asset.</param>
AnimationRigAsset(AssetID AnimationRigId);
/*-----------------------------------------------------------------------------*/
/* Conversion Operators */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Conversion operator to enable casting from a AnimationRig to an Asset.
/// </summary>
/// <param name="vec">Vector3 to convert from.</param>
static explicit operator Asset(AnimationRigAsset nativeAsset);
/// <summary>
/// Conversion operator to enable casting from a Asset to a AnimationRig.
/// </summary>
/// <param name="asset"></param>
static explicit operator AnimationRigAsset(Asset asset);
protected:
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
Asset asset;
};
}

View File

@ -28,6 +28,17 @@ namespace SHADE
/// </summary> /// </summary>
public value struct FontAsset public value struct FontAsset
{ {
public:
/*-----------------------------------------------------------------------------*/
/* Operator Overloads */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Implicit conversion operator to enable checking if a Font is valid.
/// </summary>
/// <param name="gameObj">Asset to check.</param>
/// <returns>True if the Asset is valid.</returns>
static operator bool(FontAsset asset);
internal: internal:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Properties */ /* Properties */
@ -56,16 +67,6 @@ namespace SHADE
/// <param name="fontId">AssetID to the font asset.</param> /// <param name="fontId">AssetID to the font asset.</param>
FontAsset(AssetID fontId); FontAsset(AssetID fontId);
/*-----------------------------------------------------------------------------*/
/* Operator Overloads */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Implicit conversion operator to enable checking if a Font is valid.
/// </summary>
/// <param name="gameObj">Asset to check.</param>
/// <returns>True if the Asset is valid.</returns>
static operator bool(FontAsset asset);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Conversion Operators */ /* Conversion Operators */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -28,6 +28,17 @@ namespace SHADE
/// </summary> /// </summary>
public value struct MaterialAsset public value struct MaterialAsset
{ {
public:
/*-----------------------------------------------------------------------------*/
/* Operator Overloads */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Implicit conversion operator to enable checking if a Material is valid.
/// </summary>
/// <param name="gameObj">Asset to check.</param>
/// <returns>True if the Asset is valid.</returns>
static operator bool(MaterialAsset asset);
internal: internal:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Properties */ /* Properties */
@ -56,16 +67,6 @@ namespace SHADE
/// <param name="MaterialId">AssetID to the Material asset.</param> /// <param name="MaterialId">AssetID to the Material asset.</param>
MaterialAsset(AssetID MaterialId); MaterialAsset(AssetID MaterialId);
/*-----------------------------------------------------------------------------*/
/* Operator Overloads */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Implicit conversion operator to enable checking if a Material is valid.
/// </summary>
/// <param name="gameObj">Asset to check.</param>
/// <returns>True if the Asset is valid.</returns>
static operator bool(MaterialAsset asset);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Conversion Operators */ /* Conversion Operators */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -28,7 +28,18 @@ namespace SHADE
/// </summary> /// </summary>
public value struct MeshAsset public value struct MeshAsset
{ {
internal: public:
/*-----------------------------------------------------------------------------*/
/* Operator Overloads */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Implicit conversion operator to enable checking if a Mesh is valid.
/// </summary>
/// <param name="gameObj">Asset to check.</param>
/// <returns>True if the Asset is valid.</returns>
static operator bool(MeshAsset asset);
internal:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Properties */ /* Properties */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
@ -56,16 +67,6 @@ namespace SHADE
/// <param name="meshId">AssetID to the Mesh asset.</param> /// <param name="meshId">AssetID to the Mesh asset.</param>
MeshAsset(AssetID meshId); MeshAsset(AssetID meshId);
/*-----------------------------------------------------------------------------*/
/* Operator Overloads */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Implicit conversion operator to enable checking if a Mesh is valid.
/// </summary>
/// <param name="gameObj">Asset to check.</param>
/// <returns>True if the Asset is valid.</returns>
static operator bool(MeshAsset asset);
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Conversion Operators */ /* Conversion Operators */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/

View File

@ -0,0 +1,159 @@
/************************************************************************************//*!
\file Animator.cxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 8, 2023
\brief Contains the definition of the functions of the managed Animator class.
Note: This file is written in C++17/CLI.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
// Precompiled Headers
#include "SHpch.h"
// Primary Header
#include "Animator.hxx"
#include "Assets/NativeAsset.hxx"
#include "Utility/Convert.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
Animator::Animator(Entity entity)
: Component(entity)
{}
/*---------------------------------------------------------------------------------*/
/* Properties */
/*---------------------------------------------------------------------------------*/
AnimationControllerAsset Animator::AnimationController::get()
{
auto controller = GetNativeComponent()->GetAnimationController();
return controller ? AnimationControllerAsset(controller) : AnimationControllerAsset();
}
void Animator::AnimationController::set(AnimationControllerAsset value)
{
if (value)
{
GetNativeComponent()->SetAnimationController(Handle<SHAnimationController>());
}
else
{
GetNativeComponent()->SetAnimationController(value.NativeObject);
}
}
AnimationRigAsset Animator::Rig::get()
{
auto rig = GetNativeComponent()->GetRig();
return rig ? AnimationRigAsset(rig) : AnimationRigAsset();
}
void Animator::Rig::set(AnimationRigAsset value)
{
if (value)
{
GetNativeComponent()->SetRig(Handle<SHRig>());
}
else
{
GetNativeComponent()->SetRig(Handle<SHRig>(value.NativeObject));
}
}
System::String^ Animator::CurrentNodeName::get()
{
const auto CURR_NODE = GetNativeComponent()->GetCurrentNode();
if (CURR_NODE)
return Convert::ToCLI(CURR_NODE->Name);
return nullptr;
}
/*---------------------------------------------------------------------------------*/
/* Usage Functions */
/*---------------------------------------------------------------------------------*/
void Animator::Play()
{
GetNativeComponent()->Play();
}
void Animator::Play(AnimationClipAsset clip)
{
GetNativeComponent()->Play(clip.NativeObject);
}
void Animator::PlayOneShot(AnimationClipAsset clip)
{
GetNativeComponent()->PlayOneShot(clip.NativeObject);
}
void Animator::PlayFromStart()
{
GetNativeComponent()->Play();
}
void Animator::Pause()
{
GetNativeComponent()->Pause();
}
void Animator::Stop()
{
GetNativeComponent()->Stop();
}
/*---------------------------------------------------------------------------------*/
/* Parameter Functions */
/*---------------------------------------------------------------------------------*/
generic<typename T>
void Animator::SetParameter(System::String^ paramName, T value)
{
if (T::typeid == int::typeid)
{
GetNativeComponent()->SetParameter<int>(Convert::ToNative(paramName), static_cast<int>(value));
}
else if (T::typeid == float::typeid)
{
GetNativeComponent()->SetParameter<float>(Convert::ToNative(paramName), static_cast<float>(value));
}
else if (T::typeid == bool::typeid)
{
GetNativeComponent()->SetParameter<bool>(Convert::ToNative(paramName), static_cast<bool>(value));
}
}
void Animator::SetTrigger(System::String^ paramName)
{
GetNativeComponent()->SetTrigger(Convert::ToNative(paramName));
}
System::Nullable<int> Animator::GetIntParameter(System::String^ paramName)
{
auto val = GetNativeComponent()->GetParameter<int>(Convert::ToNative(paramName));
if (val.has_value())
return System::Nullable<int>(val.value());
return {};
}
System::Nullable<float> Animator::GetFloatParameter(System::String^ paramName)
{
auto val = GetNativeComponent()->GetParameter<float>(Convert::ToNative(paramName));
if (val.has_value())
return System::Nullable<float>(val.value());
return {};
}
System::Nullable<bool> Animator::GetBoolParameter(System::String^ paramName)
{
auto val = GetNativeComponent()->GetParameter<bool>(Convert::ToNative(paramName));
if (val.has_value())
return System::Nullable<bool>(val.value());
return {};
}
System::Nullable<bool> Animator::GetTriggerState(System::String^ paramName)
{
return GetBoolParameter(paramName);
}
}

View File

@ -0,0 +1,164 @@
/************************************************************************************//*!
\file Animator.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Mar 8, 2023
\brief Contains the definition of the managed Animator class with the
declaration of functions for working with it.
Note: This file is written in C++17/CLI.
Copyright (C) 2023 DigiPen Institute of Technology.
Reproduction or disclosure of this file or its contents without the prior written consent
of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
// Project Includes
#include "Components/Component.hxx"
// External Dependencies
#include "Animation/SHAnimatorComponent.h"
// Project Includes
#include "Assets/AnimationClipAsset.hxx"
#include "Assets/AnimationControllerAsset.hxx"
#include "Assets/AnimationRigAsset.hxx"
namespace SHADE
{
/// <summary>
/// CLR version of the SHADE Engine's SHAnimatorComponent.
/// </summary>
public ref class Animator : public Component<SHAnimatorComponent>
{
internal:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructs a Animator Component that represents a native Animator
/// component tied to the specified Entity.
/// </summary>
/// <param name="entity">Entity that this Component will be tied to.</param>
Animator(Entity entity);
public:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Animation Controller used to controller the animation of this Animator.
/// </summary>
property AnimationControllerAsset AnimationController
{
AnimationControllerAsset get();
void set(AnimationControllerAsset value);
}
/// <summary>
/// The shared Material used to render this Animator and other Animators
/// using the same base Material.
/// </summary>
property AnimationRigAsset Rig
{
AnimationRigAsset get();
void set(AnimationRigAsset value);
}
/// <summary>
/// Name of the current node if there is an animation controller attached. If
/// there is none, null is returned.
/// </summary>
property System::String^ CurrentNodeName
{
System::String^ get();
}
/*-----------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Plays the currently loaded animation from the last time.
/// </summary>
void Play();
/// <summary>
/// Plays the specified animation clip from the start. This will unset any
/// SHAnimationControllers that have been set.
/// </summary>
/// <param name="clip">Animation clip to play.</param>
void Play(AnimationClipAsset clip);
/// <summary>
/// Plays the specified animation clip from the start one time only. This will unset
/// any SHAnimationControllers that have been set.
/// </summary>
/// <param name="clip">Animation clip to play.</param>
void PlayOneShot(AnimationClipAsset clip);
/// <summary>
/// Plays the currently loaded animation clip from the start. Note that this only
/// works when using manual playback mode.
/// </summary>
void PlayFromStart();
/// <summary>
/// Pauses the animation at the current time.
/// </summary>
void Pause();
/// <summary>
/// Stops the animation and resets the play time back to 0. Note that this only
/// works when using manual playback mode. This is not supported when using an
/// Animation Controller.
/// </summary>
void Stop();
/*-----------------------------------------------------------------------------*/
/* Parameter Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Sets the parameter of the for the string. Does nothing if an invalid param name
/// is provided. Type of the parameter is not checked. Also does nothing if no
/// animation controller is specified.
/// </summary>
/// <typeparam name="T">
/// Type of parameter. Only bool, int, floats are supported.
/// </typeparam>
/// <param name="paramName">Name of the parameter.</param>
/// <param name="value">Value to set the parameter to.</param>
generic<typename T>
void SetParameter(System::String^ paramName, T value);
/// <summary>
/// Sets the flag for a trigger parameter. Does nothing if an invalid param name is
/// provided or if the param name refers to a parameter that is not a trigger.
/// </summary>
/// <param name="paramName">Name of the parameter.</param>
void SetTrigger(System::String^ paramName);
/// <summary>
/// Gets the parameter of the for the named parameter of type int. Types are
/// checked and will not return a value if there is nothing. Returns nothing if
/// there is no animation controller specified either.
/// </summary>
/// <param name="paramName">Name of the parameter.</param>
/// <returns>The value of the parameter or nothing if invalid.</returns>
System::Nullable<int> GetIntParameter(System::String^ paramName);
/// <summary>
/// Gets the parameter of the for the named parameter of type float. Types are
/// checked and will not return a value if there is nothing. Returns nothing if
/// there is no animation controller specified either.
/// </summary>
/// <param name="paramName">Name of the parameter.</param>
/// <returns>The value of the parameter or nothing if invalid.</returns>
System::Nullable<float> GetFloatParameter(System::String^ paramName);
/// <summary>
/// Gets the parameter of the for the named parameter of type bool. Types are
/// checked and will not return a value if there is nothing. Returns nothing if
/// there is no animation controller specified either.
/// </summary>
/// <param name="paramName">Name of the parameter.</param>
/// <returns>The value of the parameter or nothing if invalid.</returns>
System::Nullable<bool> GetBoolParameter(System::String^ paramName);
/// <summary>
/// Checks if the trigger flag for the named trigger parameter is set. Types are
/// checked and will not return a value if there is nothing. Returns nothing if
/// there is no animation controller specified either.
/// </summary>
/// <param name="paramName">Name of the parameter.</param>
/// <returns>True if the trigger is set.</returns>
System::Nullable<bool> GetTriggerState(System::String^ paramName);
};
}

View File

@ -16,6 +16,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Collider.hxx" #include "Collider.hxx"
#include "Physics/Collision/Shapes/SHBox.h" #include "Physics/Collision/Shapes/SHBox.h"
#include "Physics/Collision/Shapes/SHCapsule.h"
#include "Physics/Collision/Shapes/SHSphere.h" #include "Physics/Collision/Shapes/SHSphere.h"
#include "Utility/Debug.hxx" #include "Utility/Debug.hxx"
@ -118,6 +119,29 @@ namespace SHADE
} }
} }
/*---------------------------------------------------------------------------------*/
/* SphereCollider - Properties */
/*---------------------------------------------------------------------------------*/
Vector3 SphereCollider::Center::get()
{
return Convert::ToCLI(getNativeCollisionShape<SHSphere>().GetWorldCentroid());
}
float SphereCollider::Radius::get()
{
return getNativeCollisionShape<SHSphere>().GetWorldRadius();
}
void SphereCollider::Radius::set(float value)
{
getNativeCollisionShape<SHSphere>().SetWorldRadius(value);
}
/*---------------------------------------------------------------------------------*/
/* SphereCollider - Constructors */
/*---------------------------------------------------------------------------------*/
SphereCollider::SphereCollider(int arrayIndex, Entity attachedEntity)
: CollisionShape{ arrayIndex, attachedEntity }
{}
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* BoxCollider - Constructors */ /* BoxCollider - Constructors */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -147,53 +171,33 @@ namespace SHADE
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* BoxCollider - Usage Functions */ /* CapsuleCollider - Properties */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
bool BoxCollider::TestPoint(Vector3 point) Vector3 CapsuleCollider::Center::get()
{ {
//return getNativeCollisionShape<SHAABB>().TestPoint(Convert::ToNative(point)); return Convert::ToCLI(getNativeCollisionShape<SHCapsule>().GetWorldCentroid());
return false;
} }
bool BoxCollider::Raycast(Ray ray, float maxDistance) float CapsuleCollider::Radius::get()
{ {
//return getNativeCollisionShape<SHAABB>().Raycast(Convert::ToNative(ray)); return getNativeCollisionShape<SHCapsule>().GetWorldRadius();
return false; }
void CapsuleCollider::Radius::set(float value)
{
getNativeCollisionShape<SHCapsule>().SetWorldRadius(value);
}
float CapsuleCollider::Height::get()
{
return getNativeCollisionShape<SHCapsule>().GetWorldHeight();
}
void CapsuleCollider::Height::set(float value)
{
getNativeCollisionShape<SHCapsule>().SetWorldHeight(value);
} }
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* SphereCollider - Properties */ /* CapsuleCollider - Constructors */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
Vector3 SphereCollider::Center::get() CapsuleCollider::CapsuleCollider(int arrayIndex, Entity attachedEntity)
{
return Convert::ToCLI(getNativeCollisionShape<SHSphere>().GetWorldCentroid());
}
float SphereCollider::Radius::get()
{
return getNativeCollisionShape<SHSphere>().GetWorldRadius();
}
void SphereCollider::Radius::set(float value)
{
getNativeCollisionShape<SHSphere>().SetWorldRadius(value);
}
/*---------------------------------------------------------------------------------*/
/* SphereCollider - Usage Functions */
/*---------------------------------------------------------------------------------*/
bool SphereCollider::TestPoint(Vector3 point)
{
//return getNativeCollisionShape<SHSphere>().TestPoint(Convert::ToNative(point));
return false;
}
bool SphereCollider::Raycast(Ray ray, float maxDistance)
{
//return getNativeCollisionShape<SHSphere>().Raycast(Convert::ToNative(ray));
return false;
}
/*---------------------------------------------------------------------------------*/
/* SphereCollider - Constructors */
/*---------------------------------------------------------------------------------*/
SphereCollider::SphereCollider(int arrayIndex, Entity attachedEntity)
: CollisionShape{ arrayIndex, attachedEntity } : CollisionShape{ arrayIndex, attachedEntity }
{} {}
@ -303,18 +307,18 @@ namespace SHADE
int i = 0; int i = 0;
for (const auto& collider : GetNativeComponent()->GetCollisionShapes()) for (const auto& collider : GetNativeComponent()->GetCollisionShapes())
{ {
CollisionShape^ bound = nullptr; CollisionShape^ shape = nullptr;
switch (collider->GetType()) switch (collider->GetType())
{ {
case SHCollisionShape::Type::BOX:
bound = gcnew BoxCollider(i, Owner.GetEntity());
break;
case SHCollisionShape::Type::SPHERE: case SHCollisionShape::Type::SPHERE:
bound = gcnew SphereCollider(i, Owner.GetEntity()); shape = gcnew SphereCollider(i, Owner.GetEntity());
break;
case SHCollisionShape::Type::BOX:
shape = gcnew BoxCollider(i, Owner.GetEntity());
break;
case SHCollisionShape::Type::CAPSULE:
shape = gcnew CapsuleCollider(i, Owner.GetEntity());
break; break;
//case SHCollisionShape::Type::CAPSULE:
// // TODO
// break;
default: default:
Debug::LogWarning("[Collider] An invalid Collider Type was detected. Skipping."); Debug::LogWarning("[Collider] An invalid Collider Type was detected. Skipping.");
break; break;
@ -322,7 +326,7 @@ namespace SHADE
++i; ++i;
// Add into list // Add into list
subColliderList->Add(bound); subColliderList->Add(shape);
} }
} }
} }

View File

@ -16,6 +16,7 @@ of DigiPen Institute of Technology is prohibited.
// Primary Include // Primary Include
#include "Component.hxx" #include "Component.hxx"
namespace SHADE namespace SHADE
{ {
template<typename CollisionShapeType> template<typename CollisionShapeType>
@ -28,7 +29,7 @@ namespace SHADE
try try
{ {
auto& shape = collider->GetCollisionShape(arrayIndex); auto& shape = collider->GetCollisionShape(arrayIndex);
if (shape.GetType() != SHCollisionShape::Type::BOX) if (shape.GetType() == SHCollisionShape::Type::INVALID)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape."); throw gcnew System::InvalidOperationException("Attempted to retrieve invalid CollisionShape.");
return dynamic_cast<CollisionShapeType&>(shape); return dynamic_cast<CollisionShapeType&>(shape);

View File

@ -87,23 +87,6 @@ namespace SHADE
void set(float value); void set(float value);
} }
/*-----------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Checks if the specified point is within this shape's bounds.
/// </summary>
/// <param name="point">Point to test with.</param>
/// <returns>True if the point is in the shape's bounds.</returns>
virtual bool TestPoint(Vector3 point) = 0;
/// <summary>
/// Computes a Raycast and checks if there is a collision with any object.
/// </summary>
/// <param name="ray">The ray to cast.</param>
/// <param name="maxDistance">Maximum distance for the raycast check.</param>
/// <returns>True if the ray intersects with an object in the scene.</returns>
virtual bool Raycast(Ray ray, float maxDistance) = 0;
protected: protected:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
@ -135,7 +118,39 @@ namespace SHADE
}; };
/// <summary> /// <summary>
/// Box-shaped Collider Bound. /// A Sphere Collider
/// </summary>
public ref class SphereCollider : public CollisionShape
{
public:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Center of the sphere.
/// </summary>
property Vector3 Center
{
Vector3 get();
}
/// <summary>
/// Radius of the sphere/
/// </summary>
property float Radius
{
float get();
void set(float value);
}
internal:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
SphereCollider(int arrayIndex, Entity attachedEntity);
};
/// <summary>
/// A Box Collider
/// </summary> /// </summary>
public ref class BoxCollider : public CollisionShape public ref class BoxCollider : public CollisionShape
{ {
@ -166,14 +181,6 @@ namespace SHADE
Quaternion get(); Quaternion get();
} }
/*-----------------------------------------------------------------------------*/
/* ColliderBound Functions */
/*-----------------------------------------------------------------------------*/
/// <inheritdoc/>
bool TestPoint(Vector3 point) override;
/// <inheritdoc/>
bool Raycast(Ray ray, float maxDistance) override;
internal: internal:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
@ -182,45 +189,46 @@ namespace SHADE
}; };
/// <summary> /// <summary>
/// Sphere-shaped Collider Bound. /// A Capsule Collider
/// </summary> /// </summary>
public ref class SphereCollider : public CollisionShape public ref class CapsuleCollider : public CollisionShape
{ {
public: public:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Properties */ /* Properties */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Center of the sphere. /// Center of the capsule.
/// </summary> /// </summary>
property Vector3 Center property Vector3 Center
{ {
Vector3 get(); Vector3 get();
} }
/// <summary> /// <summary>
/// Radius of the Bounding Sphere formed by this bound. /// Radius of the capsule.
/// </summary> /// </summary>
property float Radius property float Radius
{ {
float get(); float get();
void set(float value); void set(float value);
} }
/// <summary>
/*-----------------------------------------------------------------------------*/ /// Height of the capsule.
/* ColliderBound Functions */ /// </summary>
/*-----------------------------------------------------------------------------*/ property float Height
/// <inheritdoc/> {
bool TestPoint(Vector3 point) override; float get();
/// <inheritdoc/> void set(float value);
bool Raycast(Ray ray, float maxDistance) override; }
internal: internal:
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Constructors */ /* Constructors */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
SphereCollider(int arrayIndex, Entity attachedEntity); CapsuleCollider(int arrayIndex, Entity attachedEntity);
}; };
/// <summary> /// <summary>
/// CLR version of the the SHADE Engine's SHColliderComponent. /// CLR version of the the SHADE Engine's SHColliderComponent.
/// A single Collider component can contain one or multiple Collider Bounds. /// A single Collider component can contain one or multiple Collider Bounds.

View File

@ -13,6 +13,11 @@ namespace SHADE
} }
void TrajectoryRenderable::SimulateTrajectory(EntityID eid, Vector3 force, float timestep, uint32_t maxSteps)
{
GetNativeComponent()->SimulateTrajectory(eid, Convert::ToNative(force), timestep, maxSteps);
}
MeshAsset TrajectoryRenderable::Mesh::get() MeshAsset TrajectoryRenderable::Mesh::get()
{ {
auto mesh = GetNativeComponent()->GetMesh(); auto mesh = GetNativeComponent()->GetMesh();

Some files were not shown because too many files have changed in this diff Show More