Merge pull request #76 from WiggleWizard/feature/morereflection

Second pass reflection
This commit is contained in:
Antoine Pilote
2024-09-16 11:10:44 -04:00
committed by GitHub
81 changed files with 1449 additions and 46183 deletions

3
.gitmodules vendored
View File

@@ -31,3 +31,6 @@
[submodule "Nuake/dependencies/freetype"]
path = Nuake/dependencies/freetype
url = https://github.com/freetype/freetype.git
[submodule "Nuake/dependencies/entt"]
path = Nuake/dependencies/entt
url = https://github.com/skypjack/entt.git

View File

@@ -1,147 +0,0 @@
#pragma once
#include "ComponentPanel.h"
#include "src/FileSystem/FileSystem.h"
#include <src/Core/Maths.h>
#include <src/Scene/Components/AudioEmitterComponent.h>
#include <src/Scene/Entities/ImGuiHelper.h>
class AudioEmitterPanel : ComponentPanel
{
public:
AudioEmitterPanel() = default;
~AudioEmitterPanel() = default;
void Draw(Nuake::Entity entity) override
{
using namespace Nuake;
if (!entity.HasComponent<AudioEmitterComponent>())
return;
auto& component = entity.GetComponent<AudioEmitterComponent>();
BeginComponentTable(AUDIO EMITTER, AudioEmitterComponent);
{
{
ImGui::Text("Audio File");
ImGui::TableNextColumn();
std::string path = component.FilePath;
ImGui::Button(component.FilePath.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0));
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_AudioFile"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 256);
path = Nuake::FileSystem::AbsoluteToRelative(fullPath);
component.FilePath = path;
}
ImGui::EndDragDropTarget();
}
ImGui::TableNextColumn();
ComponentTableReset(component.FilePath, "");
}
ImGui::TableNextColumn();
{
ImGui::Text("Playing");
ImGui::TableNextColumn();
UI::ToggleButton("##Player", &component.IsPlaying);
//ImGui::Checkbox("##Playing", &component.IsPlaying);
ImGui::TableNextColumn();
ComponentTableReset(component.IsPlaying, false);
}
ImGui::TableNextColumn();
{
ImGui::Text("Loop");
ImGui::TableNextColumn();
ImGui::Checkbox("##Loop", &component.Loop);
ImGui::TableNextColumn();
ComponentTableReset(component.Loop, false);
}
ImGui::TableNextColumn();
{
ImGui::Text("Volume");
ImGui::TableNextColumn();
ImGui::DragFloat("##Volume", &component.Volume, 0.001f, 0.0f, 2.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Volume, 1.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Playback Speed");
ImGui::TableNextColumn();
ImGui::DragFloat("##PlaybackSpeed", &component.PlaybackSpeed, 0.01f, 0.0001f);
ImGui::TableNextColumn();
ComponentTableReset(component.PlaybackSpeed, 1.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Pan");
ImGui::TableNextColumn();
ImGui::DragFloat("##Pan", &component.Pan, 0.01f, -1.0f, 1.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Pan, 0.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Spatialized");
ImGui::TableNextColumn();
ImGui::Checkbox("##Spatialized", &component.Spatialized);
ImGui::TableNextColumn();
ComponentTableReset(component.Spatialized, false);
}
if (component.Spatialized)
{
ImGui::TableNextColumn();
{
ImGui::Text("Min Distance");
ImGui::TableNextColumn();
ImGui::DragFloat("##minDistance", &component.MinDistance, 0.001f, 0.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.MinDistance, 1.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Max Distance");
ImGui::TableNextColumn();
ImGui::DragFloat("##maxDistance", &component.MaxDistance, 0.001f, 0.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.MaxDistance, 10.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Attenuation Factor");
ImGui::TableNextColumn();
ImGui::DragFloat("##attenuationFactor", &component.AttenuationFactor, 0.001f, 0.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.AttenuationFactor, 1.0f);
}
}
}
EndComponentTable();
}
};

View File

@@ -6,19 +6,20 @@
#include <src/Scene/Components/BoneComponent.h>
#include <src/Scene/Entities/ImGuiHelper.h>
class BonePanel : ComponentPanel
class BonePanel
{
public:
BonePanel() {}
void Draw(Nuake::Entity entity) override
static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance)
{
using namespace Nuake;
if (!entity.HasComponent<BoneComponent>())
Nuake::BoneComponent* componentPtr = componentInstance.try_cast<Nuake::BoneComponent>();
if (componentPtr == nullptr)
{
return;
auto& component = entity.GetComponent<BoneComponent>();
}
Nuake::BoneComponent& component = *componentPtr;
BeginComponentTable(BONE, BoneComponent);
{
{

View File

@@ -3,17 +3,20 @@
#include <src/Scene/Components/CameraComponent.h>
#include "src/FileSystem/FileSystem.h"
class CameraPanel : ComponentPanel {
class CameraPanel {
public:
CameraPanel() {}
void Draw(Nuake::Entity entity) override
static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance)
{
if (!entity.HasComponent<Nuake::CameraComponent>())
using namespace Nuake;
Nuake::CameraComponent* componentPtr = componentInstance.try_cast<Nuake::CameraComponent>();
if (componentPtr == nullptr)
{
return;
auto& component = entity.GetComponent<Nuake::CameraComponent>();
}
Nuake::CameraComponent& component = *componentPtr;
BeginComponentTable(CAMERA, Nuake::CameraComponent);
{
{

View File

@@ -3,48 +3,47 @@
#include <src/Scene/Components/CapsuleColliderComponent.h>
class CapsuleColliderPanel : ComponentPanel
class CapsuleColliderPanel
{
public:
CapsuleColliderPanel() = default;
void Draw(Nuake::Entity entity) override
static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance)
{
using namespace Nuake;
if (!entity.HasComponent<CapsuleColliderComponent>())
Nuake::CapsuleColliderComponent* componentPtr = componentInstance.try_cast<Nuake::CapsuleColliderComponent>();
if (componentPtr == nullptr)
{
return;
}
auto& [Capsule, Radius, Height, IsTrigger] = entity.GetComponent<CapsuleColliderComponent>();
Nuake::CapsuleColliderComponent& component = *componentPtr;
BeginComponentTable(CAPSULE COLLIDER, CapsuleColliderComponent)
{
{
ImGui::Text("Radius");
ImGui::TableNextColumn();
ImGui::DragFloat("##Radius", &Radius, 0.01f, 0.001f);
Radius = std::max(Radius, 0.001f);
ImGui::DragFloat("##Radius", &component.Radius, 0.01f, 0.001f);
component.Radius = std::max(component.Radius, 0.001f);
ImGui::TableNextColumn();
ComponentTableReset(Radius, 0.5f)
ComponentTableReset(component.Radius, 0.5f)
}
ImGui::TableNextColumn();
{
ImGui::Text("Height");
ImGui::TableNextColumn();
ImGui::DragFloat("##Height", &Height, 0.01f, 0.001f);
Height = std::max(Height, 0.001f);
ImGui::DragFloat("##Height", &component.Height, 0.01f, 0.001f);
component.Height = std::max(component.Height, 0.001f);
ImGui::TableNextColumn();
ComponentTableReset(Height, 1.0f)
ComponentTableReset(component.Height, 1.0f)
}
ImGui::TableNextColumn();
{
ImGui::Text("Is Trigger");
ImGui::TableNextColumn();
ImGui::Checkbox("##isTrigger", &IsTrigger);
ImGui::Checkbox("##isTrigger", &component.IsTrigger);
ImGui::TableNextColumn();
ComponentTableReset(IsTrigger, false);
ComponentTableReset(component.IsTrigger, false);
}
}
EndComponentTable()

View File

@@ -3,18 +3,20 @@
#include <src/Scene/Components/CharacterControllerComponent.h>
#include "src/FileSystem/FileSystem.h"
class CharacterControllerPanel : ComponentPanel {
class CharacterControllerPanel
{
public:
CharacterControllerPanel() {}
void Draw(Nuake::Entity entity) override
static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance)
{
if (!entity.HasComponent<Nuake::CharacterControllerComponent>())
return;
using namespace Nuake;
auto& component = entity.GetComponent<Nuake::CharacterControllerComponent>();
Nuake::CharacterControllerComponent* componentPtr = componentInstance.try_cast<Nuake::CharacterControllerComponent>();
if (componentPtr == nullptr)
{
return;
}
Nuake::CharacterControllerComponent& component = *componentPtr;
BeginComponentTable(CHARACTER CONTROLLER, Nuake::CharacterControllerComponent);
{
{

View File

@@ -93,5 +93,7 @@ ImGui::Text(##name);
class ComponentPanel {
public:
virtual void Draw(Nuake::Entity entity) = 0;
};
virtual void Draw(Nuake::Entity entity);
};
inline void ComponentPanel::Draw(Nuake::Entity entity) {}

View File

@@ -3,48 +3,47 @@
#include <src/Scene/Components/CylinderColliderComponent.h>
class CylinderColliderPanel : ComponentPanel
class CylinderColliderPanel
{
public:
CylinderColliderPanel() = default;
void Draw(Nuake::Entity entity) override
static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance)
{
using namespace Nuake;
if (!entity.HasComponent<CylinderColliderComponent>())
Nuake::CylinderColliderComponent* componentPtr = componentInstance.try_cast<Nuake::CylinderColliderComponent>();
if (componentPtr == nullptr)
{
return;
}
auto& [Cylinder, Radius, Height, IsTrigger] = entity.GetComponent<CylinderColliderComponent>();
Nuake::CylinderColliderComponent& component = *componentPtr;
BeginComponentTable(CYLINDER COLLIDER, CylinderColliderComponent)
{
{
ImGui::Text("Radius");
ImGui::TableNextColumn();
ImGui::DragFloat("##Radius", &Radius, 0.01f, 0.001f);
Radius = std::max(Radius, 0.001f);
ImGui::DragFloat("##Radius", &component.Radius, 0.01f, 0.001f);
component.Radius = std::max(component.Radius, 0.001f);
ImGui::TableNextColumn();
ComponentTableReset(Radius, 0.5f)
ComponentTableReset(component.Radius, 0.5f)
}
ImGui::TableNextColumn();
{
ImGui::Text("Height");
ImGui::TableNextColumn();
ImGui::DragFloat("##Height", &Height, 0.01f, 0.0001f);
Height = std::max(Height, 0.001f);
ImGui::DragFloat("##Height", &component.Height, 0.01f, 0.0001f);
component.Height = std::max(component.Height, 0.001f);
ImGui::TableNextColumn();
ComponentTableReset(Height, 1.0f)
ComponentTableReset(component.Height, 1.0f)
}
ImGui::TableNextColumn();
{
ImGui::Text("Is Trigger");
ImGui::TableNextColumn();
ImGui::Checkbox("##isTrigger", &IsTrigger);
ImGui::Checkbox("##isTrigger", &component.IsTrigger);
ImGui::TableNextColumn();
ComponentTableReset(IsTrigger, false);
ComponentTableReset(component.IsTrigger, false);
}
}
EndComponentTable()

View File

@@ -2,17 +2,18 @@
#include "ComponentPanel.h"
#include "src/Scene/Components/LightComponent.h"
class LightPanel :ComponentPanel {
class LightPanel
{
public:
LightPanel() { }
void Draw(Nuake::Entity entity) override
static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance)
{
if (!entity.HasComponent<Nuake::LightComponent>())
return;
Nuake::LightComponent& component = entity.GetComponent<Nuake::LightComponent>();
Nuake::LightComponent* componentPtr = componentInstance.try_cast<Nuake::LightComponent>();
if (componentPtr == nullptr)
{
return;
}
Nuake::LightComponent& component = *componentPtr;
BeginComponentTable(LIGHT, Nuake::LightComponent);
{

View File

@@ -9,23 +9,25 @@
#include <src/Resource/ResourceLoader.h>
#include <src/Core/String.h>
class MeshColliderPanel : ComponentPanel {
private:
Scope<ModelResourceInspector> _modelInspector;
bool _expanded = false;
class MeshColliderPanel : ComponentPanel
{
public:
MeshColliderPanel()
{
CreateScope<ModelResourceInspector>();
}
void Draw(Nuake::Entity entity) override
static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance)
{
using namespace Nuake;
if (!entity.HasComponent<MeshColliderComponent>())
Nuake::MeshColliderComponent* componentPtr = componentInstance.try_cast<Nuake::MeshColliderComponent>();
if (componentPtr == nullptr)
{
return;
MeshColliderComponent& component = entity.GetComponent<MeshColliderComponent>();
}
Nuake::MeshColliderComponent& component = *componentPtr;
BeginComponentTable(MESH, MeshColliderComponent);
{
ImGui::Text("Model");

View File

@@ -26,13 +26,17 @@ public:
CreateScope<ModelResourceInspector>();
}
void Draw(Nuake::Entity entity) override
void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance)
{
using namespace Nuake;
if (!entity.HasComponent<ModelComponent>())
Nuake::ModelComponent* componentPtr = componentInstance.try_cast<Nuake::ModelComponent>();
if (componentPtr == nullptr)
{
return;
ModelComponent& component = entity.GetComponent<ModelComponent>();
}
Nuake::ModelComponent& component = *componentPtr;
BeginComponentTable(MESH, ModelComponent);
{
ImGui::Text("Model");

View File

@@ -3,24 +3,25 @@
#include <src/Scene/Entities/ImGuiHelper.h>
#include <src/Scene/Components/NavMeshVolumeComponent.h>
#include "src/AI/NavManager.h"
#include "src/Scene/Components/QuakeMap.h"
#include <src/Core/Maths.h>
#include <src/AI/RecastConfig.h>
class NavMeshVolumePanel : ComponentPanel {
class NavMeshVolumePanel
{
public:
NavMeshVolumePanel() {}
void Draw(Nuake::Entity entity) override
static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance)
{
using namespace Nuake;
if (!entity.HasComponent<NavMeshVolumeComponent>())
Nuake::NavMeshVolumeComponent* componentPtr = componentInstance.try_cast<Nuake::NavMeshVolumeComponent>();
if (componentPtr == nullptr)
{
return;
}
auto& component = entity.GetComponent<NavMeshVolumeComponent>();
Nuake::NavMeshVolumeComponent& component = *componentPtr;
BeginComponentTable(NAVMESH VOLUME, NavMeshVolumeComponent);
{
{
@@ -384,4 +385,4 @@ public:
}
EndComponentTable();
}
};
};

View File

@@ -8,13 +8,50 @@
#include <src/Scene/Components/NetScriptComponent.h>
#include <src/Scene/Entities/ImGuiHelper.h>
const std::string NET_TEMPLATE_SCRIPT_FIRST = R"(using Nuake.Net;
void NetScriptPanel::Draw(Nuake::Entity entity)
namespace NuakeShowcase
{
if (!entity.HasComponent<Nuake::NetScriptComponent>())
return;
class )";
auto& component = entity.GetComponent<Nuake::NetScriptComponent>();
const std::string NET_TEMPLATE_SCRIPT_SECOND = R"( : Entity
{
public override void OnInit()
{
// Called once at the start of the game
}
public override void OnUpdate(float dt)
{
// Called every frame
}
public override void OnFixedUpdate(float dt)
{
// Called every fixed update
}
public override void OnDestroy()
{
// Called at the end of the game fixed update
}
}
}
)";
void NetScriptPanel::Draw(Nuake::Entity& entity, entt::meta_any& componentInstance)
{
using namespace Nuake;
Nuake::NetScriptComponent* componentPtr = componentInstance.try_cast<Nuake::NetScriptComponent>();
if (componentPtr == nullptr)
{
return;
}
Nuake::NetScriptComponent& component = *componentPtr;
BeginComponentTable(.NETSCRIPT, Nuake::NetScriptComponent);
{
{

View File

@@ -1,45 +1,9 @@
#pragma once
#include "ComponentPanel.h"
const std::string NET_TEMPLATE_SCRIPT_FIRST = R"(using Nuake.Net;
namespace NuakeShowcase
class NetScriptPanel
{
class )";
const std::string NET_TEMPLATE_SCRIPT_SECOND = R"( : Entity
{
public override void OnInit()
{
// Called once at the start of the game
}
public override void OnUpdate(float dt)
{
// Called every frame
}
public override void OnFixedUpdate(float dt)
{
// Called every fixed update
}
public override void OnDestroy()
{
// Called at the end of the game fixed update
}
}
}
)";
class NetScriptPanel : ComponentPanel {
public:
NetScriptPanel() {}
void Draw(Nuake::Entity entity) override;
static void Draw(Nuake::Entity& entity, entt::meta_any& componentInstance);
};

View File

@@ -1,155 +0,0 @@
#pragma once
#include "ComponentPanel.h"
#include "src/FileSystem/FileSystem.h"
#include <src/Core/Maths.h>
#include <src/Scene/Components/ParticleEmitterComponent.h>
#include <src/Scene/Entities/ImGuiHelper.h>
#include "MaterialEditor.h"
#include <src/Resource/ResourceLoader.h>
#include <src/Resource/ResourceLoader.h>
class ParticleEmitterPanel : ComponentPanel
{
public:
Scope<ModelResourceInspector> _modelInspector;
ParticleEmitterPanel() {}
void Draw(Nuake::Entity entity) override
{
if (!entity.HasComponent<Nuake::ParticleEmitterComponent>())
return;
auto& component = entity.GetComponent<Nuake::ParticleEmitterComponent>();
BeginComponentTable(PARTICLE EMITTER, Nuake::ParticleEmitterComponent);
{
{
ImGui::Text("Particle Material");
ImGui::TableNextColumn();
std::string label = "Empty";
if (component.ParticleMaterial && !component.ParticleMaterial->Path.empty())
{
label = component.ParticleMaterial->Path;
}
if (ImGui::Button(label.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)))
{
}
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Material"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 256);
fullPath = Nuake::FileSystem::AbsoluteToRelative(fullPath);
Ref<Nuake::Material> material = Nuake::ResourceLoader::LoadMaterial(fullPath);
component.ParticleMaterial = material;
}
ImGui::EndDragDropTarget();
}
//std::string childId = "materialEditorParticle";
//ImGui::BeginChild(childId.c_str(), ImVec2(0, 0), false);
//{
// MaterialEditor editor;
// editor.Draw(component.ParticleMaterial);
//}
//ImGui::EndChild();
ImGui::TableNextColumn();
//ComponentTableReset(component.ParticleColor, Nuake::Vector4(1, 1, 1, 1));
}
ImGui::TableNextColumn();
{
ImGui::Text("Amount");
ImGui::TableNextColumn();
ImGui::DragFloat("##ParticleAmount", &component.Amount, 0.1f, 0.0f, 500.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Amount, 10.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Particle Scale");
ImGui::TableNextColumn();
ImGuiHelper::DrawVec3("##particleSize", &component.ParticleScale);
ImGui::TableNextColumn();
ComponentTableReset(component.ParticleScale, Nuake::Vector3(0.1, 0.1, 0.1));
}
ImGui::TableNextColumn();
{
ImGui::Text("Particle Scale Random");
ImGui::TableNextColumn();
ImGui::DragFloat("##particleSizeRandom", &component.ScaleRandomness, 0.01f, 0.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.ScaleRandomness, 0.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Global Space");
ImGui::TableNextColumn();
ImGui::Checkbox("##globalSpace", &component.GlobalSpace);
ImGui::TableNextColumn();
ComponentTableReset(component.GlobalSpace, false);
}
ImGui::TableNextColumn();
{
ImGui::Text("Rate");
ImGui::TableNextColumn();
ImGui::DragFloat("##ParticleRate", &component.Rate, 0.1f, 0.0f, 10.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Rate, 0.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Life");
ImGui::TableNextColumn();
ImGui::DragFloat("##ParticleLife", &component.Life, 0.1f, 0.0f, 100.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Life, 5.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Gravity");
ImGui::TableNextColumn();
ImGuiHelper::DrawVec3("Gravity", &component.Gravity);
ImGui::TableNextColumn();
ComponentTableReset(component.Gravity, Nuake::Vector3(0, -1, 0));
}
ImGui::TableNextColumn();
{
ImGui::Text("Gravity Random");
ImGui::TableNextColumn();
ImGui::DragFloat("##GravityRandom", &component.GravityRandom, 0.01f, 0.0f, 1.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.GravityRandom, 0.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Radius");
ImGui::TableNextColumn();
ImGui::DragFloat("##ParticleRadius", &component.Radius, 0.01f, 0.0f, 10.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Radius, 1.0f);
}
}
EndComponentTable();
}
};

View File

@@ -1,79 +0,0 @@
#pragma once
#include "ComponentPanel.h"
#include <src/Scene/Components/QuakeMap.h>
#include "src/Scene/Systems/QuakeMapBuilder.h"
#include "src/FileSystem/FileSystem.h"
#include <src/AI/NavManager.h>
#include <src/UI/ImUI.h>
class QuakeMapPanel : ComponentPanel {
public:
QuakeMapPanel() {}
void Draw(Nuake::Entity entity) override
{
using namespace Nuake;
if (!entity.HasComponent<Nuake::QuakeMapComponent>())
return;
Nuake::QuakeMapComponent& component = entity.GetComponent<Nuake::QuakeMapComponent>();
BeginComponentTable(QUAKEMAP, Nuake::QuakeMapComponent);
{
{
ImGui::Text("Map");
ImGui::TableNextColumn();
std::string path = component.Path;
ImGui::Button(component.Path.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0));
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Map"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 256);
path = Nuake::FileSystem::AbsoluteToRelative(fullPath);
component.Path = path;
}
ImGui::EndDragDropTarget();
}
ImGui::TableNextColumn();
ComponentTableReset(component.Path, "");
}
ImGui::TableNextColumn();
{
ImGui::Text("Collision");
ImGui::TableNextColumn();
ImGui::Checkbox("##Collison", &component.HasCollisions);
ImGui::TableNextColumn();
ComponentTableReset(component.HasCollisions, true);
}
ImGui::TableNextColumn();
{
ImGui::Text("Auto Rebuild");
ImGui::TableNextColumn();
ImGui::Checkbox("##AutoRebuild", &component.AutoRebuild);
ImGui::TableNextColumn();
ComponentTableReset(component.AutoRebuild, false);
}
ImGui::TableNextColumn();
{
ImGui::Text("Build");
ImGui::TableNextColumn();
if (UI::SecondaryButton("Build Geometry"))
{
Nuake::QuakeMapBuilder builder;
builder.BuildQuakeMap(entity, component.HasCollisions);
}
}
}
EndComponentTable();
}
};

View File

@@ -1,62 +0,0 @@
#pragma once
#include "ComponentPanel.h"
#include <src/Scene/Components/RigidbodyComponent.h>
#include "src/FileSystem/FileSystem.h"
class RigidbodyPanel : ComponentPanel {
public:
RigidbodyPanel() {}
void Draw(Nuake::Entity entity) override
{
if (!entity.HasComponent<Nuake::RigidBodyComponent>())
return;
auto& component = entity.GetComponent<Nuake::RigidBodyComponent>();
BeginComponentTable(RIGIDBODY, Nuake::RigidBodyComponent);
{
{
ImGui::Text("Mass");
ImGui::TableNextColumn();
ImGui::DragFloat("##Mass", &component.Mass, 0.01f, 0.1f);
component.Mass = std::max(component.Mass, 0.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Mass, 0.0f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Lock X axis");
ImGui::TableNextColumn();
ImGui::Checkbox("##lockx", &component.LockX);
ImGui::TableNextColumn();
ComponentTableReset(component.LockX, false);
}
ImGui::TableNextColumn();
{
ImGui::Text("Lock Y axis");
ImGui::TableNextColumn();
ImGui::Checkbox("##locky", &component.LockY);
ImGui::TableNextColumn();
ComponentTableReset(component.LockY, false);
}
ImGui::TableNextColumn();
{
ImGui::Text("Lock Z axis");
ImGui::TableNextColumn();
ImGui::Checkbox("##lockz", &component.LockZ);
ImGui::TableNextColumn();
ComponentTableReset(component.LockZ, false);
}
ImGui::TableNextColumn();
}
EndComponentTable();
}
};

View File

@@ -1,115 +0,0 @@
#include "ScriptPanel.h"
#include "../Windows/FileSystemUI.h"
#include <src/Scene/Components/WrenScriptComponent.h>
#include "src/FileSystem/FileDialog.h"
#include "src/FileSystem/FileSystem.h"
void ScriptPanel::Draw(Nuake::Entity entity)
{
if (!entity.HasComponent<Nuake::WrenScriptComponent>())
return;
Nuake::WrenScriptComponent& component = entity.GetComponent<Nuake::WrenScriptComponent>();
BeginComponentTable(SCRIPT, Nuake::WrenScriptComponent);
{
{
ImGui::Text("Script");
ImGui::TableNextColumn();
std::string path = component.Script;
ImGui::Button( path.empty() ? "Create New" : component.Script.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0));
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Script"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 512);
path = Nuake::FileSystem::AbsoluteToRelative(std::move(fullPath));
component.LoadScript(path);
}
ImGui::EndDragDropTarget();
}
component.Script = path;
// Double click on file
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0))
{
if(!component.Script.empty())
{
if (component.mWrenScript)
{
Nuake::OS::OpenIn(component.mWrenScript->GetFile()->GetAbsolutePath());
}
}
else
{
// TODO: Turn into command (Undo/Redo)
std::string pathCreation = Nuake::FileDialog::SaveFile("*.wren");
if (!pathCreation.empty())
{
if (!Nuake::String::EndsWith(pathCreation, ".wren"))
{
pathCreation += ".wren";
}
std::string fileName = Nuake::String::ToUpper(Nuake::FileSystem::GetFileNameFromPath(pathCreation));
fileName = Nuake::String::RemoveWhiteSpace(fileName);
if(!Nuake::String::IsDigit(fileName[0]))
{
Nuake::FileSystem::BeginWriteFile(pathCreation);
Nuake::FileSystem::WriteLine(TEMPLATE_SCRIPT_FIRST + fileName + TEMPLATE_SCRIPT_SECOND);
Nuake::FileSystem::EndWriteFile();
path = Nuake::FileSystem::AbsoluteToRelative(pathCreation);
Nuake::FileSystem::Scan();
Nuake::FileSystemUI::m_CurrentDirectory = Nuake::FileSystem::RootDirectory;
component.LoadScript(path);
component.Script = path;
}
else
{
Nuake::Logger::Log("Cannot create script files that starts with a number.","fileSystem", Nuake::CRITICAL);
}
}
}
}
ImGui::TableNextColumn();
ComponentTableReset(component.Script, "");
}
ImGui::TableNextColumn();
{
ImGui::Text("Module");
ImGui::TableNextColumn();
// Here we create a dropdown for every modules
auto& wrenScript = component.mWrenScript;
if (wrenScript)
{
auto modules = wrenScript->GetModules();
std::vector<const char*> modulesC;
for (auto& m : modules)
{
modulesC.push_back(m.c_str());
}
static int currentModule = (int)component.mModule;
ImGui::Combo("##WrenModule", &currentModule, &modulesC[0], modules.size());
component.mModule = currentModule;
}
ImGui::TableNextColumn();
//ComponentTableReset(component.Class, "");
}
}
EndComponentTable();
}

View File

@@ -1,43 +0,0 @@
#pragma once
#include "ComponentPanel.h"
const std::string TEMPLATE_SCRIPT_FIRST = R"(import "Nuake:Engine" for Engine
import "Nuake:ScriptableEntity" for ScriptableEntity
import "Nuake:Input" for Input
import "Nuake:Math" for Vector3, Math
import "Nuake:Scene" for Scene
class )";
const std::string TEMPLATE_SCRIPT_SECOND = R"( is ScriptableEntity {
construct new() {
}
// Called when the scene gets initialized
init() {
// Engine.Log("Hello World!")
}
// Called every update
update(ts) {
}
// Called 90 times per second
fixedUpdate(ts) {
}
// Called on shutdown
exit() {
}
}
)";
class ScriptPanel : ComponentPanel {
public:
ScriptPanel() {}
void Draw(Nuake::Entity entity) override;
};

View File

@@ -1,172 +0,0 @@
#pragma once
#include <src/Core/Core.h>
#include "ComponentPanel.h"
#include "ModelResourceInspector.h"
#include <src/Scene/Entities/ImGuiHelper.h>
#include <src/Scene/Components/SkinnedModelComponent.h>
#include <src/Resource/ResourceLoader.h>
#include <src/Core/String.h>
class SkinnedModelPanel : ComponentPanel
{
private:
Scope<ModelResourceInspector> m_ModelInspector;
bool m_Expanded = false;
std::string m_QueuedModelPath;
public:
SkinnedModelPanel()
{
CreateScope<ModelResourceInspector>();
}
void Draw(Nuake::Entity entity) override
{
using namespace Nuake;
if (!entity.HasComponent<SkinnedModelComponent>())
return;
SkinnedModelComponent& component = entity.GetComponent<SkinnedModelComponent>();
BeginComponentTable(SKINNED MESH, SkinnedModelComponent);
{
ImGui::Text("Model");
ImGui::TableNextColumn();
std::string label = "None";
const bool isModelNone = component.ModelResource == nullptr;
if (!isModelNone)
{
label = std::to_string(component.ModelResource->ID);
}
if (ImGui::Button(label.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)))
{
}
if (m_Expanded)
{
m_ModelInspector->Draw();
}
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Model"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 256);
fullPath = Nuake::FileSystem::AbsoluteToRelative(fullPath);
if (Nuake::String::EndsWith(fullPath, ".model"))
{
}
else
{
m_QueuedModelPath = fullPath;
ImGui::OpenPopup("Create Skeleton");
}
}
ImGui::EndDragDropTarget();
}
if (ImGui::BeginPopupModal("Create Skeleton", NULL, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::SetItemDefaultFocus();
ImGui::Text("Would you like to create the skeleton structure in the scene tree?");
ImGui::Separator();
if (ImGui::Button("OK", ImVec2(120, 0)))
{
component.ModelPath = m_QueuedModelPath;
component.LoadModel();
Scene* scene = entity.GetScene();
scene->CreateSkeleton(entity);
ImGui::CloseCurrentPopup();
}
ImGui::SetItemDefaultFocus();
ImGui::SameLine();
if (ImGui::Button("Cancel", ImVec2(120, 0)))
{
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
ImGui::TableNextColumn();
ComponentTableReset(component.ModelPath, "");
if (component.ModelResource)
{
auto& model = component.ModelResource;
ImGui::TableNextColumn();
{
ImGui::Text("Playing");
ImGui::TableNextColumn();
ImGui::Checkbox("##playing", &model->IsPlaying);
ImGui::TableNextColumn();
ComponentTableReset(model->IsPlaying, true);
ImGui::TableNextColumn();
}
if(model->GetCurrentAnimation())
{
ImGui::Text("Animation");
ImGui::TableNextColumn();
uint32_t animIndex = model->GetCurrentAnimationIndex();
uint32_t oldAnimIndex = animIndex;
auto animations = model->GetAnimations();
if (ImGui::BeginCombo("Type", model->GetCurrentAnimation()->GetName().c_str()))
{
for (uint32_t n = 0; n < model->GetAnimationsCount(); n++)
{
bool is_selected = (animIndex == n);
std::string animName = animations[n]->GetName();
if (animName.empty())
{
animName = "Empty";
}
if (ImGui::Selectable(animName.c_str(), is_selected))
{
animIndex = n;
}
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
if (animIndex != oldAnimIndex)
{
model->PlayAnimation(animIndex);
}
ImGui::TableNextColumn();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0));
std::string resetLabel = std::string(ICON_FA_UNDO) + "##ResetAnimId";
if (ImGui::Button(resetLabel.c_str()))
{
model->PlayAnimation(0);
}
ImGui::PopStyleColor();
}
}
}
EndComponentTable();
}
};

View File

@@ -1,40 +0,0 @@
#pragma once
#include "ComponentPanel.h"
#include <src/Scene/Components/SphereCollider.h>
#include "src/FileSystem/FileSystem.h"
#include <src/Scene/Entities/ImGuiHelper.h>
class SphereColliderPanel : ComponentPanel {
public:
SphereColliderPanel() {}
void Draw(Nuake::Entity entity) override
{
if (!entity.HasComponent<Nuake::SphereColliderComponent>())
return;
auto& component = entity.GetComponent<Nuake::SphereColliderComponent>();
BeginComponentTable(SPHERE COLLIDER, Nuake::SphereColliderComponent);
{
{
ImGui::Text("Size");
ImGui::TableNextColumn();
ImGui::DragFloat("##Radius", &component.Radius, 0.01f, 0.001f);
component.Radius = std::max(component.Radius, 0.001f);
ImGui::TableNextColumn();
ComponentTableReset(component.Radius, 0.5f);
}
ImGui::TableNextColumn();
{
ImGui::Text("Is Trigger");
ImGui::TableNextColumn();
ImGui::Checkbox("##isTrigger", &component.IsTrigger);
ImGui::TableNextColumn();
ComponentTableReset(component.IsTrigger, false);
}
}
EndComponentTable();
}
};

View File

@@ -1,89 +0,0 @@
#pragma once
#include "ComponentPanel.h"
#include "src/FileSystem/FileSystem.h"
#include <src/Core/Maths.h>
#include <src/Scene/Components/SpriteComponent.h>
#include <src/Scene/Entities/ImGuiHelper.h>
class SpritePanel : ComponentPanel
{
public:
SpritePanel() = default;
~SpritePanel() = default;
void Draw(Nuake::Entity entity) override
{
if (!entity.HasComponent<Nuake::SpriteComponent>())
{
return;
}
auto& component = entity.GetComponent<Nuake::SpriteComponent>();
BeginComponentTable(SPRITE, Nuake::SpriteComponent);
{
{
ImGui::Text("Sprite");
ImGui::TableNextColumn();
std::string path = component.SpritePath;
ImGui::Button(path.empty() ? "Drag image" : component.SpritePath.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0));
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Image"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 512);
path = Nuake::FileSystem::AbsoluteToRelative(std::move(fullPath));
component.SpritePath = path;
component.LoadSprite();
}
ImGui::EndDragDropTarget();
}
ImGui::TableNextColumn();
ComponentTableReset(component.LockYRotation, false);
}
ImGui::TableNextColumn();
{
ImGui::Text("Billboard");
ImGui::TableNextColumn();
ImGui::Checkbox("##billboard", &component.Billboard);
ImGui::TableNextColumn();
ComponentTableReset(component.Billboard, false);
}
ImGui::TableNextColumn();
{
ImGui::Text("Lock Y rotation");
ImGui::TableNextColumn();
ImGui::Checkbox("##lockYRotation", &component.LockYRotation);
ImGui::TableNextColumn();
ComponentTableReset(component.LockYRotation, false);
}
ImGui::TableNextColumn();
{
ImGui::Text("Position Based");
if (ImGui::BeginItemTooltip())
{
ImGui::Text("Orientation is based on the position of the camera or the orientation of the camera.");
ImGui::EndTooltip();
}
ImGui::TableNextColumn();
ImGui::Checkbox("##positionbased", &component.PositionFacing);
ImGui::TableNextColumn();
ComponentTableReset(component.LockYRotation, false);
}
}
EndComponentTable();
}
};

View File

@@ -1,61 +0,0 @@
#pragma once
#include "ComponentPanel.h"
#include "src/FileSystem/FileSystem.h"
#include <src/Core/Maths.h>
#include <src/Scene/Components/UIComponent.h>
#include <src/Scene/Entities/ImGuiHelper.h>
class UIPanel : ComponentPanel
{
public:
UIPanel() = default;
~UIPanel() = default;
void Draw(Nuake::Entity entity) override
{
using namespace Nuake;
if (!entity.HasComponent<UIComponent>())
return;
auto& component = entity.GetComponent<UIComponent>();
BeginComponentTable(UI EMITTER, UIComponent);
{
{
ImGui::Text("HTML File");
ImGui::TableNextColumn();
std::string path = component.UIFilePath;
ImGui::Button(component.UIFilePath.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0));
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_UIFile"))
{
char* file = (char*)payload->Data;
std::string fullPath = std::string(file, 256);
path = Nuake::FileSystem::AbsoluteToRelative(fullPath);
component.UIFilePath = path;
}
ImGui::EndDragDropTarget();
}
ImGui::TableNextColumn();
ComponentTableReset(component.UIFilePath, "");
}
ImGui::TableNextColumn();
{
ImGui::Text("Worldspace");
ImGui::TableNextColumn();
ImGui::Checkbox("##WorldSpace", &component.IsWorldSpace);
ImGui::TableNextColumn();
ComponentTableReset(component.IsWorldSpace, false);
}
}
EndComponentTable();
}
};

View File

@@ -8,6 +8,7 @@
#include <src/Scene/Components/SphereCollider.h>
#include <src/Scene/Components/CharacterControllerComponent.h>
#include <src/Scene/Components/BoxCollider.h>
#include "src/Scene/Components/RigidbodyComponent.h"
#include <src/Resource/ModelLoader.h>
#include <src/Rendering/RenderList.h>
@@ -26,7 +27,6 @@
#include <DetourDebugDraw.h>
#include <src/Scene/Components/BSPBrushComponent.h>
GizmoDrawer::GizmoDrawer(EditorInterface* editor)
{
m_LineShader = Nuake::ShaderManager::GetShader("Resources/Shaders/line.shader");

View File

@@ -3,6 +3,10 @@
#include "EditorSelectionPanel.h"
#include "../Misc/ImGuiTextHelper.h"
#include <src/Scene/Components.h>
#include "src/Scene/Components/FieldTypes.h"
#include "../ComponentsPanel/MaterialEditor.h"
#include "../ComponentsPanel/BoxColliderPanel.h"
#include <src/Rendering/Textures/Material.h>
#include <src/Resource/ResourceLoader.h>
@@ -15,6 +19,8 @@
#include <entt/entt.hpp>
#include "Tracy.hpp"
using namespace Nuake;
EditorSelectionPanel::EditorSelectionPanel()
@@ -22,6 +28,24 @@ EditorSelectionPanel::EditorSelectionPanel()
virtualScene = CreateRef<Scene>();
virtualScene->SetName("Virtual Scene");
virtualScene->CreateEntity("Camera").AddComponent<CameraComponent>();
RegisterComponentDrawer<LightComponent, &LightPanel::Draw>();
RegisterComponentDrawer<ModelComponent, &MeshPanel::Draw>(&meshPanel);
RegisterComponentDrawer<CameraComponent, &CameraPanel::Draw>();
RegisterComponentDrawer<MeshColliderComponent, &MeshColliderPanel::Draw>();
RegisterComponentDrawer<CapsuleColliderComponent, &CapsuleColliderPanel::Draw>();
RegisterComponentDrawer<NetScriptComponent, &NetScriptPanel::Draw>();
RegisterComponentDrawer<CylinderColliderComponent, &CylinderColliderPanel::Draw>();
RegisterComponentDrawer<CharacterControllerComponent, &CharacterControllerPanel::Draw>();
RegisterComponentDrawer<BoneComponent, &BonePanel::Draw>();
RegisterComponentDrawer<NavMeshVolumeComponent, &NavMeshVolumePanel::Draw>();
RegisterTypeDrawer<bool, &EditorSelectionPanel::DrawFieldTypeBool>(this);
RegisterTypeDrawer<float, &EditorSelectionPanel::DrawFieldTypeFloat>(this);
RegisterTypeDrawer<Vector3, &EditorSelectionPanel::DrawFieldTypeVector3>(this);
RegisterTypeDrawer<std::string, &EditorSelectionPanel::DrawFieldTypeString>(this);
RegisterTypeDrawer<ResourceFile, &EditorSelectionPanel::DrawFieldTypeResourceFile>(this);
RegisterTypeDrawer<DynamicItemList, &EditorSelectionPanel::DrawFieldTypeDynamicItemList>(this);
}
void EditorSelectionPanel::ResolveFile(Ref<Nuake::File> file)
@@ -110,6 +134,8 @@ void EditorSelectionPanel::DrawNone()
void EditorSelectionPanel::DrawEntity(Nuake::Entity entity)
{
ZoneScoped;
if (!entity.IsValid())
{
return;
@@ -117,28 +143,29 @@ void EditorSelectionPanel::DrawEntity(Nuake::Entity entity)
DrawAddComponentMenu(entity);
// Draw each component properties panels.
mTransformPanel.Draw(entity);
mLightPanel.Draw(entity);
mScriptPanel.Draw(entity);
mNetScriptPanel.Draw(entity);
mAudioEmitterPanel.Draw(entity);
mParticleEmitterPanel.Draw(entity);
mSpritePanel.Draw(entity);
mMeshPanel.Draw(entity);
mSkinnedModelPanel.Draw(entity);
mBonePanel.Draw(entity);
mQuakeMapPanel.Draw(entity);
mCameraPanel.Draw(entity);
mRigidbodyPanel.Draw(entity);
mBoxColliderPanel.Draw(entity);
mSphereColliderPanel.Draw(entity);
mCapsuleColliderPanel.Draw(entity);
mCylinderColliderPanel.Draw(entity);
mMeshColliderPanel.Draw(entity);
mCharacterControllerPanel.Draw(entity);
mNavMeshVolumePanel.Draw(entity);
mUiPanel.Draw(entity);
mTransformPanel.Draw(entity);
entt::registry& registry = entity.GetScene()->m_Registry;
for (auto&& [componentTypeId, storage] : registry.storage())
{
entt::type_info componentType = storage.type();
entt::entity entityId = static_cast<entt::entity>(entity.GetHandle());
if (storage.contains(entityId))
{
entt::meta_type type = entt::resolve(componentType);
entt::meta_any component = type.from_void(storage.value(entityId));
ComponentTypeTrait typeTraits = type.traits<ComponentTypeTrait>();
// Component not exposed as an inspector panel
if ((typeTraits & ComponentTypeTrait::InspectorExposed) == ComponentTypeTrait::None)
{
continue;
}
DrawComponent(entity, component);
}
}
using namespace Nuake;
@@ -154,16 +181,12 @@ void EditorSelectionPanel::DrawEntity(Nuake::Entity entity)
if (ImGui::BeginPopup("ComponentPopup"))
{
for(entt::meta_type t : entt::resolve())
for(auto [fst, component] : entt::resolve())
{
if (entt::meta_func func = t.func(HashedFnName::GetComponentName))
std::string componentName = Component::GetName(component);
if (ImGui::MenuItem(componentName.c_str()))
{
entt::meta_any ret = func.invoke(t);
std::string className = ret.cast<std::string>();
if (ImGui::MenuItem(className.c_str()))
{
entity.AddComponent(t);
}
entity.AddComponent(component);
}
}
@@ -511,3 +534,343 @@ void EditorSelectionPanel::DrawNetScriptPanel(Ref<Nuake::File> file)
ImGui::PopTextWrapPos();
}
void EditorSelectionPanel::DrawComponent(Nuake::Entity& entity, entt::meta_any& component)
{
ZoneScoped;
// Call into custom component drawer if one is available for this component
const auto componentIdHash = component.type().info().hash();
if (ComponentTypeDrawers.contains(componentIdHash))
{
const auto drawerFn = ComponentTypeDrawers[componentIdHash];
drawerFn(entity, component);
return;
}
const entt::meta_type componentMeta = component.type();
const std::string componentName = Component::GetName(componentMeta);
UIFont* boldFont = new UIFont(Fonts::Bold);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 0.f));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 8.f));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f);
bool removed = false;
bool headerOpened = ImGui::CollapsingHeader(componentName.c_str(), ImGuiTreeNodeFlags_DefaultOpen);
ImGui::PopStyleVar();
if (strcmp(componentName.c_str(), "TRANSFORM") != 0 && ImGui::BeginPopupContextItem())
{
if (ImGui::Selectable("Remove")) { removed = true; }
ImGui::EndPopup();
}
if(removed)
{
auto componentType = component.type();
entity.RemoveComponent(componentType);
ImGui::PopStyleVar();
delete boldFont;
}
else if (headerOpened)
{
delete boldFont;
ImGui::PopStyleVar();
ImGui::Indent();
if (ImGui::BeginTable(componentName.c_str(), 3, ImGuiTableFlags_SizingStretchProp))
{
ImGui::TableSetupColumn("name", 0, 0.25f);
ImGui::TableSetupColumn("set", 0, 0.65f);
ImGui::TableSetupColumn("reset", 0, 0.1f);
ImGui::TableNextRow();
DrawComponentContent(component);
ImGui::EndTable();
}
ImGui::Unindent();
}
else
{
ImGui::PopStyleVar();
delete boldFont;
}
ImGui::PopStyleVar();
}
void EditorSelectionPanel::DrawComponentContent(entt::meta_any& component)
{
ZoneScoped;
entt::meta_type componentMeta = component.type();
// Draw component bound data
for (auto [fst, dataType] : componentMeta.data())
{
const ComponentFieldTrait fieldTraits = dataType.traits<ComponentFieldTrait>();
// Field marked as internal and thus not exposed to the inspector
if ((fieldTraits & ComponentFieldTrait::Internal) == ComponentFieldTrait::Internal)
{
continue;
}
ImGui::TableSetColumnIndex(0);
// Search for the appropriate drawer for the type
entt::id_type dataId = dataType.type().id();
if (FieldTypeDrawers.contains(dataId))
{
auto drawerFn = FieldTypeDrawers[dataId];
drawerFn(dataType, component);
}
else
{
ImGui::Text("ERR");
}
ImGui::TableNextRow();
}
// Draw any actions bound to the component
for (auto [fst, funcMeta] : componentMeta.func())
{
const ComponentFuncTrait funcTraits = funcMeta.traits<ComponentFuncTrait>();
if ((funcTraits & ComponentFuncTrait::Action) == ComponentFuncTrait::Action)
{
ImGui::TableSetColumnIndex(0);
std::string funcDisplayName = "";
auto prop = funcMeta.prop(HashedName::DisplayName).value();
if (prop)
{
funcDisplayName = std::string(*prop.try_cast<const char*>());
}
std::string buttonName = funcDisplayName;
if (UI::SecondaryButton(buttonName.c_str()))
{
entt::meta_any result = funcMeta.invoke(component);
}
ImGui::TableNextRow();
}
}
}
void EditorSelectionPanel::DrawFieldTypeFloat(entt::meta_data& field, entt::meta_any& component)
{
float stepSize = 1.f;
if (auto prop = field.prop(HashedFieldPropName::FloatStep))
stepSize = *prop.value().try_cast<float>();
float min = 0.f;
if (auto prop = field.prop(HashedFieldPropName::FloatMin))
min = *prop.value().try_cast<float>();
float max = 0.f;
if (auto prop = field.prop(HashedFieldPropName::FloatMax))
max = *prop.value().try_cast<float>();
auto propDisplayName = field.prop(HashedName::DisplayName);
const char* displayName = *propDisplayName.value().try_cast<const char*>();
if (displayName != nullptr)
{
ImGui::Text(displayName);
ImGui::TableNextColumn();
auto fieldVal = field.get(component);
float* floatPtr = fieldVal.try_cast<float>();
if (floatPtr != nullptr)
{
float floatProxy = *floatPtr;
const std::string controlId = std::string("##") + displayName;
if (ImGui::DragFloat(controlId.c_str(), &floatProxy, stepSize, min, max))
{
field.set(component, floatProxy);
}
}
else
{
ImGui::Text("ERR");
}
}
}
void EditorSelectionPanel::DrawFieldTypeBool(entt::meta_data& field, entt::meta_any& component)
{
auto prop = field.prop(HashedName::DisplayName);
auto propVal = prop.value();
const char* displayName = *propVal.try_cast<const char*>();
if (displayName != nullptr)
{
ImGui::Text(displayName);
ImGui::TableNextColumn();
auto fieldVal = field.get(component);
bool* boolPtr = fieldVal.try_cast<bool>();
if (boolPtr != nullptr)
{
bool boolProxy = *boolPtr;
std::string controlId = std::string("##") + displayName;
if (ImGui::Checkbox(controlId.c_str(), &boolProxy))
{
field.set(component, boolProxy);
}
}
else
{
ImGui::Text("ERR");
}
}
}
void EditorSelectionPanel::DrawFieldTypeVector3(entt::meta_data& field, entt::meta_any& component)
{
auto prop = field.prop(HashedName::DisplayName);
auto propVal = prop.value();
const char* displayName = *propVal.try_cast<const char*>();
if (displayName != nullptr)
{
ImGui::Text(displayName);
ImGui::TableNextColumn();
auto fieldVal = field.get(component);
Vector3* vec3Ptr = fieldVal.try_cast<Vector3>();
std::string controlId = std::string("##") + displayName;
ImGui::PushID(controlId.c_str());
if (ImGuiHelper::DrawVec3("BoxSize", vec3Ptr, 0.5f, 100.0, 0.01f))
{
field.set(component, *vec3Ptr);
}
ImGui::PopID();
}
}
void EditorSelectionPanel::DrawFieldTypeString(entt::meta_data& field, entt::meta_any& component)
{
auto prop = field.prop(HashedName::DisplayName);
auto propVal = prop.value();
const char* displayName = *propVal.try_cast<const char*>();
if (displayName != nullptr)
{
ImGui::Text(displayName);
ImGui::TableNextColumn();
auto fieldVal = field.get(component);
std::string* fieldValPtr = fieldVal.try_cast<std::string>();
if (fieldValPtr != nullptr)
{
std::string fieldValProxy = *fieldValPtr;
std::string controlId = std::string("##") + displayName;
ImGui::InputText(controlId.c_str(), &fieldValProxy);
}
else
{
ImGui::Text("ERR");
}
}
}
void EditorSelectionPanel::DrawFieldTypeResourceFile(entt::meta_data& field, entt::meta_any& component)
{
const char* resourceRestrictedType = nullptr;
if (auto prop = field.prop(HashedFieldPropName::ResourceFileType))
resourceRestrictedType = *prop.value().try_cast<const char*>();
auto propDisplayName = field.prop(HashedName::DisplayName);
const char* displayName = *propDisplayName.value().try_cast<const char*>();
if (displayName != nullptr)
{
ImGui::Text(displayName);
ImGui::TableNextColumn();
auto fieldVal = field.get(component);
auto fieldValPtr = fieldVal.try_cast<ResourceFile>();
if (fieldValPtr != nullptr)
{
auto fieldValProxy = *fieldValPtr;
std::string filePath = fieldValProxy.file == nullptr ? "" : fieldValProxy.file->GetRelativePath();
std::string controlName = filePath + std::string("##") + displayName;
ImGui::Button(controlName.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0));
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(resourceRestrictedType))
{
const char* payloadFilePath = static_cast<char*>(payload->Data);
const std::string fullPath = std::string(payloadFilePath, 256);
const Ref<Nuake::File> file = FileSystem::GetFile(FileSystem::AbsoluteToRelative(fullPath));
field.set(component, ResourceFile{ file });
}
ImGui::EndDragDropTarget();
}
}
else
{
ImGui::Text("ERR");
}
}
}
void EditorSelectionPanel::DrawFieldTypeDynamicItemList(entt::meta_data& field, entt::meta_any& component)
{
auto propDisplayName = field.prop(HashedName::DisplayName);
const char* displayName = *propDisplayName.value().try_cast<const char*>();
if (displayName != nullptr)
{
ImGui::Text(displayName);
ImGui::TableNextColumn();
auto fieldVal = field.get(component);
auto fieldValPtr = fieldVal.try_cast<DynamicItemList>();
if (fieldValPtr == nullptr)
{
ImGui::Text("ERR");
}
const auto& items = fieldValPtr->items;
const int index = fieldValPtr->index;
// Check first to see if we are within the bounds
std::string selectedStr = "";
if (index >= 0 || index < items.size())
{
selectedStr = items[index];
}
std::string controlName = std::string("##") + displayName;
if (ImGui::BeginCombo(controlName.c_str(), selectedStr.c_str()))
{
for (int i = 0; i < items.size(); i++)
{
bool isSelected = (index == i);
std::string name = items[i];
if (name.empty())
{
name = "Empty";
}
if (ImGui::Selectable(name.c_str(), isSelected))
{
field.set(component, i);
}
if (isSelected)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
}
}

View File

@@ -7,25 +7,15 @@
#include "../ComponentsPanel/TransformPanel.h"
#include "../ComponentsPanel/LightPanel.h"
#include "../ComponentsPanel/ScriptPanel.h"
#include "../ComponentsPanel/MeshPanel.h"
#include "../ComponentsPanel/QuakeMapPanel.h"
#include "../ComponentsPanel/CameraPanel.h"
#include "../ComponentsPanel/RigidbodyPanel.h"
#include "../ComponentsPanel/BoxColliderPanel.h"
#include "../ComponentsPanel/CapsuleColliderPanel.h"
#include "../ComponentsPanel/CylinderColliderPanel.h"
#include "../ComponentsPanel/SphereColliderPanel.h"
#include "../ComponentsPanel/MeshColliderPanel.h"
#include "../ComponentsPanel/CharacterControllerPanel.h"
#include "../ComponentsPanel/SpritePanel.h"
#include "../ComponentsPanel/ParticleEmitterPanel.h"
#include "../ComponentsPanel/SkinnedModelPanel.h"
#include "../ComponentsPanel/BonePanel.h"
#include "../ComponentsPanel/AudioEmitterPanel.h"
#include "../ComponentsPanel/NetScriptPanel.h"
#include "../ComponentsPanel/NavMeshVolumePanel.h"
#include "../ComponentsPanel/UIPanel.h"
#include <src/Scene/Components/WrenScriptComponent.h>
#include <src/Resource/Prefab.h>
@@ -38,28 +28,12 @@ namespace Nuake
class EditorSelectionPanel
{
using DrawComponentTypeFn = std::function<void(Nuake::Entity& entity, entt::meta_any& componentInstance)>;
using DrawFieldTypeFn = std::function<void(entt::meta_data& fieldMeta, entt::meta_any& componentInstance)>;
private:
TransformPanel mTransformPanel;
LightPanel mLightPanel;
ScriptPanel mScriptPanel;
NetScriptPanel mNetScriptPanel;
MeshPanel mMeshPanel;
SkinnedModelPanel mSkinnedModelPanel;
QuakeMapPanel mQuakeMapPanel;
CameraPanel mCameraPanel;
RigidbodyPanel mRigidbodyPanel;
BoxColliderPanel mBoxColliderPanel;
SphereColliderPanel mSphereColliderPanel;
MeshColliderPanel mMeshColliderPanel;
CapsuleColliderPanel mCapsuleColliderPanel;
CylinderColliderPanel mCylinderColliderPanel;
SpritePanel mSpritePanel;
CharacterControllerPanel mCharacterControllerPanel;
ParticleEmitterPanel mParticleEmitterPanel;
BonePanel mBonePanel;
AudioEmitterPanel mAudioEmitterPanel;
NavMeshVolumePanel mNavMeshVolumePanel;
UIPanel mUiPanel;
MeshPanel meshPanel;
Ref<Nuake::File> currentFile;
Ref<Nuake::Resource> selectedResource;
@@ -77,10 +51,47 @@ public:
void DrawFile(Ref<Nuake::File> file);
void DrawResource(Nuake::Resource resource);
void DrawPrefabPanel(Ref<Nuake::Prefab> prefab);
template<class T, auto Func>
void RegisterComponentDrawer()
{
const auto t = entt::type_id<T>();
ComponentTypeDrawers[t.hash()] = std::bind(Func, std::placeholders::_1, std::placeholders::_2);
}
template<class T, auto Func, class O>
void RegisterComponentDrawer(O* o)
{
ComponentTypeDrawers[entt::type_id<T>().hash()] = std::bind(Func, o, std::placeholders::_1, std::placeholders::_2);
}
template<class T, auto Func, class O>
void RegisterTypeDrawer(O* o)
{
FieldTypeDrawers[entt::type_id<T>().hash()] = std::bind(Func, o, std::placeholders::_1, std::placeholders::_2);
}
protected:
// Drawing functions for each component (for writing very specific inspectors for specific components)
std::unordered_map<entt::id_type, DrawComponentTypeFn> ComponentTypeDrawers;
// List of functions to call for each component field type that needs to be drawn
std::unordered_map<entt::id_type, DrawFieldTypeFn> FieldTypeDrawers;
private:
void ResolveFile(Ref<Nuake::File> file);
void DrawMaterialPanel(Ref<Nuake::Material> material);
void DrawProjectPanel(Ref<Nuake::Project> project);
void DrawWrenScriptPanel(Ref<Nuake::WrenScript> wrenFile);
void DrawNetScriptPanel(Ref<Nuake::File> file);
void DrawComponent(Nuake::Entity& entity, entt::meta_any& component);
void DrawComponentContent(entt::meta_any& component);
void DrawFieldTypeFloat(entt::meta_data& field, entt::meta_any& component);
void DrawFieldTypeBool(entt::meta_data& field, entt::meta_any& component);
void DrawFieldTypeVector3(entt::meta_data& field, entt::meta_any& component);
void DrawFieldTypeString(entt::meta_data& field, entt::meta_any& component);
void DrawFieldTypeResourceFile(entt::meta_data& field, entt::meta_any& component);
void DrawFieldTypeDynamicItemList(entt::meta_data& field, entt::meta_any& component);
};

View File

@@ -657,36 +657,6 @@ namespace Nuake
}
}
if (ImGui::MenuItem("Wren Script"))
{
std::string path = FileDialog::SaveFile("*.wren");
if (!String::EndsWith(path, ".wren"))
{
path += ".wren";
}
if (!path.empty())
{
std::string fileName = String::ToUpper(FileSystem::GetFileNameFromPath(path));
fileName = String::RemoveWhiteSpace(fileName);
if(!String::IsDigit(fileName[0]))
{
FileSystem::BeginWriteFile(path, true);
FileSystem::WriteLine(TEMPLATE_SCRIPT_FIRST + fileName + TEMPLATE_SCRIPT_SECOND);
FileSystem::EndWriteFile();
RefreshFileBrowser();
}
else
{
Logger::Log("Cannot create script files that starts with a number.", "filesystem", CRITICAL);
}
}
}
ImGui::EndMenu();
}

