Merge remote-tracking branch 'origin/main' into SP3-16-Math

This commit is contained in:
Diren D Bharwani 2022-11-02 00:22:36 +08:00
commit 07bfb2f485
63 changed files with 16103 additions and 372 deletions

View File

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

View File

@ -151,19 +151,23 @@ namespace SHADE
****************************************************************************/
AssetID SHAssetManager::CreateNewAsset(AssetType type, AssetName name) noexcept
{
SHAssetData* data = nullptr;
std::string newPath{ ASSET_ROOT };
switch (type)
{
case AssetType::PREFAB:
newPath += PREFAB_FOLDER;
data = new SHPrefabAsset();
break;
case AssetType::SCENE:
newPath += SCENE_FOLDER;
data = new SHSceneAsset();
break;
case AssetType::MATERIAL:
newPath += MATERIAL_FOLDER;
data = new SHMaterialAsset();
break;
default:
@ -189,6 +193,8 @@ namespace SHADE
)
});
assetData.emplace(id, data);
return id;
}

View File

@ -33,18 +33,18 @@ namespace SHADE
return;
}
std::vector<SHComponentRemovedEvent> eventVec;
for (uint32_t i = 0; i < componentSet.Size(); ++i)
{
SHComponent* comp = (SHComponent*) componentSet.GetElement(i, EntityHandleGenerator::GetIndex(entityID));
if (comp)
{
comp->OnDestroy();
SHComponentRemovedEvent eventData;
eventData.eid = entityID;
eventData.removedComponentType = i;
SHEventManager::BroadcastEvent<SHComponentRemovedEvent>(eventData, SH_COMPONENT_REMOVED_EVENT);
eventVec.push_back(eventData);
}
}
@ -57,6 +57,12 @@ namespace SHADE
componentSet.RemoveElements(EntityHandleGenerator::GetIndex(entityID));
for (auto& eventData : eventVec)
{
SHEventManager::BroadcastEvent<SHComponentRemovedEvent>(eventData, SH_COMPONENT_REMOVED_EVENT);
}
//entityHandle.RemoveHandle(entityID);

View File

@ -29,7 +29,7 @@ namespace SHADE
{
system.second->Init();
#ifdef _DEBUG
std::cout << system.first << " Init" << std::endl;
SHLOG_INFO("Initialising System {}...", system.first)
#endif
}
}

View File

@ -195,18 +195,22 @@ namespace SHADE
if (SHDragDrop::BeginSource())
{
std::string moveLabel = "Moving EID: ";
static std::vector<EntityID> draggingEntities = editor->selectedEntities;
if (!isSelected)
editor->selectedEntities.push_back(eid);
for (int i = 0; i < static_cast<int>(editor->selectedEntities.size()); ++i)
{
moveLabel.append(std::to_string(editor->selectedEntities[i]));
if (i + 1 < static_cast<int>(editor->selectedEntities.size()))
draggingEntities.clear();
draggingEntities.push_back(eid);
}
for (int i = 0; i < static_cast<int>(draggingEntities.size()); ++i)
{
moveLabel.append(std::to_string(draggingEntities[i]));
if (i + 1 < static_cast<int>(draggingEntities.size()))
{
moveLabel.append(", ");
}
}
ImGui::Text(moveLabel.c_str());
SHDragDrop::SetPayload<std::vector<EntityID>>(SHDragDrop::DRAG_EID, &editor->selectedEntities);
SHDragDrop::SetPayload<std::vector<EntityID>>(SHDragDrop::DRAG_EID, &draggingEntities);
SHDragDrop::EndSource();
}
else if (SHDragDrop::BeginTarget()) //If Received DragDrop

View File

@ -274,8 +274,27 @@ namespace SHADE
}
{
SHEditorWidgets::BeginPanel("Offset", { ImGui::GetContentRegionAvail().x, 30.0f });
SHEditorWidgets::BeginPanel("Offsets",{ ImGui::GetContentRegionAvail().x, 30.0f });
SHEditorWidgets::DragVec3("Position", { "X", "Y", "Z" }, [&collider] {return collider->GetPositionOffset(); }, [&collider](SHVec3 const& vec) {collider->SetPositionOffset(vec); });
SHEditorWidgets::DragVec3("Rotation", { "X", "Y", "Z" },
[&collider]
{
auto offset = collider->GetRotationOffset();
offset.x = SHMath::RadiansToDegrees(offset.x);
offset.y = SHMath::RadiansToDegrees(offset.y);
offset.z = SHMath::RadiansToDegrees(offset.z);
return offset;
},
[&collider](SHVec3 const& vec)
{
const SHVec3 vecInRad
{
SHMath::DegreesToRadians(vec.x)
, SHMath::DegreesToRadians(vec.y)
, SHMath::DegreesToRadians(vec.z)
};
collider->SetRotationOffset(vecInRad);
});
SHEditorWidgets::EndPanel();
}
if (ImGui::Button(std::format("{} Remove Collider #{}", ICON_MD_REMOVE, i).data()))
@ -358,6 +377,7 @@ namespace SHADE
[component](AssetID const& id)
{
component->SetMesh(SHResourceManager::LoadOrGet<SHMesh>(id));
SHResourceManager::FinaliseChanges();
}, SHDragDrop::DRAG_RESOURCE);
}
else

View File

@ -175,19 +175,37 @@ namespace SHADE
ImGui::BeginDisabled(editor->editorState == SHEditor::State::PLAY);
if(ImGui::SmallButton(ICON_MD_PLAY_ARROW))
{
const SHEditorStateChangeEvent STATE_CHANGE_EVENT
{
.previousState = editor->editorState
};
editor->editorState = SHEditor::State::PLAY;
SHEventManager::BroadcastEvent<SHEditorStateChangeEvent>(STATE_CHANGE_EVENT, SH_EDITOR_ON_PLAY_EVENT);
}
ImGui::EndDisabled();
ImGui::BeginDisabled(editor->editorState == SHEditor::State::PAUSE);
if(ImGui::SmallButton(ICON_MD_PAUSE))
{
const SHEditorStateChangeEvent STATE_CHANGE_EVENT
{
.previousState = editor->editorState
};
editor->editorState = SHEditor::State::PAUSE;
SHEventManager::BroadcastEvent<SHEditorStateChangeEvent>(STATE_CHANGE_EVENT, SH_EDITOR_ON_PAUSE_EVENT);
}
ImGui::EndDisabled();
ImGui::BeginDisabled(editor->editorState == SHEditor::State::STOP);
if(ImGui::SmallButton(ICON_MD_STOP))
{
const SHEditorStateChangeEvent STATE_CHANGE_EVENT
{
.previousState = editor->editorState
};
editor->editorState = SHEditor::State::STOP;
SHEventManager::BroadcastEvent<SHEditorStateChangeEvent>(STATE_CHANGE_EVENT, SH_EDITOR_ON_STOP_EVENT);
}
ImGui::EndDisabled();
ImGui::EndMenuBar();

View File

@ -20,4 +20,10 @@ namespace SHADE
float menuBarHeight = 20.0f;
std::vector<std::filesystem::path> layoutPaths;
};//class SHEditorMenuBar
struct SHEditorStateChangeEvent
{
SHEditor::State previousState;
};
}//namespace SHADE

View File

