Merge remote-tracking branch 'origin/main' into SP3-1-Rendering

This commit is contained in:
Brandon Mak 2022-10-30 13:18:15 +08:00
commit 7b769057a2
26 changed files with 1037 additions and 448 deletions

View File

@ -159,7 +159,7 @@ namespace Sandbox
SHSceneManager::Exit(); SHSceneManager::Exit();
SHSystemManager::Exit(); SHSystemManager::Exit();
SHAssetManager::Unload(); SHAssetManager::Exit();
} }
} }

View File

@ -61,8 +61,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// method.
/// </summary>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(MethodInfo method)
{
// No errors, assign
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[1];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -86,7 +103,7 @@ namespace SHADE
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1> action) public CallbackAction(Action<T1> action)
{ {
targetAction = action; targetAction = action;
@ -103,7 +120,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1); targetAction.Invoke(t1);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
_ = targetMethod.Invoke(TargetObject, parameters); _ = targetMethod.Invoke(TargetObject, parameters);
@ -138,8 +155,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// method.
/// </summary>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(MethodInfo method)
{
// No errors, assign
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[2];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -158,12 +192,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[2];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2> action) public CallbackAction(Action<T1, T2> action)
{ {
targetAction = action; targetAction = action;
@ -180,7 +214,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2); targetAction.Invoke(t1, t2);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -216,8 +250,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// method.
/// </summary>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(MethodInfo method)
{
// No errors, assign
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[3];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -236,12 +287,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[3];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3> action) public CallbackAction(Action<T1, T2, T3> action)
{ {
targetAction = action; targetAction = action;
@ -258,7 +309,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3); targetAction.Invoke(t1, t2, t3);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -295,8 +346,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// method.
/// </summary>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(MethodInfo method)
{
// No errors, assign
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[4];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -315,12 +383,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[4];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3, T4> action) public CallbackAction(Action<T1, T2, T3, T4> action)
{ {
targetAction = action; targetAction = action;
@ -337,7 +405,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3, t4); targetAction.Invoke(t1, t2, t3, t4);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -375,8 +443,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// method.
/// </summary>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(MethodInfo method)
{
// No errors, assign
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[5];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -395,12 +480,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[5];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3, T4, T5> action) public CallbackAction(Action<T1, T2, T3, T4, T5> action)
{ {
targetAction = action; targetAction = action;
@ -417,7 +502,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3, t4, t5); targetAction.Invoke(t1, t2, t3, t4, t5);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -456,8 +541,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// method.
/// </summary>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(MethodInfo method)
{
// No errors, assign
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[6];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -476,12 +578,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[6];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6> action) public CallbackAction(Action<T1, T2, T3, T4, T5, T6> action)
{ {
targetAction = action; targetAction = action;
@ -498,7 +600,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3, t4, t5, t6); targetAction.Invoke(t1, t2, t3, t4, t5, t6);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -538,8 +640,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// method.
/// </summary>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(MethodInfo method)
{
// No errors, assign
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[7];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -558,12 +677,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[7];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7> action) public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7> action)
{ {
targetAction = action; targetAction = action;
@ -580,7 +699,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7); targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -621,8 +740,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// method.
/// </summary>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(MethodInfo method)
{
// No errors, assign
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[8];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -641,12 +777,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[8];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8> action) public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
{ {
targetAction = action; targetAction = action;
@ -663,7 +799,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8); targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -705,8 +841,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// method.
/// </summary>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(MethodInfo method)
{
// No errors, assign
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[9];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -725,12 +878,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[9];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> action) public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> action)
{ {
targetAction = action; targetAction = action;
@ -747,7 +900,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9); targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;
@ -790,8 +943,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// method.
/// </summary>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(MethodInfo method)
{
// No errors, assign
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[10];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -810,12 +980,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[10];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action) public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action)
{ {
targetAction = action; targetAction = action;
@ -832,7 +1002,7 @@ namespace SHADE
{ {
targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
parameters[0] = t1; parameters[0] = t1;
parameters[1] = t2; parameters[1] = t2;

View File

@ -78,8 +78,25 @@ namespace SHADE
/// </summary> /// </summary>
public CallbackAction() {} public CallbackAction() {}
/// <summary> /// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the /// Constructs a CallbackAction that represents a call to the specified static
/// specified target. /// method.
/// </summary>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(MethodInfo method)
{
// No errors, assign
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[<#=i#>];
}
/// <summary>
/// Constructs a CallbackAction that represents a call to a specified member
/// method on the specified target.
/// </summary> /// </summary>
/// <param name="target">Object to call the method on.</param> /// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param> /// <param name="method">Method to call.</param>
@ -98,12 +115,12 @@ namespace SHADE
targetMethod = method; targetMethod = method;
// Create storage for parameters for calling // Create storage for parameters for calling
parameters = new Object[1]; parameters = new Object[<#=i#>];
} }
/// <summary> /// <summary>
/// Constructs a Callback action based on an action. /// Constructs a Callback action based on an action.
/// </summary> /// </summary>
/// <param name="action"></param> /// <param name="action">Action that wraps a function to be called.</param>
public CallbackAction(Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action) public CallbackAction(Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action)
{ {
targetAction = action; targetAction = action;
@ -120,7 +137,7 @@ namespace SHADE
{ {
targetAction.Invoke(<# for (int t = 1; t < i + 1; ++t) { #>t<#=t#><# if (t != i) { #>, <# } #><# } #>); targetAction.Invoke(<# for (int t = 1; t < i + 1; ++t) { #>t<#=t#><# if (t != i) { #>, <# } #><# } #>);
} }
else if (TargetObject != null && targetMethod != null) else if (targetMethod != null)
{ {
<# for (int t = 0; t < i; ++t) {#>parameters[<#=t#>] = t<#=t+1#>; <# for (int t = 0; t < i; ++t) {#>parameters[<#=t#>] = t<#=t+1#>;
<# } #>_ = targetMethod.Invoke(TargetObject, parameters); <# } #>_ = targetMethod.Invoke(TargetObject, parameters);

View File

@ -0,0 +1,23 @@
/******************************************************************************
* \file SHMaterialAsset.h
* \author Loh Xiao Qi
* \date 29 October 2022
* \brief
*
* \copyright Copyright (c) 2021 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 "Assets/Asset Types/SHAssetData.h"
#include <string>
namespace SHADE
{
struct SHMaterialAsset : SHAssetData
{
std::string name;
std::string data;
};
}

View File

@ -0,0 +1,23 @@
/******************************************************************************
* \file SHPrefabAsset.h
* \author Loh Xiao Qi
* \date 28 October 2022
* \brief
*
* \copyright Copyright (c) 2021 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 "SHAssetData.h"
#include <string>
namespace SHADE
{
struct SHPrefabAsset : SHAssetData
{
std::string name;
std::string data;
};
}

View File

@ -0,0 +1,23 @@
/******************************************************************************
* \file SHSceneAsset.h
* \author Loh Xiao Qi
* \date 28 October 2022
* \brief
*
* \copyright Copyright (c) 2021 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 "SHAssetData.h"
#include <string>
namespace SHADE
{
struct SHSceneAsset : SHAssetData
{
std::string name;
std::string data;
};
}

View File

@ -18,5 +18,6 @@ namespace SHADE
struct SHAssetLoader struct SHAssetLoader
{ {
virtual SHAssetData* Load(AssetPath path) = 0; virtual SHAssetData* Load(AssetPath path) = 0;
virtual void Write(SHAssetData const* data, AssetPath path) = 0;
}; };
} }

View File

@ -22,6 +22,7 @@ namespace SHADE
if (!file.is_open()) if (!file.is_open())
{ {
SHLOG_ERROR("Unable to open SHMesh File: {}", path.string()); SHLOG_ERROR("Unable to open SHMesh File: {}", path.string());
return;
} }
const std::string name{ path.stem().string() }; const std::string name{ path.stem().string() };
@ -75,4 +76,55 @@ namespace SHADE
return result; return result;
} }
void SHMeshLoader::Write(SHAssetData const* data, AssetPath path)
{
std::ofstream file{ path, std::ios::out | std::ios::binary | std::ios::trunc };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open file for writing mesh file: {}", path.string());
}
auto asset = *dynamic_cast<SHMeshAsset const*>(data);
file.write(
reinterpret_cast<char const*>(&(asset.header.vertexCount)),
sizeof(uint32_t)
);
file.write(
reinterpret_cast<const char*>(&(asset.header.indexCount)),
sizeof(uint32_t)
);
auto const vertexVec3Byte{ sizeof(SHVec3) * asset.header.vertexCount };
auto const vertexVec2Byte{ sizeof(SHVec2) * asset.header.vertexCount };
file.write(
reinterpret_cast<char const*>(asset.vertexPosition.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexTangent.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.vertexNormal.data()),
vertexVec3Byte
);
file.write(
reinterpret_cast<char const*>(asset.texCoords.data()),
vertexVec2Byte
);
file.write(
reinterpret_cast<char const*>(asset.indices.data()),
sizeof(uint32_t) * asset.header.indexCount
);
file.close();
}
} }

View File

@ -10,7 +10,6 @@
* of DigiPen Institute of Technology is prohibited. * of DigiPen Institute of Technology is prohibited.
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#include "Assets/SHAssetMacros.h"
#include "Assets/Asset Types/SHMeshAsset.h" #include "Assets/Asset Types/SHMeshAsset.h"
#include "SHAssetLoader.h" #include "SHAssetLoader.h"
@ -20,5 +19,6 @@ namespace SHADE
{ {
void LoadSHMesh(AssetPath path, SHMeshAsset& meshes) noexcept; void LoadSHMesh(AssetPath path, SHMeshAsset& meshes) noexcept;
SHAssetData* Load(AssetPath path) override; SHAssetData* Load(AssetPath path) override;
void Write(SHAssetData const* data, AssetPath path) override;
}; };
} }

View File

@ -43,4 +43,27 @@ namespace SHADE
return result; return result;
} }
void SHShaderSourceLoader::Write(SHAssetData const* data, AssetPath path)
{
std::ofstream file{ path, std::ios::binary | std::ios::out | std::ios::trunc };
auto asset = *dynamic_cast<SHShaderAsset const*>(data);
file.write(
reinterpret_cast<char const*>(&asset.shaderType), sizeof(uint8_t)
);
size_t const byteCount = sizeof(uint32_t) * asset.spirvBinary.size();
file.write(
reinterpret_cast<char const*>(&byteCount), sizeof(size_t)
);
file.write(
reinterpret_cast<char const*>(asset.spirvBinary.data()), byteCount
);
file.close();
}
} }

View File

@ -11,12 +11,12 @@
#pragma once #pragma once
#include "Assets/Libraries/Loaders/SHAssetLoader.h" #include "Assets/Libraries/Loaders/SHAssetLoader.h"
#include "Assets/SHAssetMacros.h"
namespace SHADE namespace SHADE
{ {
struct SHShaderSourceLoader : SHAssetLoader struct SHShaderSourceLoader : SHAssetLoader
{ {
SHAssetData* Load(AssetPath path) override; SHAssetData* Load(AssetPath path) override;
void Write(SHAssetData const* data, AssetPath path) override;
}; };
} }

View File

@ -0,0 +1,95 @@
/******************************************************************************
* \file SHTextBasedLoader.cpp
* \author Loh Xiao Qi
* \date 28 October 2022
* \brief
*
* \copyright Copyright (c) 2021 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 "SHTextBasedLoader.h"
#include "Assets/Asset Types/SHSceneAsset.h"
#include "Assets/Asset Types/SHPrefabAsset.h"
#include "Assets/Asset Types/SHMaterialAsset.h"
#include <fstream>
#include <sstream>
namespace SHADE
{
SHAssetData* SHTextBasedLoader::Load(AssetPath path)
{
std::ifstream file{ path, std::ios::in };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open text File: {}", path.string());
return nullptr;
}
std::stringstream stream;
stream << file.rdbuf();
std::string content = stream.str();
SHAssetData* result;
if (path.extension().string() == SCENE_EXTENSION)
{
auto data = new SHSceneAsset();
data->name = path.stem().string();
data->data = std::move(content);
result = data;
}
else if (path.extension().string() == PREFAB_EXTENSION)
{
auto data = new SHPrefabAsset();
data->name = path.stem().string();
data->data = std::move(content);
result = data;
}
else if (path.extension().string() == MATERIAL_EXTENSION)
{
auto data = new SHMaterialAsset();
data->name = path.stem().string();
data->data = std::move(content);
result = data;
}
file.close();
return result;
}
void SHTextBasedLoader::Write(SHAssetData const* data, AssetPath path)
{
std::ofstream file{ path, std::ios::out | std::ios::trunc };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open text File: {}", path.string());
return;
}
if (path.extension().string() == SCENE_EXTENSION)
{
auto scene = dynamic_cast<SHSceneAsset const*>(data);
file << scene->data;
}
else if (path.extension().string() == PREFAB_EXTENSION)
{
auto prefab = dynamic_cast<SHPrefabAsset const*>(data);
file << prefab->data;
}
else if (path.extension().string() == MATERIAL_EXTENSION)
{
auto material = dynamic_cast<SHMaterialAsset const*>(data);
file << material->data;
}
file.close();
}
}

View File

@ -0,0 +1,21 @@
/******************************************************************************
* \file Header.h
* \author Loh Xiao Qi
* \date 28 October 2022
* \brief
*
* \copyright Copyright (c) 2021 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 "SHAssetLoader.h"
namespace SHADE
{
struct SHTextBasedLoader : SHAssetLoader
{
SHAssetData* Load(AssetPath path) override;
void Write(SHAssetData const* data, AssetPath path) override;
};
}

View File

@ -17,42 +17,94 @@
namespace SHADE namespace SHADE
{ {
void SHTextureLoader::LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept void SHTextureLoader::LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept
{ {
std::ifstream file{ path.string(), std::ios::in | std::ios::binary }; std::ifstream file{ path.string(), std::ios::in | std::ios::binary };
if (!file.is_open()) if (!file.is_open())
{ {
SHLOG_ERROR("Error opening SHTexture file: {}", path.string()); SHLOG_ERROR("Error opening SHTexture file: {}", path.string());
} }
auto const intBytes{ sizeof(uint32_t) }; auto const intBytes{ sizeof(uint32_t) };
uint32_t mipCount; uint32_t mipCount;
file.read(reinterpret_cast<char*>(&asset.numBytes), intBytes); file.read(reinterpret_cast<char*>(&asset.numBytes), intBytes);
file.read(reinterpret_cast<char*>(&asset.width), intBytes); file.read(reinterpret_cast<char*>(&asset.width), intBytes);
file.read(reinterpret_cast<char*>(&asset.height), intBytes); file.read(reinterpret_cast<char*>(&asset.height), intBytes);
file.read(reinterpret_cast<char*>(&asset.format), sizeof(SHTexture::TextureFormat)); file.read(reinterpret_cast<char*>(&asset.format), sizeof(SHTexture::TextureFormat));
file.read(reinterpret_cast<char*>(&mipCount), intBytes); file.read(reinterpret_cast<char*>(&mipCount), intBytes);
std::vector<uint32_t> mips(mipCount); std::vector<uint32_t> mips(mipCount);
file.read(reinterpret_cast<char*>(mips.data()), intBytes * mipCount); file.read(reinterpret_cast<char*>(mips.data()), intBytes * mipCount);
auto pixel = new SHTexture::PixelChannel[asset.numBytes]; auto pixel = new SHTexture::PixelChannel[asset.numBytes];
file.read(reinterpret_cast<char*>(pixel), asset.numBytes); file.read(reinterpret_cast<char*>(pixel), asset.numBytes);
asset.mipOffsets = std::move(mips); asset.mipOffsets = std::move(mips);
asset.pixelData = std::move(pixel); asset.pixelData = std::move(pixel);
asset.compiled = true; asset.compiled = true;
file.close(); file.close();
} }
SHAssetData* SHTextureLoader::Load(AssetPath path) SHAssetData* SHTextureLoader::Load(AssetPath path)
{ {
auto result = new SHTextureAsset(); auto result = new SHTextureAsset();
LoadSHTexture(path, *result); LoadSHTexture(path, *result);
return result; return result;
} }
void SHTextureLoader::Write(SHAssetData const* data, AssetPath path)
{
std::ofstream file{ path, std::ios::out | std::ios::binary };
if (!file.is_open())
{
SHLOG_ERROR("Unable to open file for writing texture file: {}", path.string());
}
auto asset = *dynamic_cast<SHTextureAsset const*>(data);
constexpr auto intBytes{ sizeof(uint32_t) };
uint32_t const mipOffsetCount{ static_cast<uint32_t>(asset.mipOffsets.size()) };
file.write(
reinterpret_cast<char const*>(&asset.numBytes),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.width),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.height),
intBytes
);
file.write(
reinterpret_cast<char const*>(&asset.format),
sizeof(SHTexture::TextureFormat)
);
file.write(
reinterpret_cast<char const*>(&mipOffsetCount),
intBytes
);
file.write(
reinterpret_cast<char const*>(asset.mipOffsets.data()),
intBytes * asset.mipOffsets.size()
);
file.write(
reinterpret_cast<char const*>(asset.pixelData),
asset.numBytes
);
file.close();
}
} }

View File

@ -10,8 +10,6 @@
* of DigiPen Institute of Technology is prohibited. * of DigiPen Institute of Technology is prohibited.
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#include "Assets/SHAssetMacros.h"
#include "Assets/Asset Types/SHTextureAsset.h" #include "Assets/Asset Types/SHTextureAsset.h"
#include "SHAssetLoader.h" #include "SHAssetLoader.h"
@ -21,5 +19,6 @@ namespace SHADE
{ {
void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept; void LoadSHTexture(AssetPath path, SHTextureAsset& asset) noexcept;
SHAssetData* Load(AssetPath path) override; SHAssetData* Load(AssetPath path) override;
void Write(SHAssetData const* data, AssetPath path) override;
}; };
} }

View File

@ -11,7 +11,6 @@
*****************************************************************************/ *****************************************************************************/
#pragma once #pragma once
#include "Filesystem/SHFileSystem.h"
#include "Assets/SHAssetMacros.h" #include "Assets/SHAssetMacros.h"
#include "SH_API.h" #include "SH_API.h"
@ -23,6 +22,5 @@ namespace SHADE
AssetID id; AssetID id;
AssetType type; AssetType type;
AssetPath path; AssetPath path;
FolderLocation location;
}; };
} }

View File

@ -47,17 +47,27 @@ enum class AssetType : AssetTypeMeta
SHADER_BUILT_IN, SHADER_BUILT_IN,
TEXTURE, TEXTURE,
MESH, MESH,
SCENE,
PREFAB,
MATERIAL,
MAX_COUNT 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) };
//Directory //Directory
#ifdef _PUBLISH #ifdef _PUBLISH
constexpr std::string_view ASSET_ROOT {"Assets"}; constexpr std::string_view ASSET_ROOT{ "Assets" };
constexpr std::string_view BUILT_IN_ASSET_ROOT {"Built_In"};
#else #else
constexpr std::string_view ASSET_ROOT {"../../Assets"}; constexpr std::string_view ASSET_ROOT {"../../Assets"};
constexpr std::string_view BUILT_IN_ASSET_ROOT{ "../../Built_In" };
#endif #endif
// INTERNAL ASSET PATHS
constexpr std::string_view SCENE_FOLDER{ "/Scenes/" };
constexpr std::string_view PREFAB_FOLDER{ "/Prefabs/" };
constexpr std::string_view MATERIAL_FOLDER{ "/Materials/" };
// ASSET EXTENSIONS // ASSET EXTENSIONS
constexpr std::string_view META_EXTENSION {".shmeta"}; constexpr std::string_view META_EXTENSION {".shmeta"};

View File

@ -10,27 +10,33 @@
#include "SHpch.h" #include "SHpch.h"
#include <random> #include <random>
#include <chrono> #include <chrono>
#include <ranges>
#include "SHAssetManager.h" #include "SHAssetManager.h"
#include "SHAssetMetaHandler.h" #include "SHAssetMetaHandler.h"
#include "Filesystem/SHFileSystem.h"
#include "Libraries/Loaders/SHMeshLoader.h" #include "Libraries/Loaders/SHMeshLoader.h"
#include "Libraries/Loaders/SHTextureLoader.h" #include "Libraries/Loaders/SHTextureLoader.h"
#include "Libraries/Loaders/SHShaderSourceLoader.h" #include "Libraries/Loaders/SHShaderSourceLoader.h"
#include "Libraries/Loaders/SHTextBasedLoader.h"
#include "Libraries/Compilers/SHMeshCompiler.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"
#include "Filesystem/SHFileSystem.h"
namespace SHADE namespace SHADE
{ {
FolderPointer SHAssetManager::folderRoot{ nullptr };
FMOD::System* SHAssetManager::audioSystem; FMOD::System* SHAssetManager::audioSystem;
std::unordered_map<AssetID, SHSound >* SHAssetManager::audioSoundList; std::unordered_map<AssetID, SHSound >* SHAssetManager::audioSoundList;
std::vector<SHAssetLoader*> SHAssetManager::loaders(TYPE_COUNT); std::vector<SHAssetLoader*> SHAssetManager::loaders(TYPE_COUNT);
std::vector<SHAsset> SHAssetManager::assetCollection; std::unordered_map<AssetID, SHAsset> SHAssetManager::assetCollection;
std::unordered_map<AssetID, SHAssetData * const> SHAssetManager::assetData; std::unordered_map<AssetID, SHAssetData * const> SHAssetManager::assetData;
/**************************************************************************** /****************************************************************************
* \brief Static function to generate asset ID. * \brief Static function to generate asset ID.
@ -45,13 +51,7 @@ namespace SHADE
result |= unique; result |= unique;
while (result == 0 || while (result == 0 || assetCollection.contains(result))
std::ranges::any_of(
assetCollection.begin(),
assetCollection.end(),
[result](SHAsset const& asset) { return asset.id == result; }
)
)
{ {
result = GenerateAssetID(type); result = GenerateAssetID(type);
} }
@ -61,11 +61,6 @@ namespace SHADE
/**************************************************************************** /****************************************************************************
* \brief Deallocate all memory used by asset data * \brief Deallocate all memory used by asset data
****************************************************************************/ ****************************************************************************/
void SHAssetManager::Unload() noexcept
{
}
void SHAssetManager::Unload(AssetID assetId) noexcept void SHAssetManager::Unload(AssetID assetId) noexcept
{ {
// TODO // TODO
@ -73,14 +68,14 @@ namespace SHADE
void SHAssetManager::Exit() noexcept void SHAssetManager::Exit() noexcept
{ {
for (auto const& loader : loaders) delete loaders[static_cast<size_t>(AssetType::SHADER)];
{ delete loaders[static_cast<size_t>(AssetType::TEXTURE)];
delete loader; delete loaders[static_cast<size_t>(AssetType::MESH)];
} delete loaders[static_cast<size_t>(AssetType::SCENE)];
for (auto const& data : assetData) for (auto const& data : std::ranges::views::values(assetData))
{ {
delete data.second; delete data;
} }
} }
@ -113,8 +108,8 @@ namespace SHADE
{ {
case AssetType::SHADER: case AssetType::SHADER:
case AssetType::SHADER_BUILT_IN: case AssetType::SHADER_BUILT_IN:
folder = "Shaders/"; folder = "Shaders/";
break; break;
default: default:
folder = "/"; folder = "/";
@ -133,9 +128,17 @@ namespace SHADE
* *
* \return const& to unordered_map<AssetName, AssetID> * \return const& to unordered_map<AssetName, AssetID>
****************************************************************************/ ****************************************************************************/
std::vector<SHAsset> const& SHAssetManager::GetAllAssets() noexcept std::vector<SHAsset> SHAssetManager::GetAllAssets() noexcept
{ {
return assetCollection; std::vector<SHAsset> result;
result.reserve(assetCollection.size());
for (auto const& asset : std::ranges::views::values(assetCollection))
{
result.push_back(asset);
}
return result;
} }
/**************************************************************************** /****************************************************************************
@ -148,41 +151,113 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
AssetID SHAssetManager::CreateNewAsset(AssetType type, AssetName name) noexcept AssetID SHAssetManager::CreateNewAsset(AssetType type, AssetName name) noexcept
{ {
AssetID id{ GenerateAssetID(type) }; std::string newPath{ ASSET_ROOT };
SHAsset meta; switch (type)
meta.id = id; {
meta.type = type; case AssetType::PREFAB:
newPath += PREFAB_FOLDER;
break;
std::string folder; case AssetType::SCENE:
//TODO implement folder choosing newPath += SCENE_FOLDER;
//switch (type) break;
//{
//default:
// folder = "";
// break;
//}
AssetPath path{ std::string{ASSET_ROOT} + folder + name + SHAssetMetaHandler::GetExtensionFromType(type) };
SHAssetMetaHandler::WriteMetaData(meta); case AssetType::MATERIAL:
newPath += MATERIAL_FOLDER;
break;
assetCollection.push_back(meta); default:
SHLOG_ERROR("Asset type of {} not an internal asset type, cannot be created", name);
return 0;
}
auto id = GenerateAssetID(type);
SHAsset asset{
name,
id,
type,
newPath
};
assetCollection.insert({
id,
SHAsset(
name,
id,
type,
newPath
)
});
return id; return id;
} }
AssetID SHAssetManager::CreateAsset(AssetName name, AssetType type) noexcept bool SHAssetManager::SaveAsset(AssetID id) noexcept
{ {
AssetID id = GenerateAssetID(type); if (assetCollection.contains(id))
{
auto const& asset = assetCollection[id];
if (
asset.type == AssetType::SCENE ||
asset.type == AssetType::PREFAB ||
asset.type == AssetType::MATERIAL
)
{
if (assetData.contains(id))
{
auto const data = assetData.at(id);
loaders[static_cast<size_t>(asset.type)]->Write(data, asset.path);
SHAssetMetaHandler::WriteMetaData(asset);
return true;
}
SHLOG_ERROR("Asset data has not been written into, cannot be saved: {}",
asset.path.filename().string());
return false;
}
}
SHLOG_WARNING("Asset id: {} not an internal asset type, save cannot be triggered", id);
return false;
}
bool SHAssetManager::DeleteAsset(AssetID id) noexcept
{
if (assetCollection.contains(id))
{
auto const& asset = assetCollection[id];
if (
asset.type == AssetType::SCENE ||
asset.type == AssetType::PREFAB ||
asset.type == AssetType::MATERIAL
)
{
return (DeleteLocalFile(asset.path) && DeleteLocalFile(asset.path.string() + META_EXTENSION.data()));
}
SHLOG_WARNING("Asset id: {} not an internal asset type, file deletion not allowed", id);
}
SHLOG_WARNING("Asset id does not exist, nothing was deleted: {}", id);
return false;
}
//AssetID SHAssetManager::CreateAsset(AssetName name, AssetType type) noexcept
//{
// AssetID id = GenerateAssetID(type);
// assetCollection.emplace_back(
// name,
// id,
// type,
// GenerateNewPath(name, type)
// );
// return id;
//}
assetCollection.emplace_back(
name,
id,
type,
GenerateNewPath(name, type),
0
);
return id;
}
/**************************************************************************** /****************************************************************************
* \brief Import new asset from outside editor window. * \brief Import new asset from outside editor window.
* *
@ -205,7 +280,8 @@ namespace SHADE
std::filesystem::copy(path, newPath); std::filesystem::copy(path, newPath);
assetCollection.push_back(CreateAssetFromPath(newPath)); auto asset = CreateAssetFromPath(newPath);
assetCollection.insert({asset.id, asset});
return id; return id;
} }
@ -235,7 +311,7 @@ namespace SHADE
std::vector<SHAsset> SHAssetManager::GetAllRecordOfType(AssetType type) noexcept std::vector<SHAsset> SHAssetManager::GetAllRecordOfType(AssetType type) noexcept
{ {
std::vector<SHAsset> result; std::vector<SHAsset> result;
for (auto const& asset : assetCollection) for (auto const& asset : std::ranges::views::values(assetCollection))
{ {
if (asset.type == type) if (asset.type == type)
{ {
@ -246,26 +322,30 @@ namespace SHADE
return result; return result;
} }
AssetID SHAssetManager::CompileAsset(AssetPath path) noexcept AssetID SHAssetManager::CompileAsset(AssetPath const& path) noexcept
{
SHAsset newAsset
{
.name = path.stem().string()
};
auto const ext{ path.extension().string() };
if (ext == GLSL_EXTENSION.data())
{
newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value();
newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN);
newAsset.type = AssetType::SHADER_BUILT_IN;
}
assetCollection.insert({ newAsset.id, newAsset });
SHAssetMetaHandler::WriteMetaData(newAsset);
return newAsset.id;
}
FolderPointer SHAssetManager::GetRootFolder() noexcept
{ {
SHAsset newAsset return folderRoot;
{
.name = path.stem().string(),
.location = 0
};
auto const ext{ path.extension().string() };
if (ext == GLSL_EXTENSION.data())
{
newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value();
newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN);
newAsset.type = AssetType::SHADER_BUILT_IN;
}
assetCollection.push_back(newAsset);
SHAssetMetaHandler::WriteMetaData(newAsset);
return newAsset.id;
} }
bool SHAssetManager::IsRecognised(char const* ext) noexcept bool SHAssetManager::IsRecognised(char const* ext) noexcept
@ -289,82 +369,88 @@ namespace SHADE
result.type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string()); result.type = SHAssetMetaHandler::GetTypeFromExtension(path.extension().string());
result.id = GenerateAssetID(result.type); result.id = GenerateAssetID(result.type);
result.path = path; result.path = path;
result.location = 0;
return result; return result;
} }
void SHAssetManager::CompileAll() noexcept void SHAssetManager::CompileAll() noexcept
{
std::vector<AssetPath> paths;
for (auto const& dir : std::filesystem::recursive_directory_iterator{ ASSET_ROOT })
{
if (dir.is_regular_file())
{
for (auto const& ext : EXTERNALS)
{
if (dir.path().extension().string() == ext.data())
{
paths.push_back(dir.path());
}
}
}
}
for (auto const& path : paths)
{
SHAsset newAsset
{
.name = path.stem().string()
};
auto const ext{ path.extension().string() };
if (ext == GLSL_EXTENSION.data())
{
newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value();
newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN);
newAsset.type = AssetType::SHADER_BUILT_IN;
}
else if (ext == DDS_EXTENSION.data())
{
newAsset.path = SHTextureCompiler::CompileTextureAsset(path).value();
newAsset.id = GenerateAssetID(AssetType::TEXTURE);
newAsset.type = AssetType::TEXTURE;
}
else if (ext == GLTF_EXTENSION.data() || ext == FBX_EXTENSION.data())
{
std::vector<SHMeshAsset*> meshes;
std::vector<SHAnimationAsset*> anims;
SHMeshCompiler::LoadFromFile(path, meshes, anims);
for (auto const& mesh : meshes)
{
SHAsset meshAsset{
.name = mesh->header.name
};
meshAsset.path = SHMeshCompiler::CompileMeshBinary(*mesh, path).value();
meshAsset.id = GenerateAssetID(AssetType::MESH);
meshAsset.type = AssetType::MESH;
assetCollection.insert({ meshAsset.id, meshAsset });
SHAssetMetaHandler::WriteMetaData(meshAsset);
}
continue;
}
assetCollection.insert({ newAsset.id, newAsset });
SHAssetMetaHandler::WriteMetaData(newAsset);
}
}
bool SHAssetManager::DeleteLocalFile(AssetPath path) noexcept
{ {
std::vector<AssetPath> paths; //TODO Move this to dedicated library
return std::filesystem::remove(path);
for (auto const& dir : std::filesystem::recursive_directory_iterator{ ASSET_ROOT })
{
if (dir.is_regular_file())
{
for (auto const& ext : EXTERNALS)
{
if (dir.path().extension().string() == ext.data())
{
paths.push_back(dir.path());
}
}
}
}
for (auto const& path : paths)
{
SHAsset newAsset
{
.name = path.stem().string(),
.location = 0
};
auto const ext{ path.extension().string() };
if (ext == GLSL_EXTENSION.data())
{
newAsset.path = SHShaderSourceCompiler::LoadAndCompileShader(path).value();
newAsset.id = GenerateAssetID(AssetType::SHADER_BUILT_IN);
newAsset.type = AssetType::SHADER_BUILT_IN;
}
else if (ext == DDS_EXTENSION.data())
{
newAsset.path = SHTextureCompiler::CompileTextureAsset(path).value();
newAsset.id = GenerateAssetID(AssetType::TEXTURE);
newAsset.type = AssetType::TEXTURE;
}
else if (ext == GLTF_EXTENSION.data() || ext == FBX_EXTENSION.data())
{
std::vector<SHMeshAsset*> meshes;
std::vector<SHAnimationAsset*> anims;
SHMeshCompiler::LoadFromFile(path, meshes, anims);
for (auto const& mesh : meshes)
{
SHAsset meshAsset{
.name = mesh->header.name,
.location = 0
};
meshAsset.path = SHMeshCompiler::CompileMeshBinary(*mesh, path).value();
meshAsset.id = GenerateAssetID(AssetType::MESH);
meshAsset.type = AssetType::MESH;
assetCollection.push_back(meshAsset);
//SHAssetMetaHandler::WriteMetaData(meshAsset);
}
continue;
}
assetCollection.push_back(newAsset);
//SHAssetMetaHandler::WriteMetaData(newAsset);
}
} }
void SHAssetManager::InitLoaders() noexcept void SHAssetManager:: InitLoaders() noexcept
{ {
loaders[static_cast<size_t>(AssetType::SHADER)] = dynamic_cast<SHAssetLoader*>(new SHShaderSourceLoader()); loaders[static_cast<size_t>(AssetType::SHADER)] = dynamic_cast<SHAssetLoader*>(new SHShaderSourceLoader());
loaders[static_cast<size_t>(AssetType::SHADER_BUILT_IN)] = loaders[static_cast<size_t>(AssetType::SHADER)]; loaders[static_cast<size_t>(AssetType::SHADER_BUILT_IN)] = loaders[static_cast<size_t>(AssetType::SHADER)];
loaders[static_cast<size_t>(AssetType::TEXTURE)] = dynamic_cast<SHAssetLoader*>(new SHTextureLoader()); loaders[static_cast<size_t>(AssetType::TEXTURE)] = dynamic_cast<SHAssetLoader*>(new SHTextureLoader());
loaders[static_cast<size_t>(AssetType::MESH)] = dynamic_cast<SHAssetLoader*>(new SHMeshLoader()); loaders[static_cast<size_t>(AssetType::MESH)] = dynamic_cast<SHAssetLoader*>(new SHMeshLoader());
loaders[static_cast<size_t>(AssetType::SCENE)] = dynamic_cast<SHAssetLoader*>(new SHTextBasedLoader());
loaders[static_cast<size_t>(AssetType::PREFAB)] = loaders[static_cast<size_t>(AssetType::SCENE)];
loaders[static_cast<size_t>(AssetType::MATERIAL)] = loaders[static_cast<size_t>(AssetType::SCENE)];
} }
/**************************************************************************** /****************************************************************************
@ -372,9 +458,9 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::Load() noexcept void SHAssetManager::Load() noexcept
{ {
CompileAll(); //CompileAll();
BuildAssetCollection();
InitLoaders(); InitLoaders();
BuildAssetCollection();
//LoadAllData(); //LoadAllData();
} }
@ -383,7 +469,7 @@ namespace SHADE
****************************************************************************/ ****************************************************************************/
void SHAssetManager::LoadAllData() noexcept void SHAssetManager::LoadAllData() noexcept
{ {
for (auto const& asset : assetCollection) for (auto const& asset : std::ranges::views::values(assetCollection))
{ {
SHAssetData* data = loaders[static_cast<size_t>(asset.type)]->Load(asset.path); SHAssetData* data = loaders[static_cast<size_t>(asset.type)]->Load(asset.path);
assetData.emplace(asset.id, data); assetData.emplace(asset.id, data);
@ -406,17 +492,8 @@ namespace SHADE
return data; return data;
} }
void SHAssetManager::BuildAssetCollection() noexcept void SHAssetManager::BuildAssetCollection() noexcept
{ {
for (auto const& dir : std::filesystem::recursive_directory_iterator{ASSET_ROOT}) SHFileSystem::BuildDirectory(ASSET_ROOT.data(), folderRoot, assetCollection);
{ }
if (dir.is_regular_file())
{
if (dir.path().extension().string() == META_EXTENSION.data())
{
assetCollection.push_back(SHAssetMetaHandler::RetrieveMetaData(dir.path()));
}
}
}
}
} }

View File

@ -10,10 +10,12 @@
******************************************************************************/ ******************************************************************************/
#pragma once #pragma once
#include "tinyddsloader.h" #include "tinyddsloader.h"
#include "SHAsset.h" #include "SHAsset.h"
#include "Asset Types/SHAssetData.h" #include "Asset Types/SHAssetData.h"
#include "Assets/Libraries/Loaders/SHAssetLoader.h" #include "Assets/Libraries/Loaders/SHAssetLoader.h"
#include <memory>
#include "Filesystem/SHFolder.h"
#include "SH_API.h" #include "SH_API.h"
@ -26,19 +28,17 @@ namespace SHADE
* \brief Static function to generate resource ID. * \brief Static function to generate resource ID.
****************************************************************************/ ****************************************************************************/
static AssetID GenerateAssetID(AssetType type) noexcept; static AssetID GenerateAssetID(AssetType type) noexcept;
static AssetPath GenerateLocalPath(AssetPath path) noexcept; static AssetPath GenerateLocalPath(AssetPath path) noexcept;
static AssetPath GenerateNewPath(AssetName name, AssetType type); static AssetPath GenerateNewPath(AssetName name, AssetType type);
/**************************************************************************** /****************************************************************************
* \brief Deallocate all memory used by resource data * \brief Deallocate all memory used by resource data
****************************************************************************/ ****************************************************************************/
static void Unload() noexcept;
static void Unload(AssetID assetId) noexcept;
static void Exit() noexcept; static void Exit() noexcept;
static void Unload(AssetID assetId) noexcept;
/**************************************************************************** /****************************************************************************
* \brief Load all resources that are in the folder * \brief Load all resources that are in the folder
****************************************************************************/ ****************************************************************************/
@ -49,7 +49,7 @@ namespace SHADE
* *
* \return const& to unordered_map<AssetName, AssetID> * \return const& to unordered_map<AssetName, AssetID>
****************************************************************************/ ****************************************************************************/
static std::vector<SHAsset> const& GetAllAssets() noexcept; static std::vector<SHAsset> GetAllAssets() noexcept;
/**************************************************************************** /****************************************************************************
* \brief Create record for new resource. CAN ONLY CREATE FOR CUSTOM * \brief Create record for new resource. CAN ONLY CREATE FOR CUSTOM
@ -59,8 +59,9 @@ namespace SHADE
* \param name of resource * \param name of resource
* \return resource id generated for new asset * \return resource id generated for new asset
****************************************************************************/ ****************************************************************************/
static AssetID CreateNewAsset(AssetType, AssetName) noexcept; static AssetID CreateNewAsset(AssetType type, AssetName name) noexcept;
static AssetID CreateAsset(AssetName name, AssetType type) noexcept; static bool SaveAsset(AssetID id) noexcept;
static bool DeleteAsset(AssetID id) noexcept;
/**************************************************************************** /****************************************************************************
* \brief Import new resource from outside editor window. * \brief Import new resource from outside editor window.
@ -78,12 +79,17 @@ namespace SHADE
// -------------------------------------------------------------------------/ // -------------------------------------------------------------------------/
template<typename T> template<typename T>
static std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> GetData(AssetID id) noexcept; static std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T* const> GetData(AssetID id) noexcept;
template<typename T>
static std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> GetConstData(AssetID id) noexcept;
static std::vector<SHAssetData const*> GetAllDataOfType(AssetType type) noexcept; static std::vector<SHAssetData const*> GetAllDataOfType(AssetType type) noexcept;
static std::vector<SHAsset> GetAllRecordOfType(AssetType type) noexcept; static std::vector<SHAsset> GetAllRecordOfType(AssetType type) noexcept;
static AssetID CompileAsset(AssetPath path) noexcept; static AssetID CompileAsset(AssetPath const& path) noexcept;
static FolderPointer GetRootFolder() noexcept;
private: private:
@ -98,13 +104,20 @@ namespace SHADE
static void CompileAll() noexcept; static void CompileAll() noexcept;
static bool DeleteLocalFile(AssetPath path) noexcept;
//TODO use this function to create asset data internall at all calls to generate id
//static AssetID CreateAsset(AssetName name, AssetType type) noexcept;
static FolderPointer folderRoot;
static FMOD::System* audioSystem; static FMOD::System* audioSystem;
static std::unordered_map<AssetID,SHSound>* audioSoundList; static std::unordered_map<AssetID,SHSound>* audioSoundList;
static std::vector<SHAssetLoader*> loaders; static std::vector<SHAssetLoader*> loaders;
// For all resources // For all resources
static std::vector<SHAsset> assetCollection; static std::unordered_map<AssetID, SHAsset> assetCollection;
static std::unordered_map<AssetID, SHAssetData * const> assetData; static std::unordered_map<AssetID, SHAssetData * const> assetData;
}; };
} }

View File

@ -4,16 +4,16 @@
namespace SHADE namespace SHADE
{ {
template<typename T> template<typename T>
std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const* const> SHAssetManager::GetData(AssetID id) noexcept std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T* const> SHAssetManager::GetData(AssetID id) noexcept
{ {
if (!assetData.contains(id)) if (!assetData.contains(id))
{ {
for (auto const& asset : assetCollection) for (auto const& asset : std::ranges::views::values(assetCollection))
{ {
if (asset.id == id) if (asset.id == id)
{ {
assetData.emplace(id, LoadData(asset)); assetData.emplace(id, LoadData(asset));
return dynamic_cast<T const* const>(assetData[id]); return dynamic_cast<T* const>(assetData[id]);
} }
} }
@ -21,6 +21,27 @@ namespace SHADE
return nullptr; return nullptr;
} }
return dynamic_cast<T const* const>(assetData[id]); return dynamic_cast<T* const>(assetData[id]);
} }
template<typename T>
std::enable_if_t<std::is_base_of_v<SHAssetData, T>, T const * const> SHAssetManager::GetConstData(AssetID id) noexcept
{
if (!assetData.contains(id))
{
for (auto const& asset : std::ranges::views::values(assetCollection))
{
if (asset.id == id)
{
assetData.emplace(id, LoadData(asset));
return dynamic_cast<T const* const>(assetData[id]);
}
}
SHLOG_ERROR("Asset ID provided does not exist: {}", id);
return nullptr;
}
return dynamic_cast<T const* const>(assetData[id]);
}
} }

View File

@ -1,159 +1,82 @@
/*************************************************************************//**
* \file SHFileSystem.cpp
* \author Loh Xiao Qi
* \date 30 October 2022
* \brief
*
* 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.
*****************************************************************************/
#include "SHpch.h" #include "SHpch.h"
#include "SHFileSystem.h" #include "SHFileSystem.h"
#include "fileapi.h"
#include <filesystem> #include <filesystem>
#include <queue> #include <queue>
#include "Assets/SHAssetMetaHandler.h"
namespace SHADE namespace SHADE
{ {
char const FOLDER_MAX_COUNT {15};
std::unordered_map<FolderLocation, std::unique_ptr<SHFolder>> SHFileSystem::folders;
FolderPointer SHFileSystem::root {nullptr};
SHFolder::SHFolder(FolderHandle id, FolderName name)
:id{ id }, name{ name }, subFolders(0), folded{ false }, path{""}
{
}
FolderLocation SHFileSystem::CreateNewFolderHere(FolderName name, FolderLocation here) noexcept
{
if (here == 0)
{
if (!folders.contains(0))
{
folders[0] = std::make_unique<SHFolder>(0, "root");
}
auto const count = static_cast<FolderCounter>(folders[here]->subFolders.size());
if (count >= FOLDER_MAX_COUNT)
{
SHLOG_ERROR("Max subfolder reached: {}\n", name);
}
auto const location = static_cast<FolderLocation>(count);
CreateFolder(folders[0]->path, here, location, name);
return location;
}
if (!folders.contains(here))
{
SHLOG_ERROR("Folder creation location does not exist/invalid: {}\n", here);
}
auto const count = static_cast<FolderCounter>(folders[here]->subFolders.size());
FolderHandle location = here;
location <<= FOLDER_BIT_ALLOCATE;
location |= count;
if (count >= FOLDER_MAX_COUNT)
{
SHLOG_ERROR("Max subfolder reached: {}\n", name);
}
CreateFolder(folders[0]->path, here, location, name);
return location;
}
bool SHFileSystem::DeleteFolder(FolderPointer location) noexcept bool SHFileSystem::DeleteFolder(FolderPointer location) noexcept
{ {
if (!folders.contains(location->id)) //TODO IMPLEMENT
{
SHLOG_ERROR("Delete target does not exist/invalid: {}\n", location->name);
}
for (auto const& subFolder : folders[location->id]->subFolders)
{
DeleteFolder(subFolder);
}
RemoveDirectoryA(folders[location->id]->path.c_str());
return true; return true;
} }
void SHFileSystem::StartupFillDirectories(FolderPath path) noexcept void SHFileSystem::BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map<AssetID, SHAsset>& assetCollection) noexcept
{ {
std::queue<FolderPointer> folderQueue; std::queue<FolderPointer> folderQueue;
root = new SHFolder("root");
folderQueue.push(RegisterFolder(path, 0, 0, "Root")); root->path = path;
folderQueue.push(root);
while (!folderQueue.empty()) while (!folderQueue.empty())
{ {
auto folder = folderQueue.front(); auto const folder = folderQueue.front();
folderQueue.pop(); folderQueue.pop();
FolderCounter count = 0;
std::vector<SHAsset> assets;
for (auto const& dirEntry : std::filesystem::directory_iterator(folder->path)) for (auto const& dirEntry : std::filesystem::directory_iterator(folder->path))
{ {
auto const& path = dirEntry.path();
if (!dirEntry.is_directory()) if (!dirEntry.is_directory())
{ {
folder->files.emplace_back( if (path.extension().string() == META_EXTENSION)
dirEntry.path().filename().string(), {
dirEntry.path().string(), //auto asset = SHAssetMetaHandler::RetrieveMetaData(path);
dirEntry.path().extension().string() //assetCollection.insert({ asset.id, asset });
); assets.push_back(SHAssetMetaHandler::RetrieveMetaData(path));
}
continue; else
{
folder->files.emplace_back(
path.stem().string(),
path.string(),
path.extension().string(),
nullptr
);
}
continue;
} }
FolderLocation location = folder->id; auto newFolder{ folder->CreateSubFolderHere(path.stem().string()) };
location <<= FOLDER_BIT_ALLOCATE; folderQueue.push(newFolder);
location |= ++count;
std::string name = dirEntry.path().string();
name = name.substr(name.find_last_of('/') + 1, name.length() - name.find_last_of('/'));
FolderPointer newFolder{ RegisterFolder(
dirEntry.path().string(),
folder->id,
location,
name)
};
folderQueue.push(newFolder);
folder->subFolders.push_back(newFolder);
} }
for (auto const& asset : assets)
{
assetCollection.emplace(asset.id, asset);
for(auto& file : folder->files)
{
if (file.name == asset.name)
{
file.assetMeta = &assetCollection[asset.id];
break;
}
}
}
} }
} }
FolderPointer SHFileSystem::GetRoot() noexcept
{
return root;
}
FolderPointer SHFileSystem::CreateFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept
{
if (!CreateDirectoryA(path.c_str(), nullptr))
{
SHLOG_ERROR("Failed to create folder: {}\n", path);
}
folders[location] = std::make_unique<SHFolder>(location, name);
folders[location]->path = path;
folders[parent]->subFolders.push_back(folders[location].get());
return FolderMakeHelper(path, parent, location, name);
}
FolderPointer SHFileSystem::RegisterFolder(FolderPath path, FolderLocation parent, FolderHandle location,
FolderName name) noexcept
{
return FolderMakeHelper(path, parent, location, name);
}
FolderPointer SHFileSystem::FolderMakeHelper(FolderPath path, FolderLocation parent, FolderHandle location,
FolderName name) noexcept
{
folders[location] = std::make_unique<SHFolder>(location, name);
folders[location]->path = path;
folders[parent]->subFolders.push_back(folders[location].get());
return folders[location].get();
}
} }

View File

@ -1,70 +1,28 @@
/******************************************************************************
* \file SHFileSystem.h
* \author Loh Xiao Qi
* \date 28 October 2022
* \brief
*
* \copyright Copyright (c) 2021 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 #pragma once
#include <string> #include "SHFolder.h"
#include <vector>
#include <memory>
#include <unordered_map> #include <unordered_map>
namespace SHADE namespace SHADE
{ {
class SHFolder;
typedef unsigned char FolderCounter;
typedef unsigned char FileCounter;
typedef uint64_t FolderLocation;
typedef uint64_t FolderHandle;
typedef std::string FolderName;
typedef std::string FileName;
typedef std::string FolderPath;
typedef std::string FilePath;
typedef std::string FileExt;
typedef SHFolder* FolderPointer;
constexpr char FOLDER_BIT_ALLOCATE{ 4 };
constexpr char FOLDER_MAX_DEPTH{ 16 };
struct SHFile
{
FileName name;
FilePath path;
FileExt ext;
};
class SHFolder
{
public:
SHFolder(FolderHandle id, FolderName name);
FolderHandle id;
FolderName name;
std::vector<FolderPointer> subFolders;
std::vector<SHFile> files;
bool folded;
private:
FolderPath path;
friend class SHFileSystem;
};
class SHFileSystem class SHFileSystem
{ {
public: public:
static FolderLocation CreateNewFolderHere(FolderName name, FolderLocation here = 0) noexcept; static void BuildDirectory(FolderPath path, FolderPointer& root, std::unordered_map<AssetID, SHAsset>& assetCollection) noexcept;
static bool DeleteFolder(FolderPointer location) noexcept;
static void StartupFillDirectories(FolderPath path) noexcept;
static FolderPointer GetRoot() noexcept;
private: private:
static FolderPointer root; static bool DeleteFolder(FolderPointer location) noexcept;
static std::unordered_map<FolderLocation, std::unique_ptr<SHFolder>> folders;
static FolderPointer CreateFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept;
static FolderPointer RegisterFolder(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept;
static FolderPointer FolderMakeHelper(FolderPath path, FolderLocation parent, FolderHandle location, FolderName name) noexcept;
}; };
} }

View File

@ -0,0 +1,38 @@
/*************************************************************************//**
* \file SHFolder.cpp
* \author Loh Xiao Qi
* \date 30 October 2022
* \brief
*
* 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.
*****************************************************************************/
#include "SHpch.h"
#include "SHFolder.h"
namespace SHADE
{
SHFolder::SHFolder(FolderName name)
:name{ name }, subFolders(0), folded{ false }, path{ "" }
{
}
FolderPointer SHFolder::CreateSubFolderHere(FolderName name)
{
for (auto const& folder : subFolders)
{
if (name == folder->name)
{
SHLOG_ERROR("Unable to create subfolder {} at {} as it already exists", name, folder->name);
return nullptr;
}
}
auto result = new SHFolder(name);
result->path = path + "/" + name;
subFolders.push_back(result);
return result;
}
}

View File

@ -0,0 +1,52 @@
/******************************************************************************
* \file SHFolder.h
* \author Loh Xiao Qi
* \date 28 October 2022
* \brief
*
* \copyright Copyright (c) 2021 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 <vector>
#include "Assets/SHAsset.h"
namespace SHADE
{
class SHFolder;
typedef unsigned char FolderCounter;
typedef unsigned char FileCounter;
typedef std::string FolderName;
typedef std::string FileName;
typedef std::string FolderPath;
typedef std::string FilePath;
typedef std::string FileExt;
typedef SHFolder* FolderPointer;
struct SHFile
{
FileName name;
FilePath path;
FileExt ext;
SHAsset const* assetMeta;
};
class SHFolder
{
public:
SHFolder(FolderName name);
FolderName name;
std::vector<FolderPointer> subFolders;
std::vector<SHFile> files;
bool folded;
FolderPointer CreateSubFolderHere(FolderName name);
FolderPath path;
};
}

View File

@ -194,7 +194,7 @@ namespace SHADE
/* Properties */ /* Properties */
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/// <summary> /// <summary>
/// Total number of ColliderBounds in the Collider component. /// Total number of ColliderShapes in the Collider component.
/// </summary> /// </summary>
property int CollisionShapeCount property int CollisionShapeCount
{ {

View File

@ -28,7 +28,7 @@ public class PhysicsTest : Script
Debug.LogError("Collider is NULL!"); Debug.LogError("Collider is NULL!");
} }
var subColider = Collider.ColliderBoundsCount; var subColider = Collider.CollisionShapeCount;
Debug.Log($"There are {subColider} colliders."); Debug.Log($"There are {subColider} colliders.");
} }
protected override void update() protected override void update()