From 6a52340e7d3ce02d84546de75ca727be66d1f82f Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 20 Sep 2023 21:41:34 -0400 Subject: [PATCH 1/3] Audio engine can now play sounds --- Editor/src/ComponentsPanel/QuakeMapPanel.h | 1 + Editor/src/Windows/EditorSelectionPanel.cpp | 37 +++++----- Nuake/src/Audio/AudioManager.cpp | 77 +++++++++++++++++---- Nuake/src/Audio/AudioManager.h | 32 +++++++-- Nuake/src/Core/Core.h | 1 + 5 files changed, 110 insertions(+), 38 deletions(-) diff --git a/Editor/src/ComponentsPanel/QuakeMapPanel.h b/Editor/src/ComponentsPanel/QuakeMapPanel.h index 7269ba76..48be8510 100644 --- a/Editor/src/ComponentsPanel/QuakeMapPanel.h +++ b/Editor/src/ComponentsPanel/QuakeMapPanel.h @@ -4,6 +4,7 @@ #include "src/Scene/Systems/QuakeMapBuilder.h" #include + class QuakeMapPanel : ComponentPanel { public: diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index af20949f..208c393a 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -118,9 +118,10 @@ void EditorSelectionPanel::DrawEntity(Nuake::Entity entity) void EditorSelectionPanel::DrawAddComponentMenu(Nuake::Entity entity) { - if (entity.HasComponent()) + using namespace Nuake; + if (entity.HasComponent()) { - auto& entityName = entity.GetComponent().Name; + auto& entityName = entity.GetComponent().Name; ImGuiTextSTD("##Name", entityName); ImGui::SameLine(); @@ -129,27 +130,27 @@ void EditorSelectionPanel::DrawAddComponentMenu(Nuake::Entity entity) if (ImGui::BeginPopup("ComponentPopup")) { - MenuItemComponent("Wren Script", Nuake::WrenScriptComponent) - MenuItemComponent("Camera", Nuake::CameraComponent) - MenuItemComponent("Light", Nuake::LightComponent) + MenuItemComponent("Wren Script", WrenScriptComponent); + MenuItemComponent("Camera", CameraComponent); + MenuItemComponent("Light", LightComponent); ImGui::Separator(); - MenuItemComponent("Model", Nuake::ModelComponent) - MenuItemComponent("Skinned Model", Nuake::SkinnedModelComponent) - MenuItemComponent("Bone", Nuake::BoneComponent) + MenuItemComponent("Model", ModelComponent); + MenuItemComponent("Skinned Model", SkinnedModelComponent); + MenuItemComponent("Bone", BoneComponent) ImGui::Separator(); - MenuItemComponent("Sprite", Nuake::SpriteComponent) - MenuItemComponent("Particle Emitter", Nuake::ParticleEmitterComponent) + MenuItemComponent("Sprite", SpriteComponent) + MenuItemComponent("Particle Emitter", ParticleEmitterComponent) ImGui::Separator(); - MenuItemComponent("Character Controller", Nuake::CharacterControllerComponent) - MenuItemComponent("Rigid body", Nuake::RigidBodyComponent) + MenuItemComponent("Character Controller", CharacterControllerComponent) + MenuItemComponent("Rigid body", RigidBodyComponent) ImGui::Separator(); - MenuItemComponent("Box collider", Nuake::BoxColliderComponent) - MenuItemComponent("Capsule collider", Nuake::CapsuleColliderComponent) - MenuItemComponent("Cylinder collider", Nuake::CylinderColliderComponent) - MenuItemComponent("Sphere collider", Nuake::SphereColliderComponent) - MenuItemComponent("Mesh collider", Nuake::MeshColliderComponent) + MenuItemComponent("Box collider", BoxColliderComponent) + MenuItemComponent("Capsule collider", CapsuleColliderComponent) + MenuItemComponent("Cylinder collider", CylinderColliderComponent) + MenuItemComponent("Sphere collider", SphereColliderComponent) + MenuItemComponent("Mesh collider", MeshColliderComponent) ImGui::Separator(); - MenuItemComponent("Quake map", Nuake::QuakeMapComponent) + MenuItemComponent("Quake map", QuakeMapComponent) ImGui::EndPopup(); } ImGui::Separator(); diff --git a/Nuake/src/Audio/AudioManager.cpp b/Nuake/src/Audio/AudioManager.cpp index d8672ea6..01a28a35 100644 --- a/Nuake/src/Audio/AudioManager.cpp +++ b/Nuake/src/Audio/AudioManager.cpp @@ -1,32 +1,43 @@ #include "AudioManager.h" +#include "src/Core/Logger.h" +#include "src/Core/FileSystem.h" #include #include "soloud_speech.h" #include "soloud_thread.h" +#include -namespace Nuake -{ - void AudioManager::Initialize() + +namespace Nuake { + + AudioManager::AudioManager() : + m_AudioThreadRunning(true) { - _soloud = CreateRef(); - _soloud->init(); - - _audioThreadRunning = false; - _audioThread = std::thread(&AudioManager::AudioThreadLoop, this); } AudioManager::~AudioManager() { Deinitialize(); - _audioThreadRunning = false; - _audioThread.join(); + m_AudioThreadRunning = false; + m_AudioThread.join(); } + void AudioManager::Initialize() + { + m_Soloud = CreateRef(); + + // TODO: Sample rate, back end, buffer size, flags. + m_Soloud->init(); + + m_AudioThread = std::thread(&AudioManager::AudioThreadLoop, this); + + Logger::Log("Audio manager initialized", "audio", VERBOSE); + } void AudioManager::Deinitialize() { - _soloud->deinit(); + m_Soloud->deinit(); } void AudioManager::PlayTTS(const std::string& text) @@ -34,11 +45,51 @@ namespace Nuake } + void AudioManager::QueueWavAudio(const std::string& filePath) + { + // Acquire mutex lock and push to queue + const std::lock_guard lock(m_AudioQueueMutex); + + // Check if file exists and load + const bool fileExists = FileSystem::FileExists(filePath, true); + if (fileExists && !IsWavLoaded(filePath)) + { + LoadWavAudio(filePath); + } + + m_AudioQueue.push({ filePath }); + } + + bool AudioManager::IsWavLoaded(const std::string& filePath) const + { + return m_WavSamples.find(filePath) != m_WavSamples.end(); + } + + void AudioManager::LoadWavAudio(const std::string& filePath) + { + m_WavSamples[filePath] = SoLoud::Wav(); + m_WavSamples[filePath].load(filePath.c_str()); + } + void AudioManager::AudioThreadLoop() { - while(_audioThreadRunning) + while(m_AudioThreadRunning) { - + // Acquire mutex lock + const std::lock_guard lock(m_AudioQueueMutex); + + // Check if we have audio queued + while (!m_AudioQueue.empty()) + { + auto& first = m_AudioQueue.front(); + const std::string& audioFilePath = first.audioFile; + + // If file exists, play it + m_Soloud->play(*&m_WavSamples[audioFilePath]); + + // Remove item from queue. + m_AudioQueue.pop(); + } } } } \ No newline at end of file diff --git a/Nuake/src/Audio/AudioManager.h b/Nuake/src/Audio/AudioManager.h index a60ab612..d2f0fc16 100644 --- a/Nuake/src/Audio/AudioManager.h +++ b/Nuake/src/Audio/AudioManager.h @@ -10,21 +10,36 @@ namespace SoLoud class AudioSource; } +// Temp code +struct audioQueueRequest +{ + std::string audioFile; +}; + +namespace SoLoud +{ + class Wav; +} + namespace Nuake { // This is a singleton that manages everything for audio. class AudioManager { private: - Ref _soloud; - - bool _audioThreadRunning; - std::thread _audioThread; - std::mutex _audioMutex; - const int MAX_VOICE_COUNT = 32; + + Ref m_Soloud; + + bool m_AudioThreadRunning; + std::thread m_AudioThread; + std::mutex m_AudioQueueMutex; + std::atomic m_AudioQueued = { false }; + std::queue m_AudioQueue; + + std::unordered_map m_WavSamples; public: - AudioManager() = default; + AudioManager(); ~AudioManager(); static AudioManager& Get() @@ -42,6 +57,9 @@ namespace Nuake void PlayTTS(const std::string& text); + void QueueWavAudio(const std::string& filePath); + bool IsWavLoaded(const std::string& filePath) const; + void LoadWavAudio(const std::string& filePath); private: void AudioThreadLoop(); }; diff --git a/Nuake/src/Core/Core.h b/Nuake/src/Core/Core.h index 9b73304f..816c6a6d 100644 --- a/Nuake/src/Core/Core.h +++ b/Nuake/src/Core/Core.h @@ -4,6 +4,7 @@ #include #include #include +#include #define ASSERT(x) if (!(x)) assert(false) From 92db6c9082da0c939705afdf3f9070a56c1c6892 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 20 Sep 2023 22:20:24 -0400 Subject: [PATCH 2/3] Added gizmo for audio emitter --- Editor/Editor.cpp | 193 +++++++----------- Editor/src/Misc/GizmoDrawer.cpp | 21 ++ Editor/src/Windows/EditorSelectionPanel.cpp | 9 +- Nuake/src/Audio/AudioSource.h | 2 + .../Scene/Components/AudioEmitterComponent.h | 17 ++ Nuake/src/Scene/Components/BoxCollider.h | 1 + Nuake/src/Scene/Components/Components.h | 4 + 7 files changed, 125 insertions(+), 122 deletions(-) create mode 100644 Nuake/src/Scene/Components/AudioEmitterComponent.h diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index d9a6695d..bc1bbe5c 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -33,11 +33,12 @@ #include -const std::string WindowTitle = "Nuake Editor"; +std::string WindowTitle = "Nuake Editor "; int main(int argc, char* argv[]) { - bool playMode = false; + using namespace Nuake; + std::string projectPath = ""; Vector2 editorResolution = Vector2(1280, 720); @@ -47,15 +48,6 @@ int main(int argc, char* argv[]) char* arg = argv[i]; std::string args = std::string(arg); - if (args == "--play") - { - if (argc > 2) - { - projectPath = std::string(argv[i + 1]); - } - playMode = true; - } - if (args == "--resolution") { if (argc >= i + 1) @@ -83,134 +75,101 @@ int main(int argc, char* argv[]) } bool shouldLoadProject = false; - if (!playMode && argc > 1) + if (argc > 1) { shouldLoadProject = true; projectPath = std::string(argv[1]); } - if (playMode) + Nuake::Engine::Init(); + Engine::GetCurrentWindow()->SetSize(editorResolution); + + Nuake::EditorInterface editor; + editor.BuildFonts(); + +#ifdef NK_DEBUG + WindowTitle += "(DEBUG)"; +#endif +#ifdef NK_RELEASE + WindowTitle += "(RELEASE)"; +#endif + + Ref window = Nuake::Engine::GetCurrentWindow(); + window->SetTitle(WindowTitle); + + if (monitorIdx != -1) { - Nuake::Engine::Init(); - Nuake::EditorInterface editor; - editor.BuildFonts(); - - Ref project = Nuake::Project::New(); - FileSystem::SetRootDirectory(FileSystem::GetParentPath(projectPath)); - - project->FullPath = projectPath; - project->Deserialize(FileSystem::ReadFile(projectPath, true)); - - Ref window = Nuake::Engine::GetCurrentWindow(); - window->SetTitle(project->Name); - - Nuake::Engine::LoadProject(project); - - Nuake::Engine::EnterPlayMode(); - auto shader = Nuake::ShaderManager::GetShader("resources/Shaders/copy.shader"); - while (!window->ShouldClose()) - { - Nuake::Vector2 WindowSize = window->GetSize(); - glViewport(0, 0, WindowSize.x, WindowSize.y); - Nuake::Renderer2D::BeginDraw(WindowSize); - Nuake::Engine::Tick(); - Nuake::Engine::Draw(); - - shader->Bind(); - - window->GetFrameBuffer()->GetTexture()->Bind(0); - shader->SetUniform1i("u_Source", 0); - Nuake::Renderer::DrawQuad(Nuake::Matrix4(1)); - - Nuake::Engine::EndDraw(); - } + window->SetMonitor(monitorIdx); } - else + + GizmoDrawer gizmoDrawer = GizmoDrawer(); + + if (shouldLoadProject) { - Nuake::Engine::Init(); - Engine::GetCurrentWindow()->SetSize(editorResolution); + FileSystem::SetRootDirectory(FileSystem::GetParentPath(projectPath)); - Nuake::EditorInterface editor; - editor.BuildFonts(); + auto project = Project::New(); + auto projectFileData = FileSystem::ReadFile(projectPath, true); + try + { + project->Deserialize(json::parse(projectFileData)); + project->FullPath = projectPath; - Ref window = Nuake::Engine::GetCurrentWindow(); - window->SetTitle(WindowTitle); + Engine::LoadProject(project); - if (monitorIdx != -1) - { - window->SetMonitor(monitorIdx); - } - - using namespace Nuake; - - GizmoDrawer gizmoDrawer = GizmoDrawer(); - - if (shouldLoadProject) - { - FileSystem::SetRootDirectory(FileSystem::GetParentPath(projectPath)); - - auto project = Project::New(); - auto projectFileData = FileSystem::ReadFile(projectPath, true); - try - { - project->Deserialize(json::parse(projectFileData)); - project->FullPath = projectPath; - - Engine::LoadProject(project); - - editor.filesystem->m_CurrentDirectory = Nuake::FileSystem::RootDirectory; - } - catch (std::exception exception) - { - Logger::Log("Error loading project: " + projectPath, "editor", CRITICAL); - Logger::Log(exception.what()); - } - } + editor.filesystem->m_CurrentDirectory = Nuake::FileSystem::RootDirectory; + } + catch (std::exception exception) + { + Logger::Log("Error loading project: " + projectPath, "editor", CRITICAL); + Logger::Log(exception.what()); + } + } - while (!window->ShouldClose()) + while (!window->ShouldClose()) + { + Nuake::Engine::Tick(); + Nuake::Engine::Draw(); + + Timestep ts = Nuake::Engine::GetTimestep(); + + Nuake::Vector2 WindowSize = window->GetSize(); + glViewport(0, 0, WindowSize.x, WindowSize.y); + Nuake::Renderer2D::BeginDraw(WindowSize); + + auto sceneFramebuffer = window->GetFrameBuffer(); + sceneFramebuffer->Bind(); { - Nuake::Engine::Tick(); - Nuake::Engine::Draw(); - - Timestep ts = Nuake::Engine::GetTimestep(); - - Nuake::Vector2 WindowSize = window->GetSize(); - glViewport(0, 0, WindowSize.x, WindowSize.y); - Nuake::Renderer2D::BeginDraw(WindowSize); - - auto sceneFramebuffer = window->GetFrameBuffer(); - sceneFramebuffer->Bind(); + Ref currentScene = Nuake::Engine::GetCurrentScene(); + Ref camera; + if (currentScene) { - Ref currentScene = Nuake::Engine::GetCurrentScene(); - Ref camera; - if (currentScene) + camera = currentScene->m_EditorCamera; + } + + if (currentScene && !Nuake::Engine::IsPlayMode()) + { + glEnable(GL_LINE_SMOOTH); + + if (editor.ShouldDrawAxis()) { - camera = currentScene->m_EditorCamera; + //gizmoDrawer.DrawAxis(currentScene); } - if (currentScene && !Nuake::Engine::IsPlayMode()) + if (editor.ShouldDrawCollision()) { - glEnable(GL_LINE_SMOOTH); - - if (editor.ShouldDrawAxis()) - { - //gizmoDrawer.DrawAxis(currentScene); - } - - if (editor.ShouldDrawCollision()) - { - gizmoDrawer.DrawGizmos(currentScene); - } + gizmoDrawer.DrawGizmos(currentScene); } } - sceneFramebuffer->Unbind(); - - editor.Update(ts); - editor.Draw(); - - Nuake::Engine::EndDraw(); } + sceneFramebuffer->Unbind(); + + editor.Update(ts); + editor.Draw(); + + Nuake::Engine::EndDraw(); } + Nuake::Engine::Close(); } \ No newline at end of file diff --git a/Editor/src/Misc/GizmoDrawer.cpp b/Editor/src/Misc/GizmoDrawer.cpp index c883d3de..83a466a0 100644 --- a/Editor/src/Misc/GizmoDrawer.cpp +++ b/Editor/src/Misc/GizmoDrawer.cpp @@ -19,6 +19,7 @@ #include #include #include +#include GizmoDrawer::GizmoDrawer() { @@ -367,6 +368,26 @@ void GizmoDrawer::DrawGizmos(Ref scene) renderList.AddToRenderList(Renderer::QuadMesh, particleTransform); } + renderList.Flush(gizmoShader, true); + + auto audioView = scene->m_Registry.view(); + for (auto e : audioView) + { + gizmoShader->SetUniformTex("gizmo_texture", TextureManager::Get()->GetTexture("resources/Gizmos/speaker.png").get()); + auto [transformComponent, audioEmitterComponent] = scene->m_Registry.get(e); + + auto initialTransform = transformComponent.GetGlobalTransform(); + Matrix4 transform = initialTransform; + transform = glm::inverse(scene->m_EditorCamera->GetTransform()); + + // Translation + const Vector3& globalPosition = transformComponent.GetGlobalPosition(); + transform[3] = initialTransform[3]; + transform = glm::scale(transform, Vector3(0.5f, 0.5f, 0.5f)); + + renderList.AddToRenderList(Renderer::QuadMesh, transform); + } + renderList.Flush(gizmoShader, true); RenderCommand::Enable(RendererEnum::DEPTH_TEST); diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index 208c393a..f7c5c74d 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -8,12 +8,9 @@ #include #include #include + #include -#include "src/Scene/Components/WrenScriptComponent.h" -#include "src/Scene/Components/ParticleEmitterComponent.h" - - EditorSelectionPanel::EditorSelectionPanel() { } @@ -150,7 +147,9 @@ void EditorSelectionPanel::DrawAddComponentMenu(Nuake::Entity entity) MenuItemComponent("Sphere collider", SphereColliderComponent) MenuItemComponent("Mesh collider", MeshColliderComponent) ImGui::Separator(); - MenuItemComponent("Quake map", QuakeMapComponent) + MenuItemComponent("Quake map", QuakeMapComponent); + ImGui::Separator(); + MenuItemComponent("Audio Emitter", AudioEmitterComponent); ImGui::EndPopup(); } ImGui::Separator(); diff --git a/Nuake/src/Audio/AudioSource.h b/Nuake/src/Audio/AudioSource.h index 7d4b513f..775983dc 100644 --- a/Nuake/src/Audio/AudioSource.h +++ b/Nuake/src/Audio/AudioSource.h @@ -5,6 +5,8 @@ namespace Nuake class AudioSource { private: + bool m_Loop = false; + bool m_Is3D = false; public: AudioSource() = default; diff --git a/Nuake/src/Scene/Components/AudioEmitterComponent.h b/Nuake/src/Scene/Components/AudioEmitterComponent.h new file mode 100644 index 00000000..1687f9de --- /dev/null +++ b/Nuake/src/Scene/Components/AudioEmitterComponent.h @@ -0,0 +1,17 @@ +#pragma once +#include "src/Core/Core.h" +#include "src/Resource/Serializable.h" + +namespace Nuake { + + class AudioEmitterComponent + { + public: + float Volume = 1.0f; + float Pan = 0.0f; + float PlaybackSpeed = 1.0f; + + json Serialize(); + bool Deserialize(const json& j); + }; +} diff --git a/Nuake/src/Scene/Components/BoxCollider.h b/Nuake/src/Scene/Components/BoxCollider.h index dd67bf08..f1fb1f84 100644 --- a/Nuake/src/Scene/Components/BoxCollider.h +++ b/Nuake/src/Scene/Components/BoxCollider.h @@ -3,6 +3,7 @@ #include "src/Core/Core.h" namespace Nuake { + class BoxColliderComponent { public: diff --git a/Nuake/src/Scene/Components/Components.h b/Nuake/src/Scene/Components/Components.h index d47b0044..b2962548 100644 --- a/Nuake/src/Scene/Components/Components.h +++ b/Nuake/src/Scene/Components/Components.h @@ -17,7 +17,11 @@ #include "CylinderColliderComponent.h" #include "NativeScriptComponent.h" +#include "ParticleEmitterComponent.h" + #include "ParentComponent.h" #include "NameComponent.h" #include "BoxCollider.h" +#include "AudioEmitterComponent.h" +#include "WrenScriptComponent.h" #include "../Entities/Entity.h" From 2efb2febac86c44e0ea465f2680fca4d58a74ccc Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 20 Sep 2023 22:28:42 -0400 Subject: [PATCH 3/3] Audio manager cleanup --- Nuake/src/Audio/AudioManager.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Nuake/src/Audio/AudioManager.cpp b/Nuake/src/Audio/AudioManager.cpp index 01a28a35..6702315e 100644 --- a/Nuake/src/Audio/AudioManager.cpp +++ b/Nuake/src/Audio/AudioManager.cpp @@ -81,11 +81,10 @@ namespace Nuake { // Check if we have audio queued while (!m_AudioQueue.empty()) { - auto& first = m_AudioQueue.front(); - const std::string& audioFilePath = first.audioFile; + auto& currentAudio = m_AudioQueue.front(); // If file exists, play it - m_Soloud->play(*&m_WavSamples[audioFilePath]); + m_Soloud->play(m_WavSamples[currentAudio.audioFile]); // Remove item from queue. m_AudioQueue.pop();