@ -16,6 +16,7 @@ of DigiPen Institute of Technology is prohibited.
// External Dependencies
#include <imgui.h>
#include "SHEditorWidgets.hpp"
#include "ECS_Base/Managers/SHEntityManager.h"
namespace SHADE
{
@ -287,6 +288,35 @@ namespace SHADE
return CHANGED;
}
bool SHEditorUI::InputGameObjectField(const std::string& label, uint32_t& value, bool* isHovered)
{
ImGui::Text(label.c_str());
if (isHovered)
*isHovered = ImGui::IsItemHovered();
ImGui::SameLine();
SHEntity* entity = SHEntityManager::GetEntityByID(value);
std::ostringstream oss;
if (entity)
{
oss << value << ": " << entity->name;
}
std::string entityName = oss.str();
bool changed = ImGui::InputText("##", &entityName, ImGuiInputTextFlags_ReadOnly);
if (SHDragDrop::BeginTarget())
{
if (const std::vector<EntityID>* payload = SHDragDrop::AcceptPayload<std::vector<EntityID>>(SHDragDrop::DRAG_EID))
{
if (!payload->empty())
{
value = payload->at(0);
changed = true;
}
SHDragDrop::EndTarget();
}
}
return changed;
}
bool SHEditorUI::InputEnumCombo(const std::string& label, int& v, const std::vector<std::string>& enumNames, bool* isHovered)
{
// Clamp input value

View File

@ -308,6 +308,14 @@ namespace SHADE
/// <returns>True if the value was changed.</returns>
static bool InputTextField(const std::string& label, std::string& value, bool* isHovered = nullptr);
/// <summary>
/// Creates a drag field widget for int input.
/// </summary>
/// <param name="label">Label used to identify this widget.</param>
/// <param name="value">Reference to the variable to store the result.</param>
/// <param name="isHovered>If set, stores the hover state of this widget.</param>
/// <returns>True if the value was changed.</returns>
static bool InputGameObjectField(const std::string& label, uint32_t& value, bool* isHovered = nullptr);
/// <summary>
/// Creates a combo box for enumeration input.
/// </summary>
/// <typeparam name="Enum">The type of enum to input.</typeparam>

View File

@ -13,4 +13,7 @@ constexpr SHEventIdentifier SH_COMPONENT_REMOVED_EVENT { 4 };
constexpr SHEventIdentifier SH_SCENEGRAPH_CHANGE_PARENT_EVENT { 5 };
constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_ADDED_EVENT { 6 };
constexpr SHEventIdentifier SH_PHYSICS_COLLIDER_REMOVED_EVENT { 7 };
constexpr SHEventIdentifier SH_EDITOR_ON_PLAY_EVENT { 8 };
constexpr SHEventIdentifier SH_EDITOR_ON_PAUSE_EVENT { 9 };
constexpr SHEventIdentifier SH_EDITOR_ON_STOP_EVENT { 10 };

View File

@ -74,11 +74,12 @@ namespace SHADE
void SHBatch::Remove(const SHRenderable* renderable)
{
// Check if we have a SubBatch with the same mesh yet
// Check if we have a SubBatch with the existing mesh yet (if changed, we use the old mesh)
Handle<SHMesh> prevSubBatchMesh = renderable->HasMeshChanged() ? renderable->GetPrevMesh() : renderable->GetMesh();
auto subBatch = std::find_if(subBatches.begin(), subBatches.end(), [&](const SHSubBatch& batch)
{
return batch.Mesh == renderable->GetMesh();
});
{
return batch.Mesh == prevSubBatchMesh;
});
// Attempt to remove if it exists
if (subBatch == subBatches.end())
@ -88,9 +89,7 @@ namespace SHADE
// Check if other renderables in subBatches contain the same material instance
bool matUnused = true;
Handle<SHMaterialInstance> matToCheck = renderable->HasMaterialChanged() ? renderable->GetPrevMaterial() : renderable->GetMaterial();
for (const auto& sb : subBatches)
{
// Check material usage

View File

@ -37,9 +37,9 @@ namespace SHADE
// Check if we have a batch with the same pipeline first
auto batch = std::find_if(batches.begin(), batches.end(), [&](const SHBatch& batch)
{
return batch.GetPipeline() == PIPELINE;
});
{
return batch.GetPipeline() == PIPELINE;
});
// Create one if not found

View File

@ -106,10 +106,7 @@ namespace SHADE
descPool = device->CreateDescriptorPools();
// Create generic command buffer
//transferCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
graphicsCmdPool = device->CreateCommandPool(SH_QUEUE_FAMILY_ARRAY_INDEX::GRAPHICS, SH_CMD_POOL_RESET::POOL_BASED, true);
transferCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
// Load Built In Shaders
static constexpr AssetID VS_DEFAULT = 39210065; defaultVertShader = SHResourceManager::LoadOrGet<SHVkShaderModule>(VS_DEFAULT);
@ -621,10 +618,14 @@ namespace SHADE
void SHGraphicsSystem::BuildMeshBuffers()
{
transferCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
device->WaitIdle();
transferCmdBuffer->BeginRecording();
meshLibrary.BuildBuffers(device, transferCmdBuffer);
transferCmdBuffer->EndRecording();
graphicsQueue->SubmitCommandBuffer({ transferCmdBuffer });
device->WaitIdle();
transferCmdBuffer.Free(); transferCmdBuffer = {};
}
/*---------------------------------------------------------------------------------*/
@ -649,10 +650,14 @@ namespace SHADE
void SHGraphicsSystem::BuildTextures()
{
graphicsTexCmdBuffer = graphicsCmdPool->RequestCommandBuffer(SH_CMD_BUFFER_TYPE::PRIMARY);
device->WaitIdle();
texLibrary.BuildTextures
(
device, graphicsTexCmdBuffer, graphicsQueue, descPool
);
device->WaitIdle();
graphicsTexCmdBuffer.Free(); graphicsTexCmdBuffer = {};
}
#pragma endregion ADD_REMOVE
@ -692,6 +697,7 @@ namespace SHADE
void SHGraphicsSystem::EndRoutine::Execute(double) noexcept
{
reinterpret_cast<SHGraphicsSystem*>(system)->EndRender();
SHResourceManager::FinaliseChanges();
}
/*-----------------------------------------------------------------------------------*/
@ -709,8 +715,13 @@ namespace SHADE
if (!renderable.HasChanged())
continue;
// Remove from old material's SuperBatch
Handle<SHMaterialInstance> prevMaterial = renderable.GetPrevMaterial();
if (!renderable.GetMesh())
{
SHLOG_CRITICAL("NULL Mesh provided!");
}
// Remove from the SuperBatch it is previously in (prevMat if mat has changed)
Handle<SHMaterialInstance> prevMaterial = renderable.HasMaterialChanged() ? renderable.GetPrevMaterial() : renderable.GetMaterial();
if (prevMaterial)
{
Handle<SHSuperBatch> oldSuperBatch = prevMaterial->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch();

View File

@ -185,7 +185,7 @@ RTTR_REGISTRATION
using namespace rttr;
registration::class_<SHTransformComponent>("Transform Component")
.property("Translate" ,&SHTransformComponent::GetLocalPosition ,&SHTransformComponent::SetLocalPosition ) (metadata(META::tooltip, "Translate"))
.property("Rotate" ,&SHTransformComponent::GetLocalRotation ,select_overload<void(const SHVec3&)>(&SHTransformComponent::SetLocalRotation) ) (metadata(META::tooltip, "Rotate"), metadata(META::angleInRad, true))
.property("Scale" ,&SHTransformComponent::GetLocalScale ,&SHTransformComponent::SetLocalScale ) (metadata(META::tooltip, "Scale"));
.property("Translate" ,&SHTransformComponent::GetLocalPosition ,&SHTransformComponent::SetLocalPosition ) (metadata(META::tooltip, "Translate"))
.property("Rotate" ,&SHTransformComponent::GetLocalRotation ,select_overload<void(const SHVec3&)>(&SHTransformComponent::SetLocalRotation)) (metadata(META::tooltip, "Rotate"), metadata(META::angleInRad, true))
.property("Scale" ,&SHTransformComponent::GetLocalScale ,&SHTransformComponent::SetLocalScale ) (metadata(META::tooltip, "Scale"));
}

View File

@ -18,6 +18,7 @@
// Project Headers
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Math/SHMathHelpers.h"
#include "Physics/SHPhysicsSystem.h"
namespace SHADE
@ -28,21 +29,9 @@ namespace SHADE
SHRigidBodyComponent::SHRigidBodyComponent() noexcept
: type { Type::DYNAMIC }
, flags { 0 }
, dirtyFlags { 0 }
, interpolate { true }
, rp3dBody { nullptr }
, mass { 1.0f }
, drag { 0.01f }
, angularDrag { 0.01f }
{
// Set default flags: Gravity & Sleeping enabled
flags |= 1U << 0;
flags |= 1U << 1;
// Set all dirty flags to true
dirtyFlags = 1023;
}
{}
/*-----------------------------------------------------------------------------------*/
/* Getter Function Definitions */
@ -50,12 +39,24 @@ namespace SHADE
bool SHRigidBodyComponent::IsGravityEnabled() const noexcept
{
return flags & (1U << 0);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
return rp3dBody->isGravityEnabled();
}
bool SHRigidBodyComponent::IsAllowedToSleep() const noexcept
{
return flags & (1U << 1);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
return rp3dBody->isAllowedToSleep();
}
bool SHRigidBodyComponent::IsInterpolating() const noexcept
@ -70,67 +71,151 @@ namespace SHADE
float SHRigidBodyComponent::GetMass() const noexcept
{
return mass;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return 0.0f;
}
return rp3dBody->getMass();
}
float SHRigidBodyComponent::GetDrag() const noexcept
{
return drag;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return 0.0f;
}
return rp3dBody->getLinearDamping();
}
float SHRigidBodyComponent::GetAngularDrag() const noexcept
{
return angularDrag;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return 0.0f;
}
return rp3dBody->getAngularDamping();
}
bool SHRigidBodyComponent::GetFreezePositionX() const noexcept
{
return flags & (1U << 2);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& LINEAR_CONSTRAINTS = rp3dBody->getLinearLockAxisFactor();
return SHMath::CompareFloat(LINEAR_CONSTRAINTS.x, 0.0f);
}
bool SHRigidBodyComponent::GetFreezePositionY() const noexcept
{
return flags & (1U << 3);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& LINEAR_CONSTRAINTS = rp3dBody->getLinearLockAxisFactor();
return SHMath::CompareFloat(LINEAR_CONSTRAINTS.y, 0.0f);
}
bool SHRigidBodyComponent::GetFreezePositionZ() const noexcept
{
return flags & (1U << 4);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& LINEAR_CONSTRAINTS = rp3dBody->getLinearLockAxisFactor();
return SHMath::CompareFloat(LINEAR_CONSTRAINTS.z, 0.0f);
}
bool SHRigidBodyComponent::GetFreezeRotationX() const noexcept
{
return flags & (1U << 5);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& ANGULAR_CONSTRAINTS = rp3dBody->getAngularLockAxisFactor();
return SHMath::CompareFloat(ANGULAR_CONSTRAINTS.x, 0.0f);
}
bool SHRigidBodyComponent::GetFreezeRotationY() const noexcept
{
return flags & (1U << 6);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& ANGULAR_CONSTRAINTS = rp3dBody->getAngularLockAxisFactor();
return SHMath::CompareFloat(ANGULAR_CONSTRAINTS.y, 0.0f);
}
bool SHRigidBodyComponent::GetFreezeRotationZ() const noexcept
{
return flags & (1U << 7);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
const auto& ANGULAR_CONSTRAINTS = rp3dBody->getAngularLockAxisFactor();
return SHMath::CompareFloat(ANGULAR_CONSTRAINTS.z, 0.0f);
}
const SHVec3& SHRigidBodyComponent::GetForce() const noexcept
SHVec3 SHRigidBodyComponent::GetForce() const noexcept
{
return force;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return false;
}
return rp3dBody->getForce();
}
const SHVec3& SHRigidBodyComponent::GetTorque() const noexcept
SHVec3 SHRigidBodyComponent::GetTorque() const noexcept
{
return torque;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return SHVec3::Zero;
}
return rp3dBody->getTorque();
}
const SHVec3& SHRigidBodyComponent::GetLinearVelocity() const noexcept
SHVec3 SHRigidBodyComponent::GetLinearVelocity() const noexcept
{
return linearVelocity;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return SHVec3::Zero;
}
return rp3dBody->getLinearVelocity();
}
const SHVec3& SHRigidBodyComponent::GetAngularVelocity() const noexcept
SHVec3 SHRigidBodyComponent::GetAngularVelocity() const noexcept
{
return angularVelocity;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return SHVec3::Zero;
}
return rp3dBody->getAngularVelocity();
}
const SHVec3& SHRigidBodyComponent::GetPosition() const noexcept
@ -157,8 +242,15 @@ namespace SHADE
if (type == newType)
return;
dirtyFlags |= 1U << 4;
type = newType;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setType(static_cast<rp3d::BodyType>(type));
}
void SHRigidBodyComponent::SetGravityEnabled(bool enableGravity) noexcept
@ -171,8 +263,13 @@ namespace SHADE
return;
}
dirtyFlags |= 1U << FLAG_POS;
enableGravity ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->enableGravity(enableGravity);
}
void SHRigidBodyComponent::SetIsAllowedToSleep(bool isAllowedToSleep) noexcept
@ -185,92 +282,127 @@ namespace SHADE
return;
}
dirtyFlags |= 1U << 1;
isAllowedToSleep ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setIsAllowedToSleep(isAllowedToSleep);
}
void SHRigidBodyComponent::SetFreezePositionX(bool freezePositionX) noexcept
{
static constexpr int FLAG_POS = 2;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 2;
freezePositionX ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto linearConstraints = rp3dBody->getLinearLockAxisFactor();
linearConstraints.x = freezePositionX ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(linearConstraints);
}
void SHRigidBodyComponent::SetFreezePositionY(bool freezePositionY) noexcept
{
static constexpr int FLAG_POS = 3;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 2;
freezePositionY ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto linearConstraints = rp3dBody->getLinearLockAxisFactor();
linearConstraints.y = freezePositionY ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(linearConstraints);
}
void SHRigidBodyComponent::SetFreezePositionZ(bool freezePositionZ) noexcept
{
static constexpr int FLAG_POS = 4;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set linear constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 2;
freezePositionZ ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto linearConstraints = rp3dBody->getLinearLockAxisFactor();
linearConstraints.z = freezePositionZ ? 0.0f : 1.0f;
rp3dBody->setLinearLockAxisFactor(linearConstraints);
}
void SHRigidBodyComponent::SetFreezeRotationX(bool freezeRotationX) noexcept
{
static constexpr int FLAG_POS = 5;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 3;
freezeRotationX ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto angularConstraints = rp3dBody->getAngularLockAxisFactor();
angularConstraints.x = freezeRotationX ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(angularConstraints);
}
void SHRigidBodyComponent::SetFreezeRotationY(bool freezeRotationY) noexcept
{
static constexpr int FLAG_POS = 6;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 3;
freezeRotationY ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto angularConstraints = rp3dBody->getAngularLockAxisFactor();
angularConstraints.y = freezeRotationY ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(angularConstraints);
}
void SHRigidBodyComponent::SetFreezeRotationZ(bool freezeRotationZ) noexcept
{
static constexpr int FLAG_POS = 7;
if (type == Type::STATIC)
{
SHLOG_WARNING("Cannot set angular constraints of a static object {}", GetEID())
return;
}
dirtyFlags |= 1U << 3;
freezeRotationZ ? flags |= (1U << FLAG_POS) : flags &= ~(1U << FLAG_POS);
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
auto angularConstraints = rp3dBody->getAngularLockAxisFactor();
angularConstraints.z = freezeRotationZ ? 0.0f : 1.0f;
rp3dBody->setAngularLockAxisFactor(angularConstraints);
}
void SHRigidBodyComponent::SetInterpolate(bool allowInterpolation) noexcept
@ -283,11 +415,16 @@ namespace SHADE
if (type != Type::DYNAMIC)
{
SHLOG_WARNING("Cannot set mass of a non-dynamic object {}", GetEID())
return;
return;
}
dirtyFlags |= 1U << 5;
mass = newMass;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setMass(newMass);
}
void SHRigidBodyComponent::SetDrag(float newDrag) noexcept
@ -298,8 +435,13 @@ namespace SHADE
return;
}
dirtyFlags |= 1U << 6;
drag = newDrag;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setLinearDamping(newDrag);
}
void SHRigidBodyComponent::SetAngularDrag(float newAngularDrag) noexcept
@ -310,8 +452,13 @@ namespace SHADE
return;
}
dirtyFlags |= 1U << 7;
angularDrag = newAngularDrag;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setLinearDamping(newAngularDrag);
}
void SHRigidBodyComponent::SetLinearVelocity(const SHVec3& newLinearVelocity) noexcept
@ -322,8 +469,13 @@ namespace SHADE
return;
}
dirtyFlags |= 1U << 8;
linearVelocity = newLinearVelocity;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setLinearVelocity(newLinearVelocity);
}
void SHRigidBodyComponent::SetAngularVelocity(const SHVec3& newAngularVelocity) noexcept
@ -334,8 +486,13 @@ namespace SHADE
return;
}
dirtyFlags |= 1U << 9;
angularVelocity = newAngularVelocity;
if (rp3dBody == nullptr)
{
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
rp3dBody->setAngularVelocity(newAngularVelocity);
}
/*-----------------------------------------------------------------------------------*/
@ -346,7 +503,7 @@ namespace SHADE
{
if (rp3dBody == nullptr)
{
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
@ -357,7 +514,7 @@ namespace SHADE
{
if (rp3dBody == nullptr)
{
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
@ -368,7 +525,7 @@ namespace SHADE
{
if (rp3dBody == nullptr)
{
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
@ -379,7 +536,7 @@ namespace SHADE
{
if (rp3dBody == nullptr)
{
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
@ -390,7 +547,7 @@ namespace SHADE
{
if (rp3dBody == nullptr)
{
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
@ -401,7 +558,7 @@ namespace SHADE
{
if (rp3dBody == nullptr)
{
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
@ -412,7 +569,7 @@ namespace SHADE
{
if (rp3dBody == nullptr)
{
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}
@ -423,7 +580,7 @@ namespace SHADE
{
if (rp3dBody == nullptr)
{
SHLOGV_ERROR("Entity {} is missing an rp3dBody!", GetEID())
SHLOG_ERROR("Missing rp3dBody from Entity {}", GetEID())
return;
}

View File

@ -94,10 +94,10 @@ namespace SHADE
[[nodiscard]] bool GetFreezeRotationY () const noexcept;
[[nodiscard]] bool GetFreezeRotationZ () const noexcept;
[[nodiscard]] const SHVec3& GetForce () const noexcept;
[[nodiscard]] const SHVec3& GetTorque () const noexcept;
[[nodiscard]] const SHVec3& GetLinearVelocity () const noexcept;
[[nodiscard]] const SHVec3& GetAngularVelocity () const noexcept;
[[nodiscard]] SHVec3 GetForce () const noexcept;
[[nodiscard]] SHVec3 GetTorque () const noexcept;
[[nodiscard]] SHVec3 GetLinearVelocity () const noexcept;
[[nodiscard]] SHVec3 GetAngularVelocity () const noexcept;
[[nodiscard]] const SHVec3& GetPosition () const noexcept;
[[nodiscard]] const SHQuaternion& GetOrientation () const noexcept;
@ -149,28 +149,13 @@ namespace SHADE
static constexpr size_t NUM_FLAGS = 8;
static constexpr size_t NUM_DIRTY_FLAGS = 16;
Type type;
// rX rY rZ pX pY pZ slp g
uint8_t flags;
// 0 0 0 0 0 0 aV lV aD d m t ag lc slp g
uint16_t dirtyFlags;
bool interpolate;
Type type;
bool interpolate;
reactphysics3d::RigidBody* rp3dBody;
float mass;
float drag;
float angularDrag;
SHVec3 force;
SHVec3 linearVelocity;
SHVec3 torque;
SHVec3 angularVelocity;
SHVec3 position;
SHQuaternion orientation;
SHVec3 position;
SHQuaternion orientation;
RTTR_ENABLE()
};

View File

@ -17,6 +17,7 @@
#include "Math/Geometry/SHBoundingSphere.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Math/SHMathHelpers.h"
#include "Reflection/SHReflectionMetadata.h"
namespace SHADE
{
@ -158,6 +159,11 @@ namespace SHADE
return positionOffset;
}
const SHVec3& SHCollider::GetRotationOffset() const noexcept
{
return rotationOffset;
}
SHShape* SHCollider::GetShape() noexcept
{
dirty = true;
@ -275,6 +281,12 @@ namespace SHADE
}
}
void SHCollider::SetRotationOffset(const SHVec3& rotOffset) noexcept
{
dirty = true;
rotationOffset = rotOffset;
}
/*-----------------------------------------------------------------------------------*/
/* Private Function Member Definitions */
/*-----------------------------------------------------------------------------------*/
@ -316,5 +328,6 @@ RTTR_REGISTRATION
);
registration::class_<SHCollider>("Collider")
.property("Position Offset", &SHCollider::GetPositionOffset, &SHCollider::SetPositionOffset);
.property("Position Offset", &SHCollider::GetPositionOffset, &SHCollider::SetPositionOffset)
.property("Rotation Offset", &SHCollider::GetRotationOffset, &SHCollider::SetRotationOffset) (metadata(META::angleInRad, true));
}

View File

@ -80,6 +80,7 @@ namespace SHADE
[[nodiscard]] const SHPhysicsMaterial& GetMaterial () const noexcept;
[[nodiscard]] const SHVec3& GetPositionOffset () const noexcept;
[[nodiscard]] const SHVec3& GetRotationOffset () const noexcept;
[[nodiscard]] SHShape* GetShape () noexcept;
@ -96,7 +97,8 @@ namespace SHADE
void SetDensity (float density) noexcept;
void SetMaterial (const SHPhysicsMaterial& newMaterial) noexcept;
void SetPositionOffset (const SHVec3& posOffset) noexcept;
void SetPositionOffset (const SHVec3& posOffset) noexcept;
void SetRotationOffset (const SHVec3& rotOffset) noexcept;
private:
/*---------------------------------------------------------------------------------*/
@ -110,6 +112,7 @@ namespace SHADE
SHShape* shape;
SHPhysicsMaterial material;
SHVec3 positionOffset;
SHVec3 rotationOffset;
/*---------------------------------------------------------------------------------*/
/* Function Members */

View File

@ -130,6 +130,8 @@ namespace SHADE
int SHPhysicsObject::AddCollider(SHCollider* collider)
{
const rp3d::Transform OFFSETS{ collider->GetPositionOffset(), collider->GetRotationOffset() };
switch (collider->GetType())
{
case SHCollider::Type::BOX:
@ -137,7 +139,7 @@ namespace SHADE
const auto* box = reinterpret_cast<SHBoundingBox*>(collider->GetShape());
rp3d::BoxShape* newBox = factory->createBoxShape(box->GetHalfExtents());
rp3dBody->addCollider(newBox, rp3d::Transform{ collider->GetPositionOffset(), SHQuaternion::Identity });
rp3dBody->addCollider(newBox, OFFSETS);
break;
}
case SHCollider::Type::SPHERE:
@ -145,7 +147,7 @@ namespace SHADE
const auto* sphere = reinterpret_cast<SHBoundingSphere*>(collider->GetShape());
rp3d::SphereShape* newSphere = factory->createSphereShape(sphere->GetRadius());
rp3dBody->addCollider(newSphere, rp3d::Transform{ collider->GetPositionOffset(), SHQuaternion::Identity });
rp3dBody->addCollider(newSphere, OFFSETS);
break;
}
// TODO(Diren): Add more collider shapes
@ -168,100 +170,6 @@ namespace SHADE
rp3dBody->removeCollider(collider);
}
void SHPhysicsObject::SyncRigidBody(SHRigidBodyComponent* rb) const noexcept
{
SHASSERT(rp3dBody != nullptr, "ReactPhysics body does not exist!")
auto* rigidBody = reinterpret_cast<rp3d::RigidBody*>(rp3dBody);
if (rb->dirtyFlags != 0)
{
const uint16_t RB_FLAGS = rb->dirtyFlags;
for (size_t i = 0; i < SHRigidBodyComponent::NUM_DIRTY_FLAGS; ++i)
{
// Check if current dirty flag has been set to true
if (RB_FLAGS & 1U << i)
{
switch (i)
{
case 0: // Gravity
{
rigidBody->enableGravity(rb->IsGravityEnabled());
break;
}
case 1: // Sleeping
{
rigidBody->setIsAllowedToSleep(rb->IsAllowedToSleep());
break;
}
case 2: // Linear Constraints
{
const rp3d::Vector3 CONSTRAINTS
{
rb->flags & 1U << 2 ? 0.0f : 1.0f,
rb->flags & 1U << 3 ? 0.0f : 1.0f,
rb->flags & 1U << 4 ? 0.0f : 1.0f
};
rigidBody->setLinearLockAxisFactor(CONSTRAINTS);
break;
}
case 3: // Angular Constraints
{
const rp3d::Vector3 CONSTRAINTS
{
rb->flags & 1U << 5 ? 0.0f : 1.0f,
rb->flags & 1U << 6 ? 0.0f : 1.0f,
rb->flags & 1U << 7 ? 0.0f : 1.0f
};
rigidBody->setAngularLockAxisFactor(CONSTRAINTS);
break;
}
case 4: // Type
{
rigidBody->setType(static_cast<rp3d::BodyType>(rb->GetType()));
break;
}
case 5: // Mass
{
rigidBody->setMass(rb->GetMass());
break;
}
case 6: // Drag
{
rigidBody->setLinearDamping(rb->GetDrag());
break;
}
case 7: // Angular Drag
{
rigidBody->setAngularDamping(rb->GetAngularDrag());
break;
}
case 8: // Linear Velocity
{
rigidBody->setLinearVelocity(rb->GetLinearVelocity());
break;
}
case 9: // Angular Velocity
{
rigidBody->setAngularVelocity(rb->GetAngularVelocity());
break;
}
default: break;
}
}
}
rb->dirtyFlags = 0;
}
else
{
rb->linearVelocity = rigidBody->getLinearVelocity();
rb->angularVelocity = rigidBody->getAngularVelocity();
}
}
void SHPhysicsObject::SyncColliders(SHColliderComponent* c) const noexcept
{
int index = 0;
@ -276,7 +184,7 @@ namespace SHADE
rp3dCollider->setIsTrigger(collider.IsTrigger());
// Update offsets
rp3dCollider->setLocalToBodyTransform(rp3d::Transform(collider.GetPositionOffset(), SHQuaternion::Identity));
rp3dCollider->setLocalToBodyTransform(rp3d::Transform(collider.GetPositionOffset(), collider.GetRotationOffset()));
switch (collider.GetType())
{

View File

@ -72,7 +72,6 @@ namespace SHADE
int AddCollider (SHCollider* collider);
void RemoveCollider (int index);
void SyncRigidBody (SHRigidBodyComponent* rb) const noexcept;
void SyncColliders (SHColliderComponent* c) const noexcept;
private:

View File

@ -17,7 +17,6 @@
#include "ECS_Base/Managers/SHComponentManager.h"
#include "ECS_Base/Managers/SHEntityManager.h"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Editor/SHEditor.h"
#include "Math/SHMathHelpers.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Scene/SHSceneManager.h"
@ -212,6 +211,12 @@ namespace SHADE
const std::shared_ptr REMOVE_COMPONENT_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::RemovePhysicsComponent) };
const ReceiverPtr REMOVE_COMPONENT_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(REMOVE_COMPONENT_RECEIVER);
SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, REMOVE_COMPONENT_RECEIVER_PTR);
#ifdef SHEDITOR
const std::shared_ptr EDITOR_STOP_RECEIVER { std::make_shared<SHEventReceiverSpec<SHPhysicsSystem>>(this, &SHPhysicsSystem::ResetWorld) };
const ReceiverPtr EDITOR_STOP_RECEIVER_PTR = std::dynamic_pointer_cast<SHEventReceiver>(EDITOR_STOP_RECEIVER);
SHEventManager::SubscribeTo(SH_EDITOR_ON_STOP_EVENT, EDITOR_STOP_RECEIVER_PTR);
#endif
}
void SHPhysicsSystem::Exit()
@ -289,24 +294,12 @@ namespace SHADE
if (rigidBodyComponent)
{
// Clear all forces and velocities if editor is stopped
if (SHSystemManager::GetSystem<SHEditor>()->editorState == SHEditor::State::STOP)
{
auto* rp3dRigidBody = reinterpret_cast<rp3d::RigidBody*>(physicsObject.rp3dBody);
rp3dRigidBody->resetForce();
rp3dRigidBody->resetTorque();
rp3dRigidBody->setLinearVelocity(SHVec3::Zero);
rp3dRigidBody->setAngularVelocity(SHVec3::Zero);
}
// Sync active states
const bool COMPONENT_ACTIVE = rigidBodyComponent->isActive;
SyncActiveStates(physicsObject, COMPONENT_ACTIVE);
if (!COMPONENT_ACTIVE)
continue;
physicsObject.SyncRigidBody(rigidBodyComponent);
}
// Sync colliders
@ -326,7 +319,12 @@ namespace SHADE
void SHPhysicsSystem::PhysicsFixedUpdate::Execute(double dt) noexcept
{
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_WARNING("Unable to invoke FixedUpdate() on scripts due to missing SHScriptEngine!");
}
fixedTimeStep = 1.0 / physicsSystem->fixedDT;
accumulatedTime += dt;
@ -334,6 +332,9 @@ namespace SHADE
int count = 0;
while (accumulatedTime > fixedTimeStep)
{
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteFixedUpdates();
physicsSystem->world->update(static_cast<rp3d::decimal>(fixedTimeStep));
accumulatedTime -= fixedTimeStep;
@ -349,12 +350,23 @@ namespace SHADE
void SHPhysicsSystem::PhysicsPostUpdate::Execute(double) noexcept
{
auto* physicsSystem = reinterpret_cast<SHPhysicsSystem*>(GetSystem());
auto* scriptingSystem = SHSystemManager::GetSystem<SHScriptEngine>();
if (scriptingSystem == nullptr)
{
SHLOGV_WARNING("Unable to invoke collision and trigger script events due to missing SHScriptEngine!");
}
// Interpolate transforms for rendering
if (physicsSystem->worldUpdated)
{
physicsSystem->SyncTransforms();
physicsSystem->ClearInvalidCollisions();
// Collision & Trigger messages
if (scriptingSystem != nullptr)
scriptingSystem->ExecuteCollisionFunctions();
physicsSystem->ClearInvalidCollisions();
}
}
void SHPhysicsSystem::onContact(const CallbackData& callbackData)
@ -610,19 +622,17 @@ namespace SHADE
auto* rigidBodyComponent = SHComponentManager::GetComponent_s<SHRigidBodyComponent>(ENTITY_ID);
auto* colliderComponent = SHComponentManager::GetComponent_s<SHColliderComponent>(ENTITY_ID);
SHASSERT(physicsObject != nullptr, "Physics object " + std::to_string(ENTITY_ID) + " has been lost from the world!")
if (REMOVED_ID == RIGID_BODY_ID)
// Wake up all physics objects
for (auto& [entityID, object] : map)
{
// Wake up all physics objects
for (auto& [entityID, object] : map)
{
if (SHComponentManager::HasComponent<SHRigidBodyComponent>(entityID))
reinterpret_cast<rp3d::RigidBody*>(object.rp3dBody)->setIsSleeping(false);
}
if (SHComponentManager::HasComponent<SHRigidBodyComponent>(entityID))
reinterpret_cast<rp3d::RigidBody*>(object.rp3dBody)->setIsSleeping(false);
}
if (REMOVED_ID == RIGID_BODY_ID && physicsObject != nullptr)
{
world->destroyRigidBody(reinterpret_cast<rp3d::RigidBody*>(physicsObject->rp3dBody));
physicsObject->rp3dBody = nullptr;
physicsObject->rp3dBody = nullptr;
if (colliderComponent != nullptr)
{
@ -637,7 +647,7 @@ namespace SHADE
}
}
if (REMOVED_ID == COLLIDER_ID)
if (REMOVED_ID == COLLIDER_ID && physicsObject != nullptr)
{
// Remove all colliders
const int NUM_COLLIDERS = static_cast<int>(physicsObject->rp3dBody->getNbColliders());
@ -653,11 +663,30 @@ namespace SHADE
physicsObject->rp3dBody = nullptr;
}
if (physicsObject->rp3dBody == nullptr)
DestroyPhysicsObject(ENTITY_ID);
if (physicsObject != nullptr && physicsObject->rp3dBody == nullptr)
DestroyPhysicsObject(ENTITY_ID);
}
return EVENT_DATA->handle;
}
SHEventHandle SHPhysicsSystem::ResetWorld(SHEventPtr editorStopEvent)
{
// TODO(Diren): Rebuild world based on how scene reloading is done
for (auto& [entityID, physicsObject] : map)
{
if (SHComponentManager::HasComponent<SHRigidBodyComponent>(entityID))
{
auto* rp3dRigidBody = reinterpret_cast<rp3d::RigidBody*>(physicsObject.rp3dBody);
rp3dRigidBody->resetForce();
rp3dRigidBody->resetTorque();
rp3dRigidBody->setLinearVelocity(SHVec3::Zero);
rp3dRigidBody->setAngularVelocity(SHVec3::Zero);
}
}
return editorStopEvent->handle;
}
} // namespace SHADE

View File

@ -28,11 +28,6 @@
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Concepts */
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
@ -194,6 +189,7 @@ namespace SHADE
SHEventHandle AddPhysicsComponent (SHEventPtr addComponentEvent);
SHEventHandle RemovePhysicsComponent (SHEventPtr removeComponentEvent);
SHEventHandle ResetWorld (SHEventPtr editorStopEvent);
template <typename RP3DCollisionPair, typename = std::enable_if_t
<std::is_same_v<RP3DCollisionPair, rp3d::CollisionCallback::ContactPair>

View File

@ -42,6 +42,9 @@ namespace SHADE
SHCollisionEvent cInfo;
// Update collision state
cInfo.collisionState = static_cast<SHCollisionEvent::State>(cp.getEventType());
// Match body and collider for collision event
const rp3d::Entity body1 = cp.getBody1()->getEntity();
const rp3d::Entity body2 = cp.getBody2()->getEntity();
@ -76,9 +79,6 @@ namespace SHADE
return cInfo;
}
// Update collision state
cInfo.collisionState = static_cast<SHCollisionEvent::State>(cp.getEventType());
return cInfo;
}
} // namespace SHADE

View File

@ -0,0 +1,65 @@
/************************************************************************************//*!
\file SHPhysicsSystemInterface.cpp
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 31, 2022
\brief Contains the definitions of the functions of the static
SHPhysicsSystemInterface 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.
*//*************************************************************************************/
// Precompiled Headers
#include "SHpch.h"
// Primary Header
#include "SHPhysicsSystemInterface.h"
// Project Includes
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Physics/SHPhysicsSystem.h"
#include "Physics/SHPhysicsUtils.h"
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Static Usage Functions */
/*-----------------------------------------------------------------------------------*/
const std::vector<SHCollisionEvent>& SHPhysicsSystemInterface::GetCollisionInfo() noexcept
{
static std::vector<SHCollisionEvent> emptyVec;
auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (phySystem)
{
return phySystem->GetCollisionInfo();
}
SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get collision events. Empty vector returned instead.");
return emptyVec;
}
const std::vector<SHCollisionEvent>& SHPhysicsSystemInterface::GetTriggerInfo() noexcept
{
static std::vector<SHCollisionEvent> emptyVec;
auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (phySystem)
{
return phySystem->GetTriggerInfo();
}
SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get trigger events. Empty vector returned instead.");
return emptyVec;
}
double SHPhysicsSystemInterface::GetFixedDT() noexcept
{
auto phySystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
if (phySystem)
{
return phySystem->GetFixedDT();
}
SHLOG_WARNING("[SHPhysicsSystemInterface] Failed to get fixed delta time. 0.0 returned instead.");
return 0.0;
}
}

View File

@ -0,0 +1,46 @@
/************************************************************************************//*!
\file SHPhysicsSystemInterface.h
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 31, 2022
\brief Contains the definition of the SHGraphicsSystemInterface static 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.
*//*************************************************************************************/
#pragma once
// STL Includes
#include <vector>
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
/* Forward Declarations */
/*-----------------------------------------------------------------------------------*/
class SHCollisionEvent;
/*-----------------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------------*/
/// <summary>
/// Static class that wraps up certain functions in the SHPhysicsSystem so that
/// accessing it from SHADE_Managed would not cause issues due to C++20 features.
/// </summary>
class SH_API SHPhysicsSystemInterface final
{
public:
/*---------------------------------------------------------------------------------*/
/* Constructor */
/*---------------------------------------------------------------------------------*/
SHPhysicsSystemInterface() = delete;
/*---------------------------------------------------------------------------------*/
/* Static Usage Functions */
/*---------------------------------------------------------------------------------*/
[[nodiscard]] static const std::vector<SHCollisionEvent>& GetCollisionInfo() noexcept;
[[nodiscard]] static const std::vector<SHCollisionEvent>& GetTriggerInfo() noexcept;
[[nodiscard]] static double GetFixedDT() noexcept;
};
}