View File

@@ -13,6 +13,7 @@
#include "src/Scripting/ScriptingEngine.h"
#include "src/Scripting/ScriptingEngineNet.h"
#include "src/Threading/JobSystem.h"
#include "src/Core/RegisterCoreTypes.h"
#include "src/Modules/Modules.h"
#include <GLFW/glfw3.h>
@@ -20,6 +21,8 @@
#include <imgui/imgui_impl_opengl3.h>
#include <Tracy.hpp>
namespace Nuake
{
Ref<Project> Engine::currentProject;
@@ -48,6 +51,8 @@ namespace Nuake
Renderer2D::Init();
Logger::Log("Engine initialized");
RegisterCoreTypes::RegisterCoreComponents();
Modules::StartupModules();
}

View File

@@ -0,0 +1,5 @@
#include "ClassDB.h"
namespace Nuake
{
}

View File

@@ -0,0 +1,14 @@
#pragma once
namespace Nuake
{
class ClassDB
{
public:
template<class T>
static void RegisterComponent(T klass)
{
T::InternalInitializeClass();
}
};
}

View File

@@ -1,38 +1,173 @@
#pragma once
#include <entt/entt.hpp>
#include <type_traits>
#define NK_HASHED_FN_NAME_IMPL(name) inline static constexpr entt::hashed_string name = entt::hashed_string(#name);
#define NK_HASHED_STATIC_STR(name) inline static constexpr entt::hashed_string name = entt::hashed_string(#name);
#define NK_ENUM_BITWISE_IMPL(enumClassName) \
inline enumClassName operator|(enumClassName lhs, enumClassName rhs) \
{ \
return static_cast<enumClassName>(ToUnderlying(lhs) | ToUnderlying(rhs)); \
} \
\
inline enumClassName operator&(enumClassName lhs, enumClassName rhs) \
{ \
return static_cast<enumClassName>(ToUnderlying(lhs) & ToUnderlying(rhs)); \
}
namespace Nuake
{
struct HashedFnName
{
NK_HASHED_FN_NAME_IMPL(GetComponentName)
NK_HASHED_FN_NAME_IMPL(AddToEntity)
NK_HASHED_STATIC_STR(GetComponentName)
NK_HASHED_STATIC_STR(AddToEntity)
NK_HASHED_STATIC_STR(RemoveFromEntity)
NK_HASHED_STATIC_STR(ActionName)
};
struct HashedFieldPropName
{
NK_HASHED_STATIC_STR(FloatStep)
NK_HASHED_STATIC_STR(FloatMin)
NK_HASHED_STATIC_STR(FloatMax)
NK_HASHED_STATIC_STR(ResourceFileType)
};
struct HashedName
{
NK_HASHED_STATIC_STR(DisplayName)
};
enum class ComponentTypeTrait : uint16_t
{
None = 0,
// Exposes the component to be added via the inspector
InspectorExposed = 1 << 0,
};
enum class ComponentFuncTrait : uint16_t
{
None = 0,
// Exposes the component to be added via the inspector
Action = 1 << 0,
};
enum class ComponentFieldTrait : uint16_t
{
None = 0,
// Stops field from showing up in the editor inspector
Internal = 1 << 0,
// Marks the field as temporary (ie, do not serialize)
Transient = 1 << 1,
};
template <typename Enum>
constexpr std::underlying_type_t<Enum> ToUnderlying(Enum e)
{
return static_cast<std::underlying_type_t<Enum>>(e);
}
NK_ENUM_BITWISE_IMPL(ComponentTypeTrait);
NK_ENUM_BITWISE_IMPL(ComponentFuncTrait);
NK_ENUM_BITWISE_IMPL(ComponentFieldTrait);
}
#define NUAKECOMPONENT(klass, componentName) \
public: \
static std::string ClassName() \
{ \
static std::string className = #klass; \
return className; \
} \
\
static std::string ComponentName() \
{ \
static std::string name = componentName; \
return name; \
} \
\
static void AddToEntity(entt::entity entity, entt::registry* enttRegistry) \
{ \
enttRegistry->emplace_or_replace<klass>(entity); \
} \
\
inline static auto ComponentFactory = entt::meta<klass>() \
.type(entt::hashed_string(#klass)) \
.func<&klass::ComponentName>(HashedFnName::GetComponentName) \
.func<&klass::AddToEntity>(HashedFnName::AddToEntity);
#define NUAKECOMPONENT(klass, componentName) \
public: \
static std::string ClassName() \
{ \
static std::string className = #klass; \
return className; \
} \
\
static std::string ComponentName() \
{ \
static std::string name = componentName; \
return name; \
} \
\
static void AddToEntity(entt::entity entity, entt::registry* enttRegistry) \
{ \
enttRegistry->emplace_or_replace<klass>(entity); \
} \
\
static void RemoveFromEntity(entt::entity entity, entt::registry* enttRegistry) \
{ \
enttRegistry->erase<klass>(entity); \
} \
\
\
static void (*GetInitializeComponentClass())() \
{ \
return &klass::InitializeComponentClass; \
} \
\
inline static auto ComponentFactory = entt::meta<klass>(); \
static void InternalInitializeClass() \
{ \
static bool initialized = false; \
if (initialized) \
return; \
\
ComponentFactory.type(entt::hashed_string(#klass)) \
.traits(ComponentTypeTrait::InspectorExposed); \
ComponentFactory.func<&klass::ComponentName>(HashedFnName::GetComponentName); \
ComponentFactory.func<&klass::AddToEntity>(HashedFnName::AddToEntity); \
ComponentFactory.func<&klass::RemoveFromEntity>(HashedFnName::RemoveFromEntity); \
\
if (klass::GetInitializeComponentClass() != Component::GetInitializeComponentClass()) \
{ \
GetInitializeComponentClass()(); \
} \
\
initialized = true; \
\
} \
\
template<auto Data> \
static auto BindComponentField(const char* varName, const char* displayName) \
{ \
return ComponentFactory \
.data<Data>(entt::hashed_string(varName)) \
.prop(HashedName::DisplayName, displayName); \
} \
\
template<auto Getter, auto Setter> \
static auto BindComponentProperty(const char* varName, const char* displayName) \
{ \
return ComponentFactory \
.data<Getter, Setter>(entt::hashed_string(varName)) \
.prop(HashedName::DisplayName, displayName); \
} \
\
static auto FieldFloatLimits(float stepSize, float min, float max) \
{ \
return ComponentFactory \
.prop(HashedFieldPropName::FloatStep, stepSize) \
.prop(HashedFieldPropName::FloatMin, min) \
.prop(HashedFieldPropName::FloatMax, max); \
} \
\
static auto ResourceFileRestriction(const char* fileType) \
{ \
return ComponentFactory \
.prop(HashedFieldPropName::ResourceFileType, fileType); \
} \
\
template <typename... Enums> \
static auto SetFlags(Enums... enums) \
{ \
static_assert((std::is_enum_v<Enums> && ...), "All arguments must be of enum class type"); \
return ComponentFactory.traits((enums | ...)); \
} \
\
template<auto Func> \
static void BindAction(const char* funcName, const char* actionName) \
{ \
ComponentFactory \
.func<Func>(entt::hashed_string(funcName)) \
.prop(HashedName::DisplayName, actionName); \
SetFlags(ComponentFuncTrait::Action); \
}

View File

@@ -0,0 +1,47 @@
#include "RegisterCoreTypes.h"
#include "src/Scene/Components/AudioEmitterComponent.h"
#include "src/Scene/Components/BoneComponent.h"
#include "src/Scene/Components/BoxCollider.h"
#include "src/Scene/Components/CameraComponent.h"
#include "src/Scene/Components/CapsuleColliderComponent.h"
#include "src/Scene/Components/CharacterControllerComponent.h"
#include "src/Scene/Components/CylinderColliderComponent.h"
#include "src/Scene/Components/MeshCollider.h"
#include "src/Scene/Components/ModelComponent.h"
#include "src/Scene/Components/NavMeshVolumeComponent.h"
#include "src/Scene/Components/NetScriptComponent.h"
#include "src/Scene/Components/ParticleEmitterComponent.h"
#include "src/Scene/Components/QuakeMap.h"
#include "src/Scene/Components/RigidbodyComponent.h"
#include "src/Scene/Components/SkinnedModelComponent.h"
#include "src/Scene/Components/SphereCollider.h"
#include "src/Scene/Components/SpriteComponent.h"
#include "src/Scene/Components/UIComponent.h"
namespace Nuake
{
void RegisterCoreTypes::RegisterCoreComponents()
{
UIComponent::InternalInitializeClass();
SpriteComponent::InternalInitializeClass();
SphereColliderComponent::InternalInitializeClass();
SkinnedModelComponent::InternalInitializeClass();
RigidBodyComponent::InternalInitializeClass();
QuakeMapComponent::InternalInitializeClass();
ParticleEmitterComponent::InternalInitializeClass();
NetScriptComponent::InternalInitializeClass();
NavMeshVolumeComponent::InternalInitializeClass();
ModelComponent::InternalInitializeClass();
MeshColliderComponent::InternalInitializeClass();
LightComponent::InternalInitializeClass();
CylinderColliderComponent::InternalInitializeClass();
CharacterControllerComponent::InternalInitializeClass();
CapsuleColliderComponent::InternalInitializeClass();
CameraComponent::InternalInitializeClass();
BoxColliderComponent::InternalInitializeClass();
BoneComponent::InternalInitializeClass();
AudioEmitterComponent::InternalInitializeClass();
}
}

View File

@@ -0,0 +1,11 @@
#pragma once
namespace Nuake
{
class RegisterCoreTypes
{
public:
static void RegisterCoreComponents();
};
}

View File

@@ -917,9 +917,24 @@ namespace Nuake
{
auto [transform, emitterComponent, visibility] = particleEmitterView.get<TransformComponent, ParticleEmitterComponent, VisibilityComponent>(e);
if (!visibility.Visible || !emitterComponent.ParticleMaterial)
if (!visibility.Visible)
continue;
if (emitterComponent.resFile.dirty)
{
emitterComponent.resFile.dirty = false;
if (emitterComponent.resFile.Exist())
{
Ref<Nuake::Material> material = Nuake::ResourceLoader::LoadMaterial(emitterComponent.resFile.GetRelativePath());
emitterComponent.ParticleMaterial = material;
}
}
if (emitterComponent.ParticleMaterial == nullptr)
{
continue;
}
Renderer::QuadMesh->SetMaterial(emitterComponent.ParticleMaterial);
Vector3 oldColor = Renderer::QuadMesh->GetMaterial()->data.m_AlbedoColor;

View File

@@ -1,6 +1,7 @@
#include "ResourceLoader.h"
#include "src/Core/Logger.h"
#include "src/Core/String.h"
#include "src/FileSystem/File.h"
#include "src/Resource/Resource.h"
#include "src/Resource/ResourceManager.h"
#include "src/Rendering/Textures/Material.h"
@@ -101,6 +102,16 @@ Ref<UIResource> ResourceLoader::LoadUI(const std::string& path)
return uiResource;
}
Ref<UIResource> ResourceLoader::LoadUI(const Ref<File>& file)
{
if (file == nullptr || !file->Exist())
{
return nullptr;
}
return LoadUI(file->GetRelativePath());
}
UUID ResourceLoader::ReadUUID(json j)
{
if (j.contains("UUID"))

View File

@@ -8,6 +8,7 @@ namespace Nuake
class Material;
class Model;
class UIResource;
class File;
class ResourceLoader
{
@@ -23,6 +24,7 @@ namespace Nuake
static Ref<Material> LoadMaterial(const std::string& path);
static Ref<Model> LoadModel(const std::string& path);
static Ref<UIResource> LoadUI(const std::string& path);
static Ref<UIResource> LoadUI(const Ref<File>& file);
private:
static UUID ReadUUID(json j);

View File

@@ -6,6 +6,13 @@ using json = nlohmann::json;
#define BEGIN_SERIALIZE() json j;
#define SERIALIZE_VAL_LBL(lbl, v) j[lbl] = v;
#define SERIALIZE_VAL(v) j[#v] = this->v;
#define SERIALIZE_RES_FILE(v) \
bool validFile = this->v.file != nullptr && this->v.file->Exist(); \
j["validFile"#v] = validFile; \
if (validFile) \
{ \
j["file"#v] = this->v.file->GetRelativePath(); \
}
#define SERIALIZE_VEC2(v) \
j[#v]["x"] = v.x; \
@@ -23,7 +30,17 @@ using json = nlohmann::json;
if(j.contains(#p)) \
{ \
p = j[#p]; \
}
}
#define DESERIALIZE_RES_FILE(v) \
if (j.contains("validFile"#v)) \
{ \
if (bool validFile = j["validFile"#v]) \
{ \
const std::string filePath = j["file"#v]; \
(v).file = FileSystem::GetFile(filePath); \
} \
}
#define DESERIALIZE_VEC4(v, p) \
p = Vector4(v["x"], v["y"], v["z"], v["w"]);

View File

@@ -1,7 +1,7 @@
#pragma once
#include "Components/AudioEmitterComponent.h"
#include "Components/BaseComponent.h"
#include "Components/VisibilityComponent.h"
#include "Components/BoneComponent.h"
#include "Components/BoxCollider.h"
#include "Components/BSPBrushComponent.h"

View File

@@ -1,11 +1,14 @@
#include "AudioEmitterComponent.h"
#include "src/FileSystem/File.h"
#include "src/FileSystem/FileSystem.h"
namespace Nuake {
json AudioEmitterComponent::Serialize()
{
BEGIN_SERIALIZE();
SERIALIZE_VAL(FilePath);
SERIALIZE_RES_FILE(FilePath);
SERIALIZE_VAL(IsPlaying);
SERIALIZE_VAL(Volume);
SERIALIZE_VAL(Pan);
@@ -20,7 +23,7 @@ namespace Nuake {
bool AudioEmitterComponent::Deserialize(const json& j)
{
DESERIALIZE_VAL(FilePath);
DESERIALIZE_RES_FILE(FilePath);
DESERIALIZE_VAL(Volume);
DESERIALIZE_VAL(IsPlaying);
DESERIALIZE_VAL(Pan);
@@ -32,4 +35,4 @@ namespace Nuake {
DESERIALIZE_VAL(Loop);
return true;
}
}
}

View File

@@ -1,17 +1,45 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "FieldTypes.h"
#include "src/Core/Core.h"
#include "src/Resource/Resource.h"
#include "src/Resource/Serializable.h"
namespace Nuake {
class AudioEmitterComponent
class AudioEmitterComponent : public Component
{
NUAKECOMPONENT(AudioEmitterComponent, "Audio Emitter")
static void InitializeComponentClass()
{
BindComponentField<&AudioEmitterComponent::FilePath>("FilePath", "File Path");
ResourceFileRestriction("_AudioFile");
BindComponentField<&AudioEmitterComponent::IsPlaying>("IsPlaying", "Is Playing");
BindComponentField<&AudioEmitterComponent::Loop>("Loop", "Loop");
BindComponentField<&AudioEmitterComponent::Volume>("Volume", "Volume");
FieldFloatLimits(0.001f, 0.0f, 2.0f);
BindComponentField<&AudioEmitterComponent::Pan>("Pan", "Pan");
FieldFloatLimits(0.01f, -1.0f, 1.0f);
BindComponentField<&AudioEmitterComponent::PlaybackSpeed>("PlaybackSpeed", "Playback Speed");
FieldFloatLimits(0.01f, 0.0001f, 0.f);
BindComponentField<&AudioEmitterComponent::Spatialized>("Spatialized", "Spatialized");
BindComponentField<&AudioEmitterComponent::MinDistance>("MinDistance", "Min Distance");
FieldFloatLimits(0.001f, 0.f, 0.f);
BindComponentField<&AudioEmitterComponent::MaxDistance>("MaxDistance", "Max Distance");
FieldFloatLimits(0.001f, 0.f, 0.f);
BindComponentField<&AudioEmitterComponent::AttenuationFactor>("AttenuationFactor", "Attenuation Factor");
FieldFloatLimits(0.001f, 0.f, 0.f);
}
public:
std::string FilePath;
ResourceFile FilePath;
bool IsPlaying = false;
bool Loop = false;

View File

@@ -1,4 +1,7 @@
#pragma once
#include "Component.h"
#include "src/Core/Core.h"
#include "src/Core/Maths.h"
@@ -7,7 +10,7 @@
#include "src/Physics/Rigibody.h"
namespace Nuake {
class BSPBrushComponent
class BSPBrushComponent : public Component
{
public:
//std::vector<Ref<Mesh>> Meshes;

View File

@@ -1,13 +1,13 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "src/Core/Core.h"
#include "src/Resource/Serializable.h"
namespace Nuake
{
class BoneComponent
class BoneComponent : public Component
{
NUAKECOMPONENT(BoneComponent, "Bone")

View File

@@ -1,22 +1,38 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "src/Physics/PhysicsShapes.h"
#include "src/Core/Core.h"
namespace Nuake {
namespace Nuake
{
class BoxColliderComponent : public Component
{
NUAKECOMPONENT(BoxColliderComponent, "Box Collider")
class BoxColliderComponent
{
NUAKECOMPONENT(BoxColliderComponent, "Box Collider")
static void InitializeComponentClass()
{
BindComponentField<&BoxColliderComponent::IsTrigger>("IsTrigger", "Is Trigger");
BindComponentProperty<&BoxColliderComponent::SetSize, &BoxColliderComponent::GetSize>("Size", "Size");
}
public:
Ref<Physics::PhysicShape> Box;
Vector3 Size = Vector3(0.5f, 0.5f, 0.5f);
bool IsTrigger = false;
public:
Ref<Physics::PhysicShape> Box;
Vector3 Size = Vector3(0.5f, 0.5f, 0.5f);
bool IsTrigger = true;
json Serialize();
bool Deserialize(const json& j);
};
void SetSize(const Vector3& newSize)
{
Size = newSize;
}
Vector3 GetSize()
{
return Size;
}
json Serialize();
bool Deserialize(const json& j);
};
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "TransformComponent.h"
#include "src/Core/Core.h"
@@ -10,7 +10,7 @@
namespace Nuake
{
class CameraComponent
class CameraComponent : public Component
{
NUAKECOMPONENT(CameraComponent, "Camera")

View File

@@ -1,12 +1,13 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "src/Physics/PhysicsShapes.h"
#include "src/Core/Core.h"
namespace Nuake
{
class CapsuleColliderComponent
class CapsuleColliderComponent : public Component
{
NUAKECOMPONENT(CapsuleColliderComponent, "Capsule Collider")

View File

@@ -1,11 +1,12 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "src/Physics/CharacterController.h"
namespace Nuake
{
class CharacterControllerComponent
class CharacterControllerComponent : public Component
{
NUAKECOMPONENT(CharacterControllerComponent, "Character Controller")

View File

@@ -0,0 +1,15 @@
#include "Component.h"
using namespace Nuake;
std::string Component::GetName(const entt::meta_type& componentMeta)
{
// TODO: [WiggleWizard] Needs some error handling
if (entt::meta_func func = componentMeta.func(HashedFnName::GetComponentName))
{
entt::meta_any ret = func.invoke(componentMeta);
return ret.cast<std::string>();
}
return "Unknown Component";
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "FieldTypes.h"
namespace Nuake
{
class Component
{
protected:
static void InitializeComponentClass() {}
static void (* GetInitializeComponentClass(void))()
{
return &Component::InitializeComponentClass;
}
public:
static std::string GetName(const entt::meta_type& componentMeta);
};
}

View File

@@ -1,12 +1,13 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "src/Physics/PhysicsShapes.h"
#include "src/Core/Core.h"
namespace Nuake
{
class CylinderColliderComponent
class CylinderColliderComponent : public Component
{
NUAKECOMPONENT(CylinderColliderComponent, "Cylinder Collider")

View File

@@ -0,0 +1,28 @@
#include "FieldTypes.h"
#include "src/FileSystem/File.h"
bool Nuake::ResourceFile::Exist()
{
return file != nullptr && file->Exist();
}
std::string Nuake::ResourceFile::GetRelativePath()
{
if (Exist())
{
return file->GetRelativePath();
}
return "";
}
std::string Nuake::ResourceFile::GetAbsolutePath()
{
if (Exist())
{
return file->GetAbsolutePath();
}
return "";
}

View File

@@ -0,0 +1,29 @@
#pragma once
#include <string>
#include "src/Core/Core.h"
namespace Nuake
{
class File;
struct ResourceFile
{
ResourceFile() = default;
ResourceFile(const Ref<File>& inFile) : file(inFile) {}
bool Exist();
std::string GetRelativePath();
std::string GetAbsolutePath();
Ref<File> file = nullptr;
bool dirty = true;
};
struct DynamicItemList
{
std::vector<std::string> items;
int index = -1;
};
}

View File

@@ -1,13 +1,13 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include <glm/ext/vector_float3.hpp>
#include <glm/ext/vector_float2.hpp>
#include "TransformComponent.h"
#include "../Rendering/Camera.h"
#include "src/Rendering/Buffers/Framebuffer.h"
#include "BaseComponent.h"
#include "VisibilityComponent.h"
#include "../Resource/Serializable.h"
#include <glm/ext/matrix_clip_space.hpp>
@@ -20,7 +20,7 @@ namespace Nuake
};
const int CSM_AMOUNT = 4;
class LightComponent
class LightComponent : public Component
{
NUAKECOMPONENT(LightComponent, "Light")

View File

@@ -1,11 +1,13 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "src/Physics/PhysicsShapes.h"
#include "src/Core/Core.h"
namespace Nuake {
class MeshColliderComponent
namespace Nuake
{
class MeshColliderComponent : public Component
{
NUAKECOMPONENT(MeshColliderComponent, "Mesh Collider")

View File

@@ -1,6 +1,7 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "src/Core/String.h"
#include "src/Resource/Model.h"
#include "src/Resource/ResourceLoader.h"
@@ -12,7 +13,7 @@
namespace Nuake
{
struct ModelComponent
struct ModelComponent : public Component
{
NUAKECOMPONENT(ModelComponent, "Model")

View File

@@ -1,13 +1,14 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "../Entities/Entity.h"
#include "Engine.h"
#include <src/AI/NavMesh.h>
namespace Nuake
{
struct NavMeshVolumeComponent
struct NavMeshVolumeComponent : public Component
{
NUAKECOMPONENT(NavMeshVolumeComponent, "Nav Mesh Volume")

View File

@@ -1,6 +1,7 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "src/Core/Core.h"
#include "src/Core/Maths.h"
#include "src/FileSystem/FileSystem.h"
@@ -34,7 +35,7 @@ namespace Nuake {
NetScriptExposedVarType Type;
};
class NetScriptComponent
class NetScriptComponent : public Component
{
NUAKECOMPONENT(NetScriptComponent, "Net Script")

View File

@@ -1,11 +1,14 @@
#include "src/Scene/Components/ParticleEmitterComponent.h"
#include "src/FileSystem/File.h"
#include <src/Resource/ResourceManager.h>
#include <src/Resource/ResourceLoader.h>
namespace Nuake
{
json ParticleEmitterComponent::Serialize()
{
BEGIN_SERIALIZE();
SERIALIZE_RES_FILE(resFile);
SERIALIZE_VEC3(ParticleScale);
SERIALIZE_VAL(Amount);
SERIALIZE_VAL(Life);
@@ -14,10 +17,6 @@ namespace Nuake
SERIALIZE_VAL(GravityRandom);
SERIALIZE_VAL(Radius);
SERIALIZE_VAL(GlobalSpace);
if (ParticleMaterial)
{
SERIALIZE_OBJECT(ParticleMaterial);
}
SERIALIZE_VAL(LifeRandomness);
SERIALIZE_VAL(ScaleRandomness);
END_SERIALIZE();
@@ -51,16 +50,10 @@ namespace Nuake
{
DESERIALIZE_VAL(GlobalSpace);
}
if (j.contains("ParticleMaterial"))
{
if (j["ParticleMaterial"].contains("Path"))
{
Ref<Material> newMaterial = ResourceLoader::LoadMaterial(j["ParticleMaterial"]["Path"]);
ParticleMaterial = newMaterial;
}
}
GravityRandom = j["GravityRandom"];
Radius = j["Radius"];
DESERIALIZE_RES_FILE(resFile);
return true;
}
}
}

View File

@@ -1,6 +1,7 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "src/Core/Core.h"
#include "src/Core/Maths.h"
#include "src/Resource/Serializable.h"
@@ -10,14 +11,37 @@
namespace Nuake
{
class ParticleEmitterComponent
class ParticleEmitterComponent : public Component
{
NUAKECOMPONENT(ParticleEmitterComponent, "Particle Emitter")
static void InitializeComponentClass()
{
BindComponentField<&ParticleEmitterComponent::resFile>("Particle", "Particle");
BindComponentField<&ParticleEmitterComponent::Amount>("Amount", "Amount");
FieldFloatLimits(0.1f, 0.0f, 500.0f);
BindComponentField<&ParticleEmitterComponent::LifeRandomness>("LifeRandomness", "Life Randomness");
FieldFloatLimits(0.1f, 0.f, 9999.f);
BindComponentField<&ParticleEmitterComponent::Life>("Life", "Life");
FieldFloatLimits(0.1f, 0.0f, 100.0f);
BindComponentField<&ParticleEmitterComponent::Rate>("Rate", "Rate");
FieldFloatLimits(0.1f, 0.0f, 10.0f);
BindComponentField<&ParticleEmitterComponent::ScaleRandomness>("ScaleRandomness", "Scale Randomness");
FieldFloatLimits(0.01f, 0.0f, 0.f);
BindComponentField<&ParticleEmitterComponent::ParticleScale>("ParticleScale", "Particle Scale");
BindComponentField<&ParticleEmitterComponent::GlobalSpace>("GlobalSpace", "Global Space");
BindComponentField<&ParticleEmitterComponent::Gravity>("Gravity", "Gravity");
BindComponentField<&ParticleEmitterComponent::GravityRandom>("GravityRandom", "Gravity Random");
FieldFloatLimits(0.01f, 0.0f, 1.0f);
BindComponentField<&ParticleEmitterComponent::Radius>("Radius", "Radius");
FieldFloatLimits(0.01f, 0.0f, 10.0f);
}
public:
ParticleEmitterComponent() = default;
~ParticleEmitterComponent() = default;
ResourceFile resFile;
Ref<Material> ParticleMaterial = CreateRef<Material>();
float Amount;

View File

@@ -1,35 +1,53 @@
#pragma once
#include <string>
#include <vector>
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "FieldTypes.h"
#include "src/FileSystem/File.h"
#include "src/Rendering/Mesh/Mesh.h"
#include "src/Resource/Serializable.h"
#include "src/Scene/Systems/QuakeMapBuilder.h"
#include "src/Scene/Entities/Entity.h"
#include "Engine.h"
#include <string>
#include <vector>
namespace Nuake {
class QuakeMapComponent
class QuakeMapComponent : public Component
{
NUAKECOMPONENT(QuakeMapComponent, "Quake Map")
static void InitializeComponentClass()
{
BindComponentField<&QuakeMapComponent::HasCollisions>("HasCollisions", "Has Collisions");
BindComponentField<&QuakeMapComponent::Path>("Path", "Path");
BindComponentField<&QuakeMapComponent::AutoRebuild>("AutoRebuild", "Auto Rebuild");
BindAction<&QuakeMapComponent::ActionRebuild>("Rebuild", "Rebuild");
}
public:
bool HasCollisions = false;
ResourceFile Path;
bool AutoRebuild = false;
float ScaleFactor = 1.f;
bool rebuildNextTick = false;
std::vector<Ref<Mesh>> m_Meshes;
std::vector<Entity> m_Brushes;
std::vector<int> m_SerializedBrushIDs;
std::string Path;
float ScaleFactor = 1.0f;
bool HasCollisions = false;
bool AutoRebuild = false;
void ActionRebuild();
json Serialize()
{
BEGIN_SERIALIZE();
SERIALIZE_VAL(HasCollisions);
SERIALIZE_VAL(Path);
SERIALIZE_RES_FILE(Path);
SERIALIZE_VAL(AutoRebuild);
for (uint32_t i = 0; i < std::size(m_Brushes); i++)
@@ -62,7 +80,7 @@ namespace Nuake {
}
}
this->Path = j["Path"];
DESERIALIZE_RES_FILE(Path);
this->HasCollisions = j["HasCollisions"];
return true;
}
@@ -79,4 +97,9 @@ namespace Nuake {
m_SerializedBrushIDs.clear();
}
};
inline void QuakeMapComponent::ActionRebuild()
{
rebuildNextTick = true;
}
}

View File

@@ -1,8 +1,9 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "TransformComponent.h"
#include "BaseComponent.h"
#include "VisibilityComponent.h"
#include "src/Core/Core.h"
namespace Nuake {
@@ -11,10 +12,18 @@ namespace Nuake {
class RigidBody;
};
class RigidBodyComponent
class RigidBodyComponent : public Component
{
NUAKECOMPONENT(RigidBodyComponent, "Rigid Body")
static void InitializeComponentClass()
{
BindComponentField<&RigidBodyComponent::Mass>("Mass", "Mass");
BindComponentField<&RigidBodyComponent::LockX>("LockX", "Lock X");
BindComponentField<&RigidBodyComponent::LockY>("LockY", "Lock Y");
BindComponentField<&RigidBodyComponent::LockZ>("LockZ", "Lock Z");
}
public:
float Mass;
bool LockX = false;
@@ -38,7 +47,7 @@ namespace Nuake {
json Serialize()
{
BEGIN_SERIALIZE();
SERIALIZE_VAL_LBL("Mass", Mass);
SERIALIZE_VAL(Mass);
SERIALIZE_VAL(LockX);
SERIALIZE_VAL(LockY);
SERIALIZE_VAL(LockZ);
@@ -47,22 +56,10 @@ namespace Nuake {
bool Deserialize(const json& j)
{
Mass = j["Mass"];
if (j.contains("LockX"))
{
LockX = j["LockX"];
}
if (j.contains("LockY"))
{
LockY = j["LockY"];
}
if (j.contains("LockZ"))
{
LockZ = j["LockZ"];
}
DESERIALIZE_VAL(Mass);
DESERIALIZE_VAL(LockX);
DESERIALIZE_VAL(LockY);
DESERIALIZE_VAL(LockZ);
return true;
}

View File

@@ -1,16 +1,92 @@
#include "SkinnedModelComponent.h"
#include "src/Resource/ModelLoader.h"
#include "src/Scene/Entities/Entity.h"
namespace Nuake
{
SkinnedModelComponent::SkinnedModelComponent()
void SkinnedModelComponent::LoadModel(entt::entity e, Scene* scene)
{
ModelLoader loader = ModelLoader();
this->ModelResource = loader.LoadSkinnedModel(ModelPath.GetRelativePath());
Entity entity = Entity{ e, scene };
scene->CreateSkeleton(entity);
RegenerateAnimationList();
}
void SkinnedModelComponent::LoadModel()
void SkinnedModelComponent::SetPlaying(bool play)
{
auto loader = ModelLoader();
this->ModelResource = loader.LoadSkinnedModel(ModelPath);
if (ModelResource == nullptr)
return;
ModelResource->IsPlaying = play;
}
}
bool SkinnedModelComponent::GetIsPlaying() const
{
if (ModelResource == nullptr)
return false;
return ModelResource->IsPlaying;
}
void SkinnedModelComponent::SetAnimationList(int i)
{
animationList.index = i;
// If the model is valid then play the animation
if (ModelResource != nullptr)
{
ModelResource->PlayAnimation(animationList.index);
}
}
void SkinnedModelComponent::RegenerateAnimationList()
{
if (ModelResource == nullptr)
{
return;
}
// Regenerate the animation list
std::vector<Ref<SkeletalAnimation>> animations = ModelResource->GetAnimations();
for (uint32_t i = 0; i < animations.size(); i++)
{
Ref<SkeletalAnimation>& animation = animations[i];
if (animation == nullptr)
{
continue;
}
animationList.items.push_back(animation->GetName());
}
}
json SkinnedModelComponent::Serialize()
{
BEGIN_SERIALIZE();
SERIALIZE_RES_FILE(ModelPath);
if (ModelResource)
{
SERIALIZE_OBJECT(ModelResource);
}
END_SERIALIZE();
}
bool SkinnedModelComponent::Deserialize(const json& j)
{
DESERIALIZE_RES_FILE(ModelPath);
ModelResource = CreateRef<SkinnedModel>();
if (j.contains("ModelResource"))
{
auto& res = j["ModelResource"];
ModelResource->Deserialize(res);
}
RegenerateAnimationList();
return true;
}
}

View File

@@ -1,53 +1,50 @@
#pragma once
#include <vector>
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "FieldTypes.h"
#include "src/FileSystem/File.h"
#include "src/FileSystem/FileSystem.h"
#include "src/Resource/Serializable.h"
#include "src/Resource/SkinnedModel.h"
#include <string>
#include <vector>
namespace Nuake
{
struct SkinnedModelComponent
class Scene;
class SkinnedModelComponent : public Component
{
NUAKECOMPONENT(SkinnedModelComponent, "Skinned Model")
static void InitializeComponentClass()
{
BindComponentField<&SkinnedModelComponent::ModelPath>("ModelPath", "Model Path");
BindComponentProperty<&SkinnedModelComponent::SetPlaying, &SkinnedModelComponent::GetIsPlaying>("Playing", "Playing");
SetFlags(ComponentFieldTrait::Transient);
BindComponentProperty<&SkinnedModelComponent::SetAnimationList, &SkinnedModelComponent::GetAnimationList>("Animation", "Animation");
SetFlags(ComponentFieldTrait::Transient);
}
Ref<SkinnedModel> ModelResource;
std::string ModelPath;
ResourceFile ModelPath;
DynamicItemList animationList;
SkinnedModelComponent();
void LoadModel(entt::entity e, Scene* scene);
void LoadModel();
void SetPlaying(bool play);
bool GetIsPlaying() const;
std::string directory;
DynamicItemList& GetAnimationList() { return animationList; }
void SetAnimationList(int i);
json Serialize()
{
BEGIN_SERIALIZE();
SERIALIZE_VAL(ModelPath);
void RegenerateAnimationList();
if (ModelResource)
{
SERIALIZE_OBJECT(ModelResource);
}
END_SERIALIZE();
}
json Serialize();
bool Deserialize(const json& j)
{
ModelPath = j["ModelPath"];
ModelResource = CreateRef<SkinnedModel>();
if (j.contains("ModelResource"))
{
auto& res = j["ModelResource"];
ModelResource->Deserialize(res);
}
return true;
}
bool Deserialize(const json& j);
};
}

View File

@@ -1,20 +1,38 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "src/Physics/PhysicsShapes.h"
#include "src/Core/Core.h"
namespace Nuake {
class SphereColliderComponent
namespace Nuake
{
class SphereColliderComponent : public Component
{
NUAKECOMPONENT(SphereColliderComponent, "Sphere Component")
static void InitializeComponentClass()
{
BindComponentField<&SphereColliderComponent::IsTrigger>("IsTrigger", "Is Trigger");
BindComponentProperty<&SphereColliderComponent::SetRadius, &SphereColliderComponent::GetRadius>("Radius", "Radius");
}
public:
Ref<Physics::PhysicShape> Sphere;
float Radius = 0.5f;
bool IsTrigger = false;
void SetRadius(const float newRadius)
{
Radius = newRadius;
}
float GetRadius()
{
return Radius;
}
json Serialize()
{
BEGIN_SERIALIZE();

View File

@@ -1,5 +1,6 @@
#include "SpriteComponent.h"
#include "src/FileSystem/File.h"
#include "src/FileSystem/FileSystem.h"
#include "src/Rendering/Textures/TextureManager.h"
#include "src/Rendering/Textures/MaterialManager.h"
@@ -10,8 +11,7 @@ namespace Nuake
{
SpriteComponent::SpriteComponent() :
Billboard(false),
LockYRotation(false),
SpritePath("")
LockYRotation(false)
{
}
@@ -32,7 +32,13 @@ namespace Nuake
SpriteMesh = CreateRef<Mesh>();
SpriteMesh->AddSurface(quadVertices, { 0, 1, 2, 3, 4, 5 });
Ref<Material> material = MaterialManager::Get()->GetMaterial(FileSystem::Root + SpritePath);
std::string absPath = "";
if (SpritePath.file != nullptr && SpritePath.file->Exist())
{
absPath = SpritePath.file->GetAbsolutePath();
}
Ref<Material> material = MaterialManager::Get()->GetMaterial(absPath);
bool hasNormal = material->HasNormal();
SpriteMesh->SetMaterial(material);
@@ -44,7 +50,7 @@ namespace Nuake
BEGIN_SERIALIZE();
SERIALIZE_VAL(Billboard);
SERIALIZE_VAL(LockYRotation);
SERIALIZE_VAL(SpritePath);
SERIALIZE_RES_FILE(SpritePath);
SERIALIZE_VAL(PositionFacing);
END_SERIALIZE();
}
@@ -61,17 +67,13 @@ namespace Nuake
LockYRotation = j["LockYRotation"];
}
DESERIALIZE_RES_FILE(SpritePath);
if (j.contains("PositionFacing"))
{
PositionFacing = j["PositionFacing"];
}
if (j.contains("SpritePath"))
{
SpritePath = j["SpritePath"];
LoadSprite();
}
return true;
}
}

View File

@@ -1,6 +1,8 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "FieldTypes.h"
#include "src/Core/Core.h"
#include "src/Resource/Serializable.h"
#include "src/Rendering/Textures/Texture.h"
@@ -8,16 +10,24 @@
namespace Nuake
{
class SpriteComponent
class SpriteComponent : public Component
{
NUAKECOMPONENT(SpriteComponent, "Sprite")
static void InitializeComponentClass()
{
BindComponentField<&SpriteComponent::Billboard>("Billboard", "Billboard");
BindComponentField<&SpriteComponent::LockYRotation>("LockYRotation", "Lock Y Rotation");
BindComponentField<&SpriteComponent::PositionFacing>("PositionFacing", "Position Facing");
BindComponentField<&SpriteComponent::SpritePath>("SpritePath", "Sprite Path");
}
public:
bool Billboard;
bool LockYRotation;
bool PositionFacing;
std::string SpritePath;
ResourceFile SpritePath;
Ref<Mesh> SpriteMesh;
SpriteComponent();

View File

@@ -1,26 +0,0 @@
#pragma once
#include <vector>
namespace Nuake
{
class TriggerZone
{
public:
std::string target = "";
std::vector<Entity> Targets;
bool Enabled = true;
TriggerZone()
{
Targets = std::vector<Entity>();
}
std::vector<Entity> GetTargets()
{
return Targets;
}
};
}

View File

@@ -1,33 +1,48 @@
#pragma once
#include "src/Core/Object/Object.h"
#include "Component.h"
#include "FieldTypes.h"
#include "src/Core/Logger.h"
#include "src/FileSystem/File.h"
#include "src/FileSystem/FileSystem.h"
#include "src/Resource/UUID.h"
#include "src/Resource/Serializable.h"
namespace Nuake
{
struct UIComponent
{
NUAKECOMPONENT(UIComponent, "UI Component");
struct UIComponent : public Component
{
NUAKECOMPONENT(UIComponent, "UI")
static void InitializeComponentClass()
{
BindComponentField<&UIComponent::UIResource>("UIResource", "UIResource");
SetFlags(ComponentFieldTrait::Internal, ComponentFieldTrait::Transient);
BindComponentField<&UIComponent::UIFilePath>("UIFilePath", "File Path");
BindComponentField<&UIComponent::IsWorldSpace>("IsWorldspace", "Is Worldspace");
}
UUID UIResource = UUID(0);
std::string CSharpUIController;
std::string UIFilePath;
bool IsWorldSpace;
// TODO: Z-Ordering
public:
UUID UIResource = UUID(0);
ResourceFile UIFilePath;
bool IsWorldSpace;
// TODO: Z-Ordering
json Serialize()
{
BEGIN_SERIALIZE();
SERIALIZE_VAL(UIFilePath);
SERIALIZE_VAL(IsWorldSpace);
END_SERIALIZE();
}
json Serialize()
{
BEGIN_SERIALIZE();
SERIALIZE_RES_FILE(UIFilePath);
SERIALIZE_VAL(IsWorldSpace);
END_SERIALIZE();
}
bool Deserialize(const json& j)
{
DESERIALIZE_VAL(UIFilePath);
DESERIALIZE_VAL(IsWorldSpace);
return true;
}
};
}
bool Deserialize(const json& j)
{
DESERIALIZE_RES_FILE(UIFilePath);
DESERIALIZE_VAL(IsWorldSpace);
return true;
}
};
}

View File

@@ -4,7 +4,6 @@
#include "src/Core/Logger.h"
#include "../Scene.h"
#include "../Components/BaseComponent.h"
#include "../Resource/Serializable.h"
#include "../Components/NameComponent.h"
@@ -59,6 +58,32 @@ namespace Nuake
func.invoke(newComponent, m_EntityHandle, &m_Scene->m_Registry);
}
void RemoveComponent(entt::meta_type& enttMetaType)
{
if (!enttMetaType)
{
Logger::Log("Meta data empty/invalid", "Entity", WARNING);
return;
}
entt::meta_any newComponent = enttMetaType.construct();
if (!newComponent)
{
Logger::Log("Could not create a component from the meta type", "Entity", CRITICAL);
return;
}
auto func = enttMetaType.func(HashedFnName::RemoveFromEntity);
// TODO: [WiggleWizard] Needs a lot more validation
if (!func)
{
Logger::Log("No such function exists or is registered on component", "Entity", CRITICAL);
return;
}
func.invoke(newComponent, m_EntityHandle, &m_Scene->m_Registry);
}
template<typename T>
T& AddComponent()
{

View File

@@ -8,8 +8,10 @@
class ImGuiHelper {
public:
static void DrawVec3(const std::string label, glm::vec3* values, float resetValue = 0.0f, float columnWidth = 100.0, float rate = 0.1f, float min = 0.0f)
static bool DrawVec3(const std::string label, glm::vec3* values, float resetValue = 0.0f, float columnWidth = 100.0, float rate = 0.1f, float min = 0.0f)
{
bool changed = false;
ImGuiIO& io = ImGui::GetIO();
auto boldFont = io.Fonts->Fonts[0];
@@ -26,13 +28,19 @@ public:
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.8f, 0.1f, 0.15f, 1.0f });
ImGui::PushFont(boldFont);
if (ImGui::Button("###X", buttonSize))
{
values->x = resetValue;
changed = true;
}
ImGui::PopFont();
ImGui::PopStyleColor(3);
ImGui::SameLine();
ImGui::PushItemWidth(availWidth);
ImGui::DragFloat("##X", &values->x, rate, min, 0.0f, "%.2f");
if (ImGui::DragFloat("##X", &values->x, rate, min, 0.0f, "%.2f"))
{
changed = true;
}
ImGui::PopItemWidth();
ImGui::SameLine();
@@ -41,12 +49,18 @@ public:
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.2f, 0.7f, 0.2f, 1.0f });
ImGui::PushFont(boldFont);
if (ImGui::Button("Y", buttonSize))
{
values->y = resetValue;
changed = true;
}
ImGui::PopFont();
ImGui::PopStyleColor(3);
ImGui::SameLine();
ImGui::PushItemWidth(availWidth);
ImGui::DragFloat("##Y", &values->y, rate, 0.0f, 0.0f, "%.2f");
if (ImGui::DragFloat("##Y", &values->y, rate, 0.0f, 0.0f, "%.2f"))
{
changed = true;
}
ImGui::PopItemWidth();
ImGui::SameLine();
@@ -55,19 +69,26 @@ public:
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4{ 0.1f, 0.25f, 0.8f, 1.0f });
ImGui::PushFont(boldFont);
if (ImGui::Button("Z", buttonSize))
{
values->z = resetValue;
changed = true;
}
ImGui::PopFont();
ImGui::PopStyleColor(3);
ImGui::SameLine();
ImGui::PushItemWidth(availWidth);
ImGui::DragFloat("##Z", &values->z, rate, 0.0f, 0.0f, "%.2f");
if (ImGui::DragFloat("##Z", &values->z, rate, 0.0f, 0.0f, "%.2f"))
{
changed = true;
}
ImGui::PopItemWidth();
ImGui::PopStyleVar();
ImGui::PopID();
//ImGui::Text("Hello");
return changed;
}
static void DrawVec2(const std::string label, glm::vec2* values, float resetValue = 0.0f, float columnWidth = 100.0, float rate = 0.1f, float min = 0.0f)

View File

@@ -273,17 +273,29 @@ namespace Nuake
for (const auto& e : view)
{
auto& map = view.get<QuakeMapComponent>(e);
if (map.AutoRebuild && !map.Path.empty() && FileSystem::FileExists(map.Path))
bool buildMap = false;
if (map.rebuildNextTick && map.Path.Exist())
{
if (auto file = FileSystem::GetFile(map.Path); file->Exist() && file->GetHasBeenModified())
buildMap = true;
map.rebuildNextTick = false;
}
if (map.AutoRebuild && map.Path.Exist())
{
if (auto file = FileSystem::GetFile(map.Path.GetRelativePath()); file->Exist() && file->GetHasBeenModified())
{
file->SetHasBeenModified(false);
Entity entity = Entity(e, this);
QuakeMapBuilder builder;
builder.BuildQuakeMap(entity, map.HasCollisions);
buildMap = true;
}
}
if (buildMap)
{
Entity entity = Entity(e, this);
QuakeMapBuilder builder;
builder.BuildQuakeMap(entity, map.HasCollisions);
}
}
}
@@ -469,7 +481,6 @@ namespace Nuake
}
entity.Destroy();
m_Registry.shrink_to_fit();
}
bool Scene::EntityExists(const std::string& name)
@@ -638,11 +649,12 @@ namespace Nuake
// This will turn the deserialized entity ids into actual Entities.
// This has to be done after the whole scene has been deserialized
// to make sure we can fetch the id in the scene. Otherwise, we could
m_Registry.each([this](auto e) {
// to make sure we can fetch the id in the scene. Otherwise, we could
for (const entt::entity& e : m_Registry.view<entt::entity>())
{
auto entity = Entity{ e, this };
entity.PostDeserialize();
});
};
return true;
}

View File

@@ -2,7 +2,7 @@
#include "src/Core/Core.h"
#include "src/Core/Maths.h"
#include "entt/entt.hpp"
#include <entt/entt.hpp>
#include "src/Rendering/Camera.h"
#include "Lighting/Environment.h"

View File

@@ -31,7 +31,16 @@ namespace Nuake
{
auto [transformComponent, skinnedComponent] = view.get<TransformComponent, SkinnedModelComponent>(e);
auto& model = skinnedComponent.ModelResource;
Ref<SkinnedModel> model = skinnedComponent.ModelResource;
// Load the model if it's not already loaded
// TODO: [WiggleWizard] Needs some sort of flag to infer that we've tried loading it once already, so
// we don't try loading the model every frame if it's invalid.
if (skinnedComponent.ModelPath.Exist() && skinnedComponent.ModelResource == nullptr)
{
skinnedComponent.LoadModel(e, m_Scene);
}
if (!model)
{
continue;

View File

@@ -4,12 +4,11 @@
#include "src/Scene/Scene.h"
#include "src/Scene/Entities/Entity.h"
#include "src/Scene/Components/AudioEmitterComponent.h"
#include "src/FileSystem/File.h"
#include "src/Audio/AudioManager.h"
#include <future>
namespace Nuake
{
AudioSystem::AudioSystem(Scene* scene)
@@ -44,14 +43,14 @@ namespace Nuake
{
auto [transformComponent, audioEmitterComponent] = view.get<TransformComponent, AudioEmitterComponent>(e);
if (audioEmitterComponent.FilePath.empty())
if (audioEmitterComponent.FilePath.file == nullptr || !audioEmitterComponent.FilePath.file->Exist())
{
// Doesn't have a file
continue;
}
const bool isPlaying = audioEmitterComponent.IsPlaying;
const std::string absoluteFilePath = FileSystem::RelativeToAbsolute(audioEmitterComponent.FilePath);
const std::string absoluteFilePath = audioEmitterComponent.FilePath.file->GetAbsolutePath();
const bool isVoiceActive = audioManager.IsVoiceActive(absoluteFilePath);
AudioRequest audioRequest;

View File

@@ -11,7 +11,6 @@
#include <src/Scene/Components/CharacterControllerComponent.h>
#include <src/Scene/Components/QuakeMap.h>
#include <src/Scene/Components/BSPBrushComponent.h>
#include <src/Scene/Components/TriggerZone.h>
#include <src/Scene/Components/CylinderColliderComponent.h>
namespace Nuake

View File

@@ -22,7 +22,6 @@ extern "C" {
#include "src/Scene/Components/TransformComponent.h"
#include "src/Scene/Components/LightComponent.h"
#include "src/Scene/Components/NameComponent.h"
#include "src/Scene/Components/TriggerZone.h"
#include "src/Resource/FGD/FGDClass.h"
#include "src/Scene/Components/WrenScriptComponent.h"
#include "src/Scene/Components/PrefabComponent.h"
@@ -68,7 +67,7 @@ namespace Nuake {
m_Scene->DestroyEntity(e);
}
map_parser_load((FileSystem::Root + quakeMapC.Path).c_str());
map_parser_load(quakeMapC.Path.GetAbsolutePath().c_str());
geo_generator_run();
DefaultMaterial = MaterialManager::Get()->GetMaterial("default");

View File

@@ -28,15 +28,15 @@ namespace Nuake
for (auto e : uiView)
{
auto& uiViewComponent = uiView.get<UIComponent>(e);
const std::string& filePath = uiViewComponent.UIFilePath;
Ref<File> file = uiViewComponent.UIFilePath.file;
if (uiViewComponent.UIResource == 0)
{
if (filePath.empty() || !FileSystem::FileExists(filePath))
if (file == nullptr || !file->Exist())
{
continue;
}
Ref<UIResource> uiResource = ResourceLoader::LoadUI(filePath);
Ref<UIResource> uiResource = ResourceLoader::LoadUI(file);
uiViewComponent.UIResource = uiResource->ID;
uis[uiViewComponent.UIResource] = uiResource;
@@ -44,7 +44,7 @@ namespace Nuake
}
else
{
if (FileSystem::FileExists(filePath))
if (file != nullptr && file->Exist())
{
auto ui = ResourceManager::GetResource<UIResource>(uiViewComponent.UIResource);
bool sourceHasChanged = false;

View File

@@ -19,7 +19,6 @@
#include <src/Scene/Components/RigidbodyComponent.h>
#include <src/Scene/Components/CharacterControllerComponent.h>
#include <src/Scene/Components/WrenScriptComponent.h>
#include <src/Scene/Components/TriggerZone.h>
#include <src/Scene/Components/BSPBrushComponent.h>
#include <src/Scene/Components/PrefabComponent.h>
#include <src/Scene/Components/AudioEmitterComponent.h>
@@ -406,8 +405,6 @@ namespace Nuake
double handle = wrenGetSlotDouble(vm, 1);
Entity ent = Entity((entt::entity)handle, Engine::GetCurrentScene().get());
TriggerZone trigger = ent.GetComponent<TriggerZone>();
int count = 0;
wrenSetSlotDouble(vm, 0, count);
@@ -418,8 +415,6 @@ namespace Nuake
double handle = wrenGetSlotDouble(vm, 1);
Entity ent = Entity((entt::entity)handle, Engine::GetCurrentScene().get());
TriggerZone trigger = ent.GetComponent<TriggerZone>();
std::vector<Entity> entities = {};
wrenEnsureSlots(vm, static_cast<int>(entities.size()));

File diff suppressed because it is too large Load Diff

View File

@@ -171,7 +171,8 @@ project "Nuake"
"%{prj.name}/dependencies/msdf-atlas-gen/msdfgen",
"%{prj.name}/dependencies/msdf-atlas-gen/msdfgen/include",
"%{prj.name}/dependencies/freetype/include",
"%{prj.name}/../Nuake/dependencies/tracy/public/tracy",
"%{prj.name}/dependencies/tracy/public/tracy",
"%{prj.name}/dependencies/entt/src",
}
@@ -263,6 +264,7 @@ project "NuakeRuntime"
"%{prj.name}/../Nuake/dependencies/recastnavigation/Recast/Include",
"%{prj.name}/../Nuake/dependencies/tracy/public/tracy",
"%{prj.name}/../Nuake/dependencies/entt/src",
}
libdirs
@@ -313,7 +315,7 @@ project "NuakeRuntime"
'{COPYFILE} "%{wks.location}/Nuake/dependencies/Coral/Coral.Managed/Coral.Managed.runtimeconfig.json" "%{wks.location}/%{prj.name}"'
}
filter { "system:windows", "action:vs*"}
filter { "system:windows", "action:vs*" }
flags
{
"MultiProcessorCompile",
@@ -393,7 +395,10 @@ project "Editor"
{
"%{prj.name}/Editor.cpp",
"%{prj.name}/src/**.cpp",
"%{prj.name}/src/**.h"
"%{prj.name}/src/**.h",
-- This isn't ideal, but it works...needs a proper way of doing this, but that's for another time
"Nuake/dependencies/entt/natvis/entt/*.natvis"
}
includedirs
@@ -420,6 +425,7 @@ project "Editor"
"%{prj.name}/../Nuake/dependencies/msdf-atlas-gen/msdfgen/include",
"%{prj.name}/../Nuake/dependencies/freetype/include",
"%{prj.name}/../Nuake/dependencies/tracy/public/tracy",
"%{prj.name}/../Nuake/dependencies/entt/src",
}