New component field type to support files
Also fixed Audio System to work with this new supported component field type
This commit is contained in:
@@ -15,133 +15,6 @@ public:
|
||||
|
||||
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();
|
||||
|
||||
}
|
||||
};
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "EditorSelectionPanel.h"
|
||||
#include "../Misc/ImGuiTextHelper.h"
|
||||
#include <src/Scene/Components.h>
|
||||
#include "src/Scene/Components/FieldTypes.h"
|
||||
|
||||
#include <src/Rendering/Textures/Material.h>
|
||||
#include <src/Resource/ResourceLoader.h>
|
||||
@@ -15,6 +16,7 @@
|
||||
|
||||
#include <entt/entt.hpp>
|
||||
|
||||
|
||||
#define REGISTER_TYPE_DRAWER(forType, fn) \
|
||||
FieldTypeDrawers[entt::type_id<forType>().hash()] = std::bind(&fn, this, std::placeholders::_1, std::placeholders::_2);
|
||||
|
||||
@@ -29,6 +31,8 @@ EditorSelectionPanel::EditorSelectionPanel()
|
||||
REGISTER_TYPE_DRAWER(bool, EditorSelectionPanel::DrawFieldTypeBool);
|
||||
REGISTER_TYPE_DRAWER(float, EditorSelectionPanel::DrawFieldTypeFloat);
|
||||
REGISTER_TYPE_DRAWER(Vector3, EditorSelectionPanel::DrawFieldTypeVector3);
|
||||
REGISTER_TYPE_DRAWER(std::string, EditorSelectionPanel::DrawFieldTypeString);
|
||||
REGISTER_TYPE_DRAWER(ResourceFile, EditorSelectionPanel::DrawFieldTypeResourceFile);
|
||||
}
|
||||
|
||||
void EditorSelectionPanel::ResolveFile(Ref<Nuake::File> file)
|
||||
@@ -705,3 +709,74 @@ void EditorSelectionPanel::DrawFieldTypeVector3(entt::meta_data& field, entt::me
|
||||
ImGui::TableNextRow();
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::TableNextRow();
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::TableNextRow();
|
||||
}
|
||||
|
||||
|
||||
@@ -97,4 +97,6 @@ private:
|
||||
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);
|
||||
};
|
||||
@@ -18,6 +18,8 @@ namespace Nuake
|
||||
NK_HASHED_STATIC_STR(FloatStep)
|
||||
NK_HASHED_STATIC_STR(FloatMin)
|
||||
NK_HASHED_STATIC_STR(FloatMax)
|
||||
|
||||
NK_HASHED_STATIC_STR(ResourceFileType)
|
||||
};
|
||||
|
||||
struct HashedName
|
||||
@@ -50,72 +52,78 @@ namespace Nuake
|
||||
}
|
||||
}
|
||||
|
||||
#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 (*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); \
|
||||
\
|
||||
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); \
|
||||
} \
|
||||
#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 (*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); \
|
||||
\
|
||||
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 FloatFieldLimits(float stepSize, float min, float max) \
|
||||
{ \
|
||||
return ComponentFactory \
|
||||
.prop(HashedFieldPropName::FloatStep, stepSize) \
|
||||
.prop(HashedFieldPropName::FloatMin, min) \
|
||||
.prop(HashedFieldPropName::FloatMax, max); \
|
||||
} \
|
||||
\
|
||||
template<auto Getter, auto Setter> \
|
||||
static auto BindComponentProperty(const char* varName, const char* displayName) \
|
||||
static auto ResourceFileRestriction(const char* fileType) \
|
||||
{ \
|
||||
return ComponentFactory \
|
||||
.data<Getter, Setter>(entt::hashed_string(varName)) \
|
||||
.prop(HashedName::DisplayName, displayName); \
|
||||
} \
|
||||
\
|
||||
static auto FloatFieldLimits(float stepSize, float min, float max) \
|
||||
{ \
|
||||
return ComponentFactory \
|
||||
.prop(HashedFieldPropName::FloatStep, stepSize) \
|
||||
.prop(HashedFieldPropName::FloatMin, min) \
|
||||
.prop(HashedFieldPropName::FloatMax, max); \
|
||||
}
|
||||
.prop(HashedFieldPropName::ResourceFileType, fileType); \
|
||||
}
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
#include "AudioEmitterComponent.h"
|
||||
|
||||
#include "src/FileSystem/FileSystem.h"
|
||||
|
||||
namespace Nuake {
|
||||
|
||||
json AudioEmitterComponent::Serialize()
|
||||
{
|
||||
BEGIN_SERIALIZE();
|
||||
SERIALIZE_VAL(FilePath);
|
||||
|
||||
bool validFile = FilePath.file != nullptr && FilePath.file->Exist();
|
||||
j["validFile"] = validFile;
|
||||
if (validFile)
|
||||
{
|
||||
j["file"] = FilePath.file->GetRelativePath();
|
||||
}
|
||||
|
||||
SERIALIZE_VAL(IsPlaying);
|
||||
SERIALIZE_VAL(Volume);
|
||||
SERIALIZE_VAL(Pan);
|
||||
@@ -20,7 +29,16 @@ namespace Nuake {
|
||||
|
||||
bool AudioEmitterComponent::Deserialize(const json& j)
|
||||
{
|
||||
DESERIALIZE_VAL(FilePath);
|
||||
if (j.contains("validFile"))
|
||||
{
|
||||
bool validFile = j["validFile"];
|
||||
if (validFile)
|
||||
{
|
||||
std::string filePath = j["file"];
|
||||
FilePath.file = FileSystem::GetFile(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
DESERIALIZE_VAL(Volume);
|
||||
DESERIALIZE_VAL(IsPlaying);
|
||||
DESERIALIZE_VAL(Pan);
|
||||
@@ -32,4 +50,4 @@ namespace Nuake {
|
||||
DESERIALIZE_VAL(Loop);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "Component.h"
|
||||
#include "FieldTypes.h"
|
||||
|
||||
#include "src/Core/Core.h"
|
||||
#include "src/FileSystem/File.h"
|
||||
#include "src/Resource/Resource.h"
|
||||
#include "src/Resource/Serializable.h"
|
||||
|
||||
namespace Nuake {
|
||||
@@ -13,6 +16,11 @@ namespace Nuake {
|
||||
|
||||
static void InitializeComponentClass()
|
||||
{
|
||||
BindComponentField<&AudioEmitterComponent::File>("FilePath", "File Path");
|
||||
|
||||
BindComponentField<&AudioEmitterComponent::FilePath>("FilePath", "File Path");
|
||||
ResourceFileRestriction("_AudioFile");
|
||||
|
||||
BindComponentField<&AudioEmitterComponent::IsPlaying>("IsPlaying", "Is Playing");
|
||||
BindComponentField<&AudioEmitterComponent::Loop>("Loop", "Loop");
|
||||
|
||||
@@ -34,7 +42,8 @@ namespace Nuake {
|
||||
}
|
||||
|
||||
public:
|
||||
std::string FilePath;
|
||||
Ref<File> File;
|
||||
ResourceFile FilePath;
|
||||
|
||||
bool IsPlaying = false;
|
||||
bool Loop = false;
|
||||
|
||||
18
Nuake/src/Scene/Components/FieldTypes.h
Normal file
18
Nuake/src/Scene/Components/FieldTypes.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "src/Core/Core.h"
|
||||
|
||||
namespace Nuake
|
||||
{
|
||||
class File;
|
||||
|
||||
struct ResourceFile
|
||||
{
|
||||
ResourceFile() {}
|
||||
ResourceFile(const Ref<File>& inFile) : file(inFile) {}
|
||||
|
||||
Ref<File> file = nullptr;
|
||||
};
|
||||
}
|
||||
@@ -44,14 +44,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;
|
||||
|
||||
Reference in New Issue
Block a user