View File

@ -21,9 +21,11 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
SHResourceHub SHResourceManager::resourceHub;
std::unordered_map<std::type_index, std::unordered_map<AssetID, Handle<void>>> SHResourceManager::handlesMap;
std::unordered_map<std::type_index, SHADE::SHResourceManager::HandleAssetMap> SHResourceManager::assetIdMap;
std::unordered_map<std::type_index, SHResourceManager::HandleAssetMap> SHResourceManager::assetIdMap;
std::unordered_map<std::type_index, std::function<void(AssetID)>> SHResourceManager::typedFreeFuncMap;
std::vector<AssetID> SHResourceManager::loadedAssetData;
bool SHResourceManager::textureChanged = false;
bool SHResourceManager::meshChanged = false;
/*-----------------------------------------------------------------------------------*/
/* Function Definitions */
@ -63,8 +65,17 @@ namespace SHADE
SHGraphicsSystem* gfxSystem = SHSystemManager::GetSystem<SHGraphicsSystem>();
if (gfxSystem == nullptr)
throw std::runtime_error("[SHResourceManager] Attempted to load graphics resource without a SHGraphicsSystem installed.");
gfxSystem->BuildMeshBuffers();
gfxSystem->BuildTextures();
if (meshChanged)
{
gfxSystem->BuildMeshBuffers();
meshChanged = false;
}
if (textureChanged)
{
gfxSystem->BuildTextures();
textureChanged = false;
}
// Free CPU Resources
for (auto assetId : loadedAssetData)

View File

@ -28,33 +28,15 @@ of DigiPen Institute of Technology is prohibited.
namespace SHADE
{
/// <summary>
/// Template structs that maps a resource to their loaded asset representation type.
/// </summary>
template<typename T = void>
struct SHResourceLoader
{
using AssetType = void;
};
template<>
struct SHResourceLoader<SHMesh>
{
using AssetType = SHMeshAsset;
};
template<>
struct SHResourceLoader<SHTexture>
{
using AssetType = SHTextureAsset;
};
template<>
struct SHResourceLoader<SHVkShaderModule>
{
using AssetType = SHShaderAsset;
};
template<>
struct SHResourceLoader<SHMaterial>
{
using AssetType = SHMaterialAsset;
};
struct SHResourceLoader { using AssetType = void; };
template<> struct SHResourceLoader<SHMesh> { using AssetType = SHMeshAsset; };
template<> struct SHResourceLoader<SHTexture> { using AssetType = SHTextureAsset; };
template<> struct SHResourceLoader<SHVkShaderModule> { using AssetType = SHShaderAsset; };
template<> struct SHResourceLoader<SHMaterial> { using AssetType = SHMaterialAsset; };
/// <summary>
/// Static class responsible for loading and caching runtime resources from their
@ -97,7 +79,7 @@ namespace SHADE
/// <param name="assetId">Handle to the resource to unload.</param>
static void Unload(AssetID assetId);
/// <summary>
/// Needs to be called to finalise all changes to loads.
/// Needs to be called to finalise all changes to loads, unless at runtime.
/// </summary>
static void FinaliseChanges();
@ -147,6 +129,9 @@ namespace SHADE
static std::unordered_map<std::type_index, std::function<void(AssetID)>> typedFreeFuncMap;
// Pointers to temp CPU resources
static std::vector<AssetID> loadedAssetData;
// Dirty Flags
static bool meshChanged;
static bool textureChanged;
/*---------------------------------------------------------------------------------*/
/* Helper Functions */

View File

@ -54,7 +54,7 @@ namespace SHADE
}
auto handle = load<ResourceType>(assetId, *assetData);
Handle genericHandle = Handle();
Handle genericHandle = Handle(handle);
typedHandleMap.get().emplace(assetId, genericHandle);
typedAssetIdMap.get().emplace(genericHandle, assetId);
return handle;
@ -139,6 +139,7 @@ namespace SHADE
if constexpr (std::is_same_v<ResourceType, SHMesh>)
{
loadedAssetData.emplace_back(assetId);
meshChanged = true;
return gfxSystem->AddMesh
(
@ -155,6 +156,7 @@ namespace SHADE
else if constexpr (std::is_same_v<ResourceType, SHTexture>)
{
loadedAssetData.emplace_back(assetId);
textureChanged = true;
return gfxSystem->AddTexture
(

View File

@ -80,7 +80,10 @@ namespace SHADE
{
csScriptsExecuteFixedUpdate();
}
void SHScriptEngine::ExecuteCollisionFunctions()
{
csScriptsExecutePhysicsEvents();
}
void SHScriptEngine::Exit()
{
// Do not allow deinitialization if not initialised
@ -377,6 +380,12 @@ namespace SHADE
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"ExecuteLateUpdate"
);
csScriptsExecutePhysicsEvents = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"ExecuteCollisionFunctions"
);
csScriptsFrameCleanUp = dotNet.GetFunctionPtr<CsFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,

View File

@ -98,6 +98,11 @@ namespace SHADE
/// </summary>
void ExecuteFixedUpdates();
/// <summary>
/// Executes the OnCollision*()s and OnTrigger*()s of the Scripts that are attached
/// to Entities.
/// </summary>
void ExecuteCollisionFunctions();
/// <summary>
/// Shuts down the DotNetRuntime.
/// </summary>
void Exit() override;
@ -245,6 +250,7 @@ namespace SHADE
CsFuncPtr csScriptsExecuteFixedUpdate = nullptr;
CsFuncPtr csScriptsExecuteUpdate = nullptr;
CsFuncPtr csScriptsExecuteLateUpdate = nullptr;
CsFuncPtr csScriptsExecutePhysicsEvents = nullptr;
CsFuncPtr csScriptsFrameCleanUp = nullptr;
CsScriptManipFuncPtr csScriptsAdd = nullptr;
CsScriptBasicFuncPtr csScriptsRemoveAll = nullptr;

View File

@ -0,0 +1,127 @@
#include "SHpch.h"
#include "Camera.hxx"
#include "ECS_Base/Managers/SHSystemManager.h"
#include "Camera/SHCameraSystem.h"
namespace SHADE
{
Camera::Camera(Entity entity)
:Component(entity)
{
}
float Camera::Pitch::get()
{
return (GetNativeComponent()->GetPitch());
}
void Camera::Pitch::set(float val)
{
GetNativeComponent()->SetPitch(val);
}
float Camera::Yaw::get()
{
return (GetNativeComponent()->GetYaw());
}
void Camera::Yaw::set(float val)
{
GetNativeComponent()->SetYaw(val);
}
float Camera::Roll::get()
{
return (GetNativeComponent()->GetRoll());
}
void Camera::Roll::set(float val)
{
GetNativeComponent()->SetRoll(val);
}
float Camera::Width::get()
{
return (GetNativeComponent()->GetWidth());
}
void Camera::Width::set(float val)
{
GetNativeComponent()->SetWidth(val);
}
float Camera::Height::get()
{
return (GetNativeComponent()->GetHeight());
}
void Camera::Height::set(float val)
{
GetNativeComponent()->SetHeight(val);
}
float Camera::Near::get()
{
return (GetNativeComponent()->GetNear());
}
void Camera::Near::set(float val)
{
GetNativeComponent()->SetNear(val);
}
float Camera::Far::get()
{
return (GetNativeComponent()->GetFar());
}
void Camera::Far::set(float val)
{
GetNativeComponent()->SetFar(val);
}
float Camera::FOV::get()
{
return (GetNativeComponent()->GetFOV());
}
void Camera::FOV::set(float val)
{
GetNativeComponent()->SetFOV(val);
}
Vector3 Camera::Position::get()
{
return Convert::ToCLI(GetNativeComponent()->GetPosition());
}
void Camera::Position::set(Vector3 val)
{
GetNativeComponent()->SetPosition(Convert::ToNative(val));
}
void Camera::SetMainCamera(size_t directorIndex)
{
auto system = SHSystemManager::GetSystem<SHCameraSystem>();
system->SetMainCamera(GetNativeComponent()->GetEID(), directorIndex);
}
void Camera::SetMainCamera()
{
SetMainCamera(0);
}
void Camera::LookAt(Vector3 targetPosition)
{
auto system = SHSystemManager::GetSystem<SHCameraSystem>();
system->CameraLookAt(*GetNativeComponent(), Convert::ToNative(targetPosition));
}
Vector3 Camera::GetForward()
{
auto system = SHSystemManager::GetSystem<SHCameraSystem>();
SHVec3 forward, up, right;
system->GetCameraAxis(*GetNativeComponent(), forward, right, up);
return Convert::ToCLI(forward);
}
}

View File

@ -0,0 +1,70 @@
#pragma once
// Project Includes
#include "Components/Component.hxx"
#include "Math/Vector3.hxx"
#include "Math/Quaternion.hxx"
// External Dependencies
#include "Camera/SHCameraComponent.h"
namespace SHADE
{
public ref class Camera : public Component<SHCameraComponent>
{
internal:
Camera(Entity entity);
public:
property float Pitch
{
float get();
void set(float val);
}
property float Yaw
{
float get();
void set(float val);
}
property float Roll
{
float get();
void set(float val);
}
property float Width
{
float get();
void set(float val);
}
property float Height
{
float get();
void set(float val);
}
property float Near
{
float get();
void set(float val);
}
property float Far
{
float get();
void set(float val);
}
property float FOV
{
float get();
void set(float val);
}
property Vector3 Position
{
Vector3 get();
void set(Vector3 val);
}
void SetMainCamera(size_t directorIndex);
void SetMainCamera();
void LookAt(Vector3 targetPosition);
Vector3 GetForward();
};
}

View File

@ -0,0 +1,51 @@
#include "SHpch.h"
#include "CameraArm.hxx"
namespace SHADE
{
CameraArm::CameraArm(Entity entity)
:Component(entity)
{
}
float CameraArm::Pitch::get()
{
return (GetNativeComponent()->GetPitch());
}
void CameraArm::Pitch::set(float val)
{
GetNativeComponent()->SetPitch(val);
}
float CameraArm::Yaw::get()
{
return (GetNativeComponent()->GetYaw());
}
void CameraArm::Yaw::set(float val)
{
GetNativeComponent()->SetYaw(val);
}
float CameraArm::ArmLength::get()
{
return (GetNativeComponent()->GetArmLength());
}
void CameraArm::ArmLength::set(float val)
{
GetNativeComponent()->SetArmLength(val);
}
bool CameraArm::LookAtCameraOrigin::get()
{
return GetNativeComponent()->lookAtCameraOrigin;
}
void CameraArm::LookAtCameraOrigin::set(bool val)
{
GetNativeComponent()->lookAtCameraOrigin = val;
}
}

View File

@ -0,0 +1,40 @@
#pragma once
// Project Includes
#include "Components/Component.hxx"
#include "Math/Vector3.hxx"
// External Dependencies
#include "Camera/SHCameraArmComponent.h"
namespace SHADE
{
public ref class CameraArm : public Component<SHCameraArmComponent>
{
internal:
CameraArm(Entity entity);
public:
property float Pitch
{
float get();
void set(float val);
}
property float Yaw
{
float get();
void set(float val);
}
property float ArmLength
{
float get();
void set(float val);
}
property bool LookAtCameraOrigin
{
bool get();
void set(bool val);
}
};
}

View File

@ -87,15 +87,6 @@ namespace SHADE
{
GetNativeComponent()->SetWorldScale(Convert::ToNative(val));
}
Transform^ Transform::Parent::get()
{
auto node = SHSceneManager::GetCurrentSceneGraph().GetNode(owner.GetEntity());
if (!node)
throw gcnew System::InvalidOperationException("[Transform] Unable to retrieve SceneGraphNode for an Entity.");
const auto PARENT = node->GetParent();
return PARENT ? gcnew Transform(PARENT->GetEntityID()) : nullptr;
}
/*---------------------------------------------------------------------------------*/
/* Constructors */
@ -103,21 +94,4 @@ namespace SHADE
Transform::Transform(Entity entity)
: Component(entity)
{}
/*---------------------------------------------------------------------------------*/
/* Usage Functions */
/*---------------------------------------------------------------------------------*/
void Transform::SetParent(Transform^ parent, bool worldPositionStays)
{
auto& sceneGraph = SHSceneManager::GetCurrentSceneGraph();
auto node = sceneGraph.GetNode(owner.GetEntity());
if (!node)
throw gcnew System::InvalidOperationException("[Transform] Unable to retrieve SceneGraphNode for an Entity.");
if (parent)
node->SetParent(sceneGraph.GetNode(parent->owner.GetEntity()));
else
sceneGraph.SetParent(parent->owner.GetEntity(), nullptr);
}
}

View File

@ -107,30 +107,6 @@ namespace SHADE
Vector3 get();
void set(Vector3 val);
}
/// <summary>
/// Parent Transform that affects this Transform.
/// </summary>
property Transform^ Parent
{
Transform^ get();
}
/*-----------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Sets the parent of this Transform component.
/// </summary>
/// <param name="parent">
/// Entity that contains the Transform component that this Transform will be
/// parented to. If null, unparenting will occur.
/// </param>
/// <param name="worldPositionStays">
/// If true, the transform values of this Transform component will retain their
/// pre-parent-change global transforms. The local transform values will be
/// modified to ensure that the global transforms do not change.
/// </param>
void SetParent(Transform^ parent, bool worldPositionStays);
};
}

View File

@ -260,7 +260,7 @@ namespace SHADE
int val = safe_cast<int>(field->GetValue(object));
int oldVal = val;
if (SHEditorUI::InputEnumCombo(Convert::ToNative(field->Name), val, nativeEnumNames))
if (SHEditorUI::InputEnumCombo(Convert::ToNative(field->Name), val, nativeEnumNames, &isHovered))
{
field->SetValue(object, val);
registerUndoAction(object, field, val, oldVal);
@ -280,12 +280,23 @@ namespace SHADE
// Actual Field
std::string val = Convert::ToNative(stringVal);
std::string oldVal = val;
if (SHEditorUI::InputTextField(Convert::ToNative(field->Name), val))
if (SHEditorUI::InputTextField(Convert::ToNative(field->Name), val, &isHovered))
{
field->SetValue(object, Convert::ToCLI(val));
registerUndoAction(object, field, Convert::ToCLI(val), Convert::ToCLI(oldVal));
}
}
else if (field->FieldType == GameObject::typeid)
{
GameObject gameObj = safe_cast<GameObject>(field->GetValue(object));
uint32_t entityId = gameObj.GetEntity();
if (SHEditorUI::InputGameObjectField(Convert::ToNative(field->Name), entityId, &isHovered))
{
GameObject newVal = GameObject(entityId);
field->SetValue(object, newVal);
registerUndoAction(object, field, newVal, gameObj);
}
}
else
{
array<System::Type^>^ interfaces = field->FieldType->GetInterfaces();

View File

@ -33,6 +33,8 @@ of DigiPen Institute of Technology is prohibited.
#include "Components/Transform.hxx"
#include "Components\RigidBody.hxx"
#include "Components\Collider.hxx"
#include "Components/Camera.hxx"
#include "Components/CameraArm.hxx"
namespace SHADE
{
@ -248,6 +250,8 @@ namespace SHADE
componentMap.Add(createComponentSet<SHTransformComponent, Transform>());
componentMap.Add(createComponentSet<SHColliderComponent, Collider>());
componentMap.Add(createComponentSet<SHRigidBodyComponent, RigidBody>());
componentMap.Add(createComponentSet<SHCameraComponent, Camera>());
componentMap.Add(createComponentSet<SHCameraArmComponent, CameraArm>());
}
/*---------------------------------------------------------------------------------*/

View File

@ -17,6 +17,7 @@ of DigiPen Institute of Technology is prohibited.
#include "GameObject.hxx"
// External Dependencies
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Scene/SHSceneGraph.h"
// Project Headers
#include "ECS.hxx"
#include "Utility/Convert.hxx"
@ -72,6 +73,31 @@ namespace SHADE
}
return node->IsActive();
}
Entity GameObject::EntityId::get()
{
return entity;
}
GameObject^ GameObject::Parent::get()
{
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
const auto* ROOT = SCENE_GRAPH.GetRoot();
const auto* NODE = SCENE_GRAPH.GetNode(entity);
if (NODE == nullptr)
throw gcnew System::InvalidOperationException("Unable to retrieve SceneGraphNode for Entity " + entity.ToString());
const auto* PARENT = NODE->GetParent();
return PARENT != ROOT ? gcnew GameObject(PARENT->GetEntityID()) : nullptr;
}
void GameObject::Parent::set(GameObject^ newParent)
{
const auto& SCENE_GRAPH = SHSceneManager::GetCurrentSceneGraph();
if (newParent == nullptr)
SCENE_GRAPH.SetParent(entity, nullptr);
else
SCENE_GRAPH.SetParent(entity, newParent->EntityId);
}
/*---------------------------------------------------------------------------------*/
/* GameObject Property Functions */
@ -155,11 +181,13 @@ namespace SHADE
/* Constructors */
/*---------------------------------------------------------------------------------*/
GameObject::GameObject(const SHEntity& entity)
: entity { entity.GetEID() }
: entity { entity.GetEID() }
, children{ gcnew System::Collections::ArrayList }
{}
GameObject::GameObject(Entity entity)
: entity { entity }
: entity { entity }
, children{ gcnew System::Collections::ArrayList }
{}
/*---------------------------------------------------------------------------------*/

View File

@ -86,6 +86,21 @@ namespace SHADE
{
bool get();
}
/// <summary>
/// Native Entity ID value for this GameObject.
/// </summary>
property Entity EntityId
{
Entity get();
}
/// <summary>
/// The parent entity for this GameObject.
/// </summary>
property GameObject^ Parent
{
GameObject^ get();
void set(GameObject^);
}
/*-----------------------------------------------------------------------------*/
/* GameObject Property Functions */
@ -105,6 +120,7 @@ namespace SHADE
/// Whether to activate or deactivate this GameObject.
/// </param>
void SetActive(bool active);
/*-----------------------------------------------------------------------------*/
/* Component Access Functions */
@ -235,7 +251,8 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
Entity entity;
Entity entity;
System::Collections::ArrayList^ children;
public:
/*-----------------------------------------------------------------------------*/

View File

@ -14,6 +14,9 @@ of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
// Precompiled Headers
#include "SHpch.h"
// External Dependencies
#include "FRC/SHFramerateController.h"
#include "Physics/SHPhysicsSystemInterface.h"
// Primary Header
#include "Time.hxx"
@ -26,4 +29,14 @@ namespace SHADE
{
return SHFrameRateController::GetRawDeltaTime();
}
float Time::DeltaTimeF::get()
{
return static_cast<float>(SHFrameRateController::GetRawDeltaTime());
}
double Time::FixedDeltaTime::get()
{
return SHPhysicsSystemInterface::GetFixedDT();
}
}

View File

@ -14,8 +14,6 @@ of DigiPen Institute of Technology is prohibited.
*//*************************************************************************************/
#pragma once
#include "FRC/SHFramerateController.h"
namespace SHADE
{
/// <summary>
@ -29,13 +27,28 @@ namespace SHADE
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Time taken to process the previous frame.
/// Note, is affected by TimeScale. Use UnscaledDeltaTime if you wish to retrieve
/// real world time. This is also affected by MaxDeltaTime clamping that
/// UnscaledDeltaTime is subject to.
/// </summary>
static property double DeltaTime
{
double get();
}
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Time taken to process the previous frame.
/// </summary>
static property float DeltaTimeF
{
float get();
}
/// <summary>
/// Time taken for Physics simulations. You should use this for operations
/// within Script.FixedUpdate()
/// </summary>
static property double FixedDeltaTime
{
double get();
}
};
}

View File

@ -99,4 +99,11 @@ namespace SHADE
return SHInputManager::GetKeyReleasedTime(static_cast<SHInputManager::SH_KEYCODE>(key));
}
Vector2 Input::GetMouseVelocity()
{
double velX, velY;
SHInputManager::GetMouseVelocity(&velX, &velY);
return Convert::ToCLI(SHVec2{ (float)velX,(float)velY });
}
}

View File

@ -471,5 +471,7 @@ namespace SHADE
/// <param name="key">The key to check.</param>
/// <returns>Time in seconds that the key was held.</returns>
static double GetMouseReleasedTime(MouseCode mouseButton);
static Vector2 GetMouseVelocity();
};
}

View File

@ -236,6 +236,22 @@ namespace SHADE
lhs.y * rhs.y
);
}
Vector2 Vector2::operator*(Vector2 lhs, double rhs)
{
return Vector2
(
lhs.x * static_cast<float>(rhs),
lhs.y * static_cast<float>(rhs)
);
}
Vector2 Vector2::operator/(Vector2 lhs, double rhs)
{
return Vector2
(
lhs.x / static_cast<float>(rhs),
lhs.y / static_cast<float>(rhs)
);
}
Vector2 Vector2::operator*(Vector2 lhs, float rhs)
{
return Vector2

View File

@ -361,6 +361,22 @@ namespace SHADE
/// <param name="lhs">Vector2 to multiply with.</param>
/// <param name="rhs">Scalar to multiply with.</param>
/// <returns>The result of the scalar multiplication.</returns>
static Vector2 operator*(Vector2 lhs, double rhs);
/// <summary>
/// Calculates the division of a Vector2 with a scalar value and returns
/// the result.
/// </summary>
/// <param name="lhs">Scalar to divide with.</param>
/// <param name="rhs">Vector2 to divide with.</param>
/// <returns>The result of the scalar division.</returns>
static Vector2 operator/(Vector2 lhs, double rhs);
/// <summary>
/// Calculates the multiplication of a Vector2 with a scalar value and returns
/// the result.
/// </summary>
/// <param name="lhs">Vector2 to multiply with.</param>
/// <param name="rhs">Scalar to multiply with.</param>
/// <returns>The result of the scalar multiplication.</returns>
static Vector2 operator*(Vector2 lhs, float rhs);
/// <summary>
/// Calculates the division of a Vector2 with a scalar value and returns

View File

@ -237,6 +237,24 @@ namespace SHADE
lhs.z * rhs.z
);
}
Vector3 Vector3::operator*(Vector3 lhs, double rhs)
{
return Vector3
(
lhs.x * static_cast<float>(rhs),
lhs.y * static_cast<float>(rhs),
lhs.z * static_cast<float>(rhs)
);
}
Vector3 Vector3::operator/(Vector3 lhs, double rhs)
{
return Vector3
(
lhs.x / static_cast<float>(rhs),
lhs.y / static_cast<float>(rhs),
lhs.z / static_cast<float>(rhs)
);
}
Vector3 Vector3::operator*(Vector3 lhs, float rhs)
{
return Vector3

View File

@ -375,6 +375,22 @@ namespace SHADE
/// <param name="lhs">Vector3 to multiply with.</param>
/// <param name="rhs">Scalar to multiply with.</param>
/// <returns>The result of the scalar multiplication.</returns>
static Vector3 operator*(Vector3 lhs, double rhs);
/// <summary>
/// Calculates the division of a Vector3 with a scalar value and returns
/// the result.
/// </summary>
/// <param name="lhs">Scalar to divide with.</param>
/// <param name="rhs">Vector3 to divide with.</param>
/// <returns>The result of the scalar division.</returns>
static Vector3 operator/(Vector3 lhs, double rhs);
/// <summary>
/// Calculates the multiplication of a Vector3 with a scalar value and returns
/// the result.
/// </summary>
/// <param name="lhs">Vector3 to multiply with.</param>
/// <param name="rhs">Scalar to multiply with.</param>
/// <returns>The result of the scalar multiplication.</returns>
static Vector3 operator*(Vector3 lhs, float rhs);
/// <summary>
/// Calculates the division of a Vector3 with a scalar value and returns

View File

@ -0,0 +1,36 @@
/************************************************************************************//*!
\file CollisionInfo.cxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 31, 2022
\brief Contains the definition of the functions of the managed CollisionInfo
struct.
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.
*//*************************************************************************************/
#include "SHpch.h"
#include "CollisionInfo.hxx"
#include "Components/RigidBody.hxx"
#include "Components/Collider.hxx"
namespace SHADE
{
Collider^ CollisionInfo::Collider::get()
{
return GameObject.GetComponent<SHADE::Collider^>();
}
CollisionShape^ CollisionInfo::CollisionShape::get()
{
throw gcnew System::NotImplementedException();
}
RigidBody^ CollisionInfo::RigidBody::get()
{
return GameObject.GetComponent<SHADE::RigidBody^>();
}
}

View File

@ -0,0 +1,66 @@
/************************************************************************************//*!
\file CollisionInfo.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 31, 2022
\brief Contains the definition of the managed CollisionInfo struct with the
definition of its properties and declaration of functions.
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
// Project Includes
#include "Engine/GameObject.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Forward Declarations */
/*---------------------------------------------------------------------------------*/
ref class RigidBody;
ref class Collider;
ref class CollisionShape;
/*---------------------------------------------------------------------------------*/
/* Type Definitions */
/*---------------------------------------------------------------------------------*/
/// <summary>
/// Struct that describes a collision
/// </summary>
public value struct CollisionInfo
{
public:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// The GameObject whose collider you are colliding with.
/// </summary>
property GameObject GameObject;
/// <summary>
/// The Collider that you are colliding with.
/// </summary>
property Collider^ Collider
{
SHADE::Collider^ get();
}
/// <summary>
/// The CollisionShape of the Collider that you are colliding with.
/// </summary>
property CollisionShape^ CollisionShape
{
SHADE::CollisionShape^ get();
}
/// <summary>
/// The RigidBody that you are colliding with.
/// </summary>
property RigidBody^ RigidBody
{
SHADE::RigidBody^ get();
}
};
}

View File

@ -147,6 +147,48 @@ namespace SHADE
SAFE_NATIVE_CALL_END(this)
}
void Script::OnCollisionEnter(CollisionInfo collision)
{
SAFE_NATIVE_CALL_BEGIN
onCollisionEnter(collision);
SAFE_NATIVE_CALL_END(this)
}
void Script::OnCollisionStay(CollisionInfo collision)
{
SAFE_NATIVE_CALL_BEGIN
onCollisionStay(collision);
SAFE_NATIVE_CALL_END(this)
}
void Script::OnCollisionExit(CollisionInfo collision)
{
SAFE_NATIVE_CALL_BEGIN
onCollisionExit(collision);
SAFE_NATIVE_CALL_END(this)
}
void Script::OnTriggerEnter(CollisionInfo collision)
{
SAFE_NATIVE_CALL_BEGIN
onTriggerEnter(collision);
SAFE_NATIVE_CALL_END(this)
}
void Script::OnTriggerStay(CollisionInfo collision)
{
SAFE_NATIVE_CALL_BEGIN
onTriggerStay(collision);
SAFE_NATIVE_CALL_END(this)
}
void Script::OnTriggerExit(CollisionInfo collision)
{
SAFE_NATIVE_CALL_BEGIN
onTriggerExit(collision);
SAFE_NATIVE_CALL_END(this)
}
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
@ -169,4 +211,14 @@ namespace SHADE
void Script::update() {}
void Script::lateUpdate() {}
void Script::onDestroy() {}
}// namespace PlushieAPI
/*---------------------------------------------------------------------------------*/
/* Virtual Event Functions */
/*---------------------------------------------------------------------------------*/
void Script::onTriggerEnter(CollisionInfo) {}
void Script::onTriggerStay(CollisionInfo) {}
void Script::onTriggerExit(CollisionInfo) {}
void Script::onCollisionEnter(CollisionInfo) {}
void Script::onCollisionStay(CollisionInfo) {}
void Script::onCollisionExit(CollisionInfo) {}
}

View File

@ -15,6 +15,7 @@ of DigiPen Institute of Technology is prohibited.
// Project Includes
#include "Engine/GameObject.hxx"
#include "Physics/CollisionInfo.hxx"
namespace SHADE
{
@ -213,6 +214,46 @@ namespace SHADE
/// </summary>
void OnDestroy();
/*-----------------------------------------------------------------------------*/
/* Event Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Used to call onCollisionEnter(). This should be called when a collision is
/// detected between the attached GameObject and another GameObject.
/// </summary>
/// <param name="collision">Information on the collision event.</param>
void OnCollisionEnter(CollisionInfo collision);
/// <summary>
/// Used to call onCollisionStay(). This should be called when a collision is
/// persistent between the attached GameObject and another GameObject.
/// </summary>
/// <param name="collision">Information on the collision event.</param>
void OnCollisionStay(CollisionInfo collision);
/// <summary>
/// Used to call onCollisionExit(). This should be called when a collision ends
/// between the attached GameObject and another GameObject.
/// </summary>
/// <param name="collision">Information on the collision event.</param>
void OnCollisionExit(CollisionInfo collision);
/// <summary>
/// Used to call onTriggerEnter(). This should be called when a trigger-type
/// collision is detected between the attached GameObject and another GameObject.
/// </summary>
/// <param name="collision">Information on the collision event.</param>
void OnTriggerEnter(CollisionInfo collision);
/// <summary>
/// Used to call onTriggerStay(). This should be called when a trigger-type
/// collision is detected between the attached GameObject and another GameObject.
/// </summary>
/// <param name="collision">Information on the collision event.</param>
void OnTriggerStay(CollisionInfo collision);
/// <summary>
/// Used to call onTriggerExit(). This should be called when a trigger-type
/// collision is detected between the attached GameObject and another GameObject.
/// </summary>
/// <param name="collision">Information on the collision event.</param>
void OnTriggerExit(CollisionInfo collision);
protected:
/*-----------------------------------------------------------------------------*/
/* Constructors */
@ -273,6 +314,46 @@ namespace SHADE
/// </summary>
virtual void onDestroy();
/*-----------------------------------------------------------------------------*/
/* Virtual Event Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Called when the attached GameObject has a trigger Collider and collides with
/// another GameObject with a Collider in the first frame of collision.
/// </summary>
/// <param name="info">Information on the collision event.</param>
virtual void onTriggerEnter(CollisionInfo info);
/// <summary>
/// Called when the attached GameObject has a trigger Collider and collides with
/// another GameObject with a Collider in subsequent frames of collision.
/// </summary>
/// <param name="info">Information on the collision event.</param>
virtual void onTriggerStay(CollisionInfo info);
/// <summary>
/// Called when the attached GameObject has a trigger Collider and leaves a
/// collision with another GameObject with a Collider2D.
/// </summary>
/// <param name="info">Information on the collision event.</param>
virtual void onTriggerExit(CollisionInfo info);
/// <summary>
/// Called when the attached GameObject has a Collider and collides with
/// another GameObject with a Collider in the first frame of collision.
/// </summary>
/// <param name="info">Information on the collision event.</param>
virtual void onCollisionEnter(CollisionInfo info);
/// <summary>
/// Called when the attached GameObject has a Collider and collides with
/// another GameObject with a Collider in subsequent frames of collision.
/// </summary>
/// <param name="info">Information on the collision event.</param>
virtual void onCollisionStay(CollisionInfo info);
/// <summary>
/// Called when the attached GameObject has a Collider and leaves a
/// collision with another GameObject with a Collider2D.
/// </summary>
/// <param name="info">Information on the collision event.</param>
virtual void onCollisionExit(CollisionInfo info);
private:
/*-----------------------------------------------------------------------------*/
/* Data Members */
@ -280,4 +361,4 @@ namespace SHADE
GameObject owner;
};
} // namespace PlushieAPI
}

View File

@ -28,6 +28,8 @@ of DigiPen Institute of Technology is prohibited.
#include "Engine/Entity.hxx"
#include "Serialisation/ReflectionUtilities.hxx"
#include "Engine/Application.hxx"
#include "Physics/SHPhysicsSystemInterface.h"
#include "Physics/SHPhysicsUtils.h"
namespace SHADE
{
@ -71,7 +73,7 @@ namespace SHADE
SAFE_NATIVE_CALL_BEGIN
Script^ script;
return AddScriptViaNameWithRef(entity, scriptName, script);
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
return false;
}
@ -301,7 +303,7 @@ namespace SHADE
removeScript(script);
}
scriptList->Clear();
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
}
void ScriptStore::RemoveAllScriptsImmediately(Entity entity, bool callOnDestroy)
{
@ -326,7 +328,7 @@ namespace SHADE
startList.Remove(script);
}
scriptList->Clear();
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
}
/*---------------------------------------------------------------------------------*/
@ -365,7 +367,7 @@ namespace SHADE
startList.AddRange(%inactiveStartList);
inactiveStartList.Clear();
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
}
void ScriptStore::FrameCleanUp()
{
@ -386,7 +388,7 @@ namespace SHADE
scripts.Remove(entity);
}
}
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
}
void ScriptStore::Exit()
{
@ -410,7 +412,7 @@ namespace SHADE
startList.Clear();
disposalQueue.Clear();
scriptTypeList = nullptr;
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
}
/*---------------------------------------------------------------------------------*/
@ -439,7 +441,7 @@ namespace SHADE
script->FixedUpdate();
}
}
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
}
void ScriptStore::ExecuteUpdate()
{
@ -456,7 +458,7 @@ namespace SHADE
script->Update();
}
}
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
}
void ScriptStore::ExecuteLateUpdate()
{
@ -473,7 +475,95 @@ namespace SHADE
script->LateUpdate();
}
}
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
}
void ScriptStore::ExecuteCollisionFunctions()
{
SAFE_NATIVE_CALL_BEGIN
/* Collisions */
const auto& collisions = SHPhysicsSystemInterface::GetCollisionInfo();
for (const auto& collisionInfo : collisions)
{
auto entities =
{
std::make_pair(collisionInfo.GetEntityA(), collisionInfo.GetEntityB()),
std::make_pair(collisionInfo.GetEntityB(), collisionInfo.GetEntityA())
};
for (auto entity : entities)
{
// Don't bother if this object has no scripts or is inactive
if (!isEntityActive(entity.first) || !scripts.ContainsKey(entity.first))
continue;
// Construct the collision state object
CollisionInfo info;
info.GameObject = GameObject(entity.second);
// Call all of the script's functions
auto entityScripts = scripts[entity.first];
if (entityScripts->Count > 0)
{
for each (Script ^ script in entityScripts)
{
switch (collisionInfo.GetCollisionState())
{
case SHCollisionEvent::State::ENTER:
script->OnCollisionEnter(info);
break;
case SHCollisionEvent::State::STAY:
script->OnCollisionStay(info);
break;
case SHCollisionEvent::State::EXIT:
script->OnCollisionExit(info);
break;
}
}
}
}
}
/* Triggers */
const auto& triggers = SHPhysicsSystemInterface::GetTriggerInfo();
for (const auto& triggerInfo : triggers)
{
auto entities =
{
std::make_pair(triggerInfo.GetEntityA(), triggerInfo.GetEntityB()),
std::make_pair(triggerInfo.GetEntityB(), triggerInfo.GetEntityA())
};
for (auto entity : entities)
{
// Don't bother if this object has no scripts or is inactive
if (!isEntityActive(entity.first) || !scripts.ContainsKey(entity.first))
continue;
// Construct the collision state object
CollisionInfo info;
info.GameObject = GameObject(entity.second);
// Call all of the script's functions
auto entityScripts = scripts[entity.first];
if (entityScripts->Count > 0)
{
for each (Script ^ script in entityScripts)
{
switch (triggerInfo.GetCollisionState())
{
case SHCollisionEvent::State::ENTER:
script->OnTriggerEnter(info);
break;
case SHCollisionEvent::State::STAY:
script->OnTriggerStay(info);
break;
case SHCollisionEvent::State::EXIT:
script->OnTriggerExit(info);
break;
}
}
}
}
}
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
}
bool ScriptStore::SerialiseScripts(Entity entity, System::IntPtr yamlNodePtr)
@ -509,7 +599,7 @@ namespace SHADE
}
return true;
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
return false;
}
@ -559,7 +649,7 @@ namespace SHADE
}
return true;
SAFE_NATIVE_CALL_END_N("SHADE.ScriptStore")
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
return false;
}

View File

@ -233,6 +233,10 @@ namespace SHADE
/// Executes LateUpdate() for all scripts.
/// </summary>
static void ExecuteLateUpdate();
/// <summary>
/// Executes OnCollision*() and OnTrigger*() for all scripts.
/// </summary>
static void ExecuteCollisionFunctions();
/*-----------------------------------------------------------------------------*/
/* Serialisation Functions */

View File

@ -22,6 +22,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Math/Vector2.hxx"
#include "Math/Vector3.hxx"
#include "Utility/Debug.hxx"
#include "Engine/GameObject.hxx"
/*-------------------------------------------------------------------------------------*/
/* Macro Functions */
@ -167,6 +168,11 @@ namespace SHADE
fieldNode.push_back(vec.y);
fieldNode.push_back(vec.z);
}
else if (fieldInfo->FieldType == GameObject::typeid)
{
GameObject gameObj = safe_cast<GameObject>(fieldInfo->GetValue(object));
fieldNode = gameObj.GetEntity();
}
else // Not any of the supported types
{
Debug::LogWarning(Convert::ToNative(System::String::Format
@ -242,6 +248,10 @@ namespace SHADE
);
}
}
else if (fieldInfo->FieldType == GameObject::typeid)
{
fieldInfo->SetValue(object, GameObject(node.as<uint32_t>()));
}
else // Not any of the supported types
{
Debug::LogWarning(Convert::ToNative(System::String::Format

View File

@ -0,0 +1,22 @@
using System;
using SHADE;
namespace SHADE_Scripting
{
public class CameraControl :Script
{
public float turnSpeed = 0.5f;
public CameraControl(GameObject go) : base(go) { }
protected override void update()
{
//Camera
Camera cam = GetComponent<Camera>();
Vector2 mouseVel = Input.GetMouseVelocity();
cam.Pitch -= mouseVel.y * turnSpeed * (float)Time.DeltaTime;
cam.Yaw += mouseVel.x * turnSpeed * (float)Time.DeltaTime;
}
}
}

View File

@ -38,6 +38,35 @@ public class PhysicsTest : Script
RigidBody.AddForce(Force);
Debug.Log($"Jump!");
}
Debug.Log($"{Transform.LocalPosition.y}");
}
protected override void fixedUpdate()
{
Debug.Log("Fixed Update");
}
protected override void onCollisionEnter(CollisionInfo info)
{
Debug.Log($"Collision Enter: {info.GameObject.Name}");
}
protected override void onCollisionStay(CollisionInfo info)
{
Debug.Log($"Collision Stay: {info.GameObject.Name}");
}
protected override void onCollisionExit(CollisionInfo info)
{
Debug.Log($"Collision Exit: {info.GameObject.Name}");
}
protected override void onTriggerEnter(CollisionInfo info)
{
Debug.Log($"Trigger Enter: {info.GameObject.Name}");
}
protected override void onTriggerStay(CollisionInfo info)
{
Debug.Log($"Trigger Stay: {info.GameObject.Name}");
}
protected override void onTriggerExit(CollisionInfo info)
{
Debug.Log($"Trigger Exit: {info.GameObject.Name}");
}
}

View File

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SHADE;
namespace SHADE_Scripting
{
public class ThirdPersonCamera: Script
{
public float armLength = 4.0f;
public float turnSpeedPitch = 0.3f;
public float turnSpeedYaw = 0.5f;
public float pitchClamp = 45.0f;
public ThirdPersonCamera(GameObject go) : base(go) { }
protected override void awake()
{
if(!GetComponent<Camera>())
{
AddComponent<Camera>();
}
if (!GetComponent<CameraArm>())
{
AddComponent<CameraArm>();
}
GetComponent<CameraArm>().ArmLength = armLength;
}
protected override void update()
{
CameraArm arm = GetComponent<CameraArm>();
if(arm)
{
Vector2 vel = Input.GetMouseVelocity();
arm.Pitch -= vel.y * turnSpeedPitch * Time.DeltaTimeF;
arm.Yaw += vel.x * turnSpeedYaw * Time.DeltaTimeF;
if(arm.Pitch > pitchClamp)
{
arm.Pitch = pitchClamp;
}
else if(arm.Pitch < -pitchClamp)
{
arm.Pitch = -pitchClamp;
}
}
}
}
}

1029
bin/Debug/SHADE_CSharp.xml Normal file

File diff suppressed because it is too large Load Diff

6250
bin/Debug/SHADE_Managed.xml Normal file

File diff suppressed because it is too large Load Diff

1029
bin/Release/SHADE_CSharp.xml Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff