From a4724e2a917391723e41caf7a27640f450e32d65 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Sat, 23 Sep 2023 00:37:42 -0400 Subject: [PATCH] Upgraded to C++ 20 & better audio voice management --- Editor/Editor.cpp | 2 +- .../src/ComponentsPanel/AudioEmitterPanel.h | 55 +++++++++ .../src/ComponentsPanel/SkinnedModelPanel.h | 2 +- Editor/src/Misc/GizmoDrawer.cpp | 6 +- Editor/src/Misc/PopupHelper.h | 2 +- Editor/src/Windows/EditorInterface.cpp | 8 +- Editor/src/Windows/LoadingSplash.h | 2 +- Editor/src/Windows/ProjectInterface.cpp | 2 +- Nuake/src/Audio/AudioManager.cpp | 106 +++++++++++++++++- Nuake/src/Audio/AudioManager.h | 40 +++++-- Nuake/src/Core/FileSystem.cpp | 2 +- Nuake/src/Core/Physics/DynamicWorld.cpp | 12 +- .../Rendering/Buffers/VertexBufferLayout.h | 1 - Nuake/src/Rendering/PostFX/SSAO.cpp | 4 +- Nuake/src/Rendering/Renderer2D.cpp | 8 +- Nuake/src/Rendering/SceneRenderer.cpp | 4 +- Nuake/src/Rendering/Textures/Texture.cpp | 2 +- Nuake/src/Resource/AudioResource.h | 12 ++ Nuake/src/Resource/ModelLoader.cpp | 10 +- .../Components/AudioEmitterComponent.cpp | 13 +++ .../Scene/Components/AudioEmitterComponent.h | 12 +- Nuake/src/Scene/Scene.cpp | 2 +- Nuake/src/Scene/Scene.h | 5 - Nuake/src/Scene/Systems/AnimationSystem.cpp | 2 +- Nuake/src/Scene/Systems/AudioSystem.cpp | 65 +++++++++-- Nuake/src/Scene/Systems/ParticleSystem.cpp | 4 +- Nuake/src/Scene/Systems/ScriptingSystem.cpp | 2 +- Nuake/src/Scripting/WrenScript.cpp | 2 +- Runtime/Runtime.cpp | 6 +- premake5.lua | 6 +- 30 files changed, 319 insertions(+), 80 deletions(-) create mode 100644 Nuake/src/Resource/AudioResource.h diff --git a/Editor/Editor.cpp b/Editor/Editor.cpp index dcee039b..b7f0514d 100644 --- a/Editor/Editor.cpp +++ b/Editor/Editor.cpp @@ -121,7 +121,7 @@ int ApplicationMain(int argc, char* argv[]) // Initialize Engine & Window Engine::Init(); - auto& window = Engine::GetCurrentWindow(); + auto window = Engine::GetCurrentWindow(); window->SetSize(launchSettings.resolution); window->SetTitle(launchSettings.windowTitle); diff --git a/Editor/src/ComponentsPanel/AudioEmitterPanel.h b/Editor/src/ComponentsPanel/AudioEmitterPanel.h index 8c15f795..85f925fa 100644 --- a/Editor/src/ComponentsPanel/AudioEmitterPanel.h +++ b/Editor/src/ComponentsPanel/AudioEmitterPanel.h @@ -56,6 +56,16 @@ public: 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(); @@ -85,6 +95,51 @@ public: 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(); } diff --git a/Editor/src/ComponentsPanel/SkinnedModelPanel.h b/Editor/src/ComponentsPanel/SkinnedModelPanel.h index cdba235d..12d3c73e 100644 --- a/Editor/src/ComponentsPanel/SkinnedModelPanel.h +++ b/Editor/src/ComponentsPanel/SkinnedModelPanel.h @@ -126,7 +126,7 @@ public: uint32_t animIndex = model->GetCurrentAnimationIndex(); uint32_t oldAnimIndex = animIndex; - auto& animations = model->GetAnimations(); + auto animations = model->GetAnimations(); if (ImGui::BeginCombo("Type", model->GetCurrentAnimation()->GetName().c_str())) { for (int n = 0; n < model->GetAnimationsCount(); n++) diff --git a/Editor/src/Misc/GizmoDrawer.cpp b/Editor/src/Misc/GizmoDrawer.cpp index 83a466a0..737a392c 100644 --- a/Editor/src/Misc/GizmoDrawer.cpp +++ b/Editor/src/Misc/GizmoDrawer.cpp @@ -175,7 +175,7 @@ void GizmoDrawer::DrawGizmos(Ref scene) auto capsuleColliderView = scene->m_Registry.view(); for (auto e : capsuleColliderView) { - auto& [transform, capsule] = scene->m_Registry.get(e); + auto [transform, capsule] = scene->m_Registry.get(e); const auto entityId = (uint32_t)e; if (_CapsuleEntity.find(entityId) == _CapsuleEntity.end()) @@ -199,7 +199,7 @@ void GizmoDrawer::DrawGizmos(Ref scene) auto cylinderColliderView = scene->m_Registry.view(); for (auto e : cylinderColliderView) { - auto& [transform, cylinder] = scene->m_Registry.get(e); + auto [transform, cylinder] = scene->m_Registry.get(e); const auto entityId = (uint32_t)e; if (_CylinderEntity.find(entityId) == _CylinderEntity.end()) @@ -235,7 +235,7 @@ void GizmoDrawer::DrawGizmos(Ref scene) auto meshColliderView = scene->m_Registry.view(); for (auto e : meshColliderView) { - auto& [transform, mesh, model] = scene->m_Registry.get(e); + auto [transform, mesh, model] = scene->m_Registry.get(e); // Component has no mesh set. if (!model.ModelResource) diff --git a/Editor/src/Misc/PopupHelper.h b/Editor/src/Misc/PopupHelper.h index 7e9c27d8..31ed82c7 100644 --- a/Editor/src/Misc/PopupHelper.h +++ b/Editor/src/Misc/PopupHelper.h @@ -6,5 +6,5 @@ class PopupHelper public: static void OpenPopup(const std::string& id); static bool DefineConfirmationDialog(const std::string& id, const std::string& text); - static bool PopupHelper::DefineTextDialog(const std::string& id, std::string& currentText); + static bool DefineTextDialog(const std::string& id, std::string& currentText); }; diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index 838f1318..65c2357a 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -269,7 +269,7 @@ namespace Nuake { if (const int result = gbuffer.ReadPixel(3, pixelPos); result > 0) { - auto& ent = Entity{ (entt::entity)(result - 1), Engine::GetCurrentScene().get() }; + auto ent = Entity{ (entt::entity)(result - 1), Engine::GetCurrentScene().get() }; if (ent.IsValid()) { Selection = EditorSelection(ent); @@ -423,9 +423,9 @@ namespace Nuake { ImGui::TableNextColumn(); { bool& isVisible = e.GetComponent().Visible; - char* visibilityIcon = isVisible ? ICON_FA_EYE : ICON_FA_EYE_SLASH; + std::string visibilityIcon = isVisible ? ICON_FA_EYE : ICON_FA_EYE_SLASH; ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0 }); - if (ImGui::Button(visibilityIcon, { 40, 0 })) + if (ImGui::Button(visibilityIcon.c_str(), {40, 0})) { isVisible = !isVisible; } @@ -1540,7 +1540,7 @@ namespace Nuake { _WelcomeWindow->LoadQueuedProject(); isLoadingProjectQueue = false; - auto& window = Window::Get(); + auto window = Window::Get(); window->SetDecorated(true); window->SetSize({ 1900, 1000 }); window->Center(); diff --git a/Editor/src/Windows/LoadingSplash.h b/Editor/src/Windows/LoadingSplash.h index 5f36f8ea..698f1cfe 100644 --- a/Editor/src/Windows/LoadingSplash.h +++ b/Editor/src/Windows/LoadingSplash.h @@ -16,7 +16,7 @@ private: Ref _NuakeLogo; public: - static LoadingSplash& LoadingSplash::Get() + static LoadingSplash& Get() { static LoadingSplash instance; return instance; diff --git a/Editor/src/Windows/ProjectInterface.cpp b/Editor/src/Windows/ProjectInterface.cpp index f899a190..e936659a 100644 --- a/Editor/src/Windows/ProjectInterface.cpp +++ b/Editor/src/Windows/ProjectInterface.cpp @@ -76,7 +76,7 @@ namespace Nuake { { //ImGuiTextSTD("Name", p.name); ImGui::TableNextColumn(); - std::string current_item = NULL; + std::string current_item = ""; if (ImGui::BeginCombo(("TypeSelection" + std::to_string(idx)).c_str(), current_item.c_str())) { for (int n = 0; n < IM_ARRAYSIZE(items); n++) diff --git a/Nuake/src/Audio/AudioManager.cpp b/Nuake/src/Audio/AudioManager.cpp index d031f5ef..c042dd84 100644 --- a/Nuake/src/Audio/AudioManager.cpp +++ b/Nuake/src/Audio/AudioManager.cpp @@ -37,9 +37,30 @@ namespace Nuake { void AudioManager::Deinitialize() { + m_WavSamples.clear(); + m_ActiveClips.clear(); m_Soloud->deinit(); } + void AudioManager::SetListenerPosition(const Vector3& position, const Vector3& direction, const Vector3& up) + { + const std::lock_guard lock(m_AudioQueueMutex); + + if (position != m_ListenerPosition || direction != m_ListenerDirection || up != m_ListenerUp) + { + m_ListenerPosition = position; + m_ListenerDirection = direction; + m_ListenerUp = up; + + m_Soloud->set3dListenerParameters(m_ListenerPosition.x, m_ListenerPosition.y, m_ListenerPosition.z, + m_ListenerDirection.x, m_ListenerDirection.y, m_ListenerDirection.z, + m_ListenerUp.x, m_ListenerUp.y, m_ListenerUp.z + ); + + m_Soloud->update3dAudio(); + } + } + void AudioManager::PlayTTS(const std::string& text) { @@ -60,11 +81,53 @@ namespace Nuake { m_AudioQueue.push(request); } + void AudioManager::UpdateVoice(const AudioRequest& request) + { + // Acquire mutex lock + const std::lock_guard lock(m_AudioQueueMutex); + + if (IsVoiceActive(request.audioFile)) + { + if (!m_Soloud->isValidVoiceHandle(m_ActiveClips[request.audioFile])) + { + m_ActiveClips.erase(request.audioFile); + return; + } + } + + SoLoud::handle& voice = m_ActiveClips[request.audioFile]; + m_Soloud->set3dSourcePosition(voice, request.position.x, request.position.y, request.position.z); + m_Soloud->setLooping(voice, request.Loop); + m_Soloud->set3dSourceMinMaxDistance(voice, request.MinDistance, request.MaxDistance); + m_Soloud->set3dSourceAttenuation(voice, 1, request.AttenuationFactor); + m_Soloud->setRelativePlaySpeed(voice, request.speed); + m_Soloud->setPan(voice, request.pan); + m_Soloud->update3dAudio(); + } + + void AudioManager::StopVoice(const std::string& filePath) + { + const std::lock_guard lock(m_AudioQueueMutex); + + if (!IsVoiceActive(filePath)) + { + return; + } + + SoLoud::handle& voice = m_ActiveClips[filePath]; + m_Soloud->stop(voice); + } + bool AudioManager::IsWavLoaded(const std::string& filePath) const { return m_WavSamples.find(filePath) != m_WavSamples.end(); } + bool AudioManager::IsVoiceActive(const std::string& voice) const + { + return m_ActiveClips.find(voice) != m_ActiveClips.end(); + } + void AudioManager::LoadWavAudio(const std::string& filePath) { m_WavSamples[filePath] = SoLoud::Wav(); @@ -73,24 +136,57 @@ namespace Nuake { void AudioManager::AudioThreadLoop() { + + while(m_AudioThreadRunning) { // Acquire mutex lock const std::lock_guard lock(m_AudioQueueMutex); + //CleanupInactiveVoices(); + // Check if we have audio queued while (!m_AudioQueue.empty()) { - AudioRequest& currentAudio = m_AudioQueue.front(); + AudioRequest& audioRequest = m_AudioQueue.front(); + SoLoud::Wav& audio = m_WavSamples[audioRequest.audioFile]; - SoLoud::handle soloudHandle = m_Soloud->play(m_WavSamples[currentAudio.audioFile]); - m_Soloud->setVolume(soloudHandle, currentAudio.volume); - m_Soloud->setPan(soloudHandle, currentAudio.pan); - m_Soloud->setRelativePlaySpeed(soloudHandle, currentAudio.speed); + SoLoud::handle soloudHandle; + if (!audioRequest.spatialized) + { + soloudHandle = m_Soloud->play(audio); + m_Soloud->setVolume(soloudHandle, audioRequest.volume); + m_Soloud->setPan(soloudHandle, audioRequest.pan); + m_Soloud->setRelativePlaySpeed(soloudHandle, audioRequest.speed); + m_Soloud->setLooping(soloudHandle, audioRequest.Loop); + } + else + { + const Vector3& position = audioRequest.position; + soloudHandle = m_Soloud->play3d(audio, position.x, position.y, position.z); + m_Soloud->set3dSourceMinMaxDistance(soloudHandle, audioRequest.MinDistance, audioRequest.MaxDistance); + m_Soloud->set3dSourceAttenuation(soloudHandle, 1, audioRequest.AttenuationFactor); + m_Soloud->setLooping(soloudHandle, audioRequest.Loop); + } + + m_ActiveClips[audioRequest.audioFile] = soloudHandle; // Remove item from queue. m_AudioQueue.pop(); } } } + + void AudioManager::CleanupInactiveVoices() + { + if (m_ActiveClips.empty()) + { + return; + } + + std::erase_if(m_ActiveClips, [this](const auto& item) + { + return !m_Soloud->isValidVoiceHandle(item.second); + }); + } } \ No newline at end of file diff --git a/Nuake/src/Audio/AudioManager.h b/Nuake/src/Audio/AudioManager.h index a4bd0488..8742051e 100644 --- a/Nuake/src/Audio/AudioManager.h +++ b/Nuake/src/Audio/AudioManager.h @@ -1,25 +1,17 @@ #pragma once #include "src/Core/Core.h" +#include #include #include + namespace SoLoud { class Soloud; class AudioSource; } -// Temp code -struct AudioRequest -{ - std::string audioFile; - float volume = 1.0f; - float pan = 0.0f; - float speed = 1.0f; - -}; - namespace SoLoud { class Wav; @@ -27,6 +19,20 @@ namespace SoLoud namespace Nuake { + struct AudioRequest + { + std::string audioFile; + float volume = 1.0f; + float pan = 0.0f; + float speed = 1.0f; + bool spatialized = false; + Vector3 position; + float MinDistance = 1.0f; + float MaxDistance = 25.0f; + float AttenuationFactor = 1.0f; + bool Loop = false; + }; + // This is a singleton that manages everything for audio. class AudioManager { @@ -41,7 +47,13 @@ namespace Nuake std::atomic m_AudioQueued = { false }; std::queue m_AudioQueue; + Vector3 m_ListenerPosition; + Vector3 m_ListenerDirection; + Vector3 m_ListenerUp; + std::unordered_map m_WavSamples; + std::unordered_map m_ActiveClips; + public: AudioManager(); ~AudioManager(); @@ -59,12 +71,20 @@ namespace Nuake float GetVolume() const; void SetVolume(float volume); + void SetListenerPosition(const Vector3& position, const Vector3& direction, const Vector3& up); + void PlayTTS(const std::string& text); void QueueWavAudio(const AudioRequest& request); + void UpdateVoice(const AudioRequest & request); + void StopVoice(const std::string& filePath); bool IsWavLoaded(const std::string& filePath) const; + bool IsVoiceActive(const std::string & voice) const; void LoadWavAudio(const std::string& filePath); + private: void AudioThreadLoop(); + + void CleanupInactiveVoices(); }; } diff --git a/Nuake/src/Core/FileSystem.cpp b/Nuake/src/Core/FileSystem.cpp index a7b1c642..17bcab2d 100644 --- a/Nuake/src/Core/FileSystem.cpp +++ b/Nuake/src/Core/FileSystem.cpp @@ -192,7 +192,7 @@ namespace Nuake Ref FileSystem::GetFile(const std::string& path) { // Note, Might be broken on other platforms. - auto& splits = String::Split(path, '/'); + auto splits = String::Split(path, '/'); int currentDepth = -1; std::string currentDirName = "."; diff --git a/Nuake/src/Core/Physics/DynamicWorld.cpp b/Nuake/src/Core/Physics/DynamicWorld.cpp index 7ee93c9f..da062a48 100644 --- a/Nuake/src/Core/Physics/DynamicWorld.cpp +++ b/Nuake/src/Core/Physics/DynamicWorld.cpp @@ -338,7 +338,7 @@ namespace Nuake settings->mPredictiveContactDistance = 0.01f; settings->mShape = GetJoltShape(cc->Shape); - auto& joltPosition = JPH::Vec3(cc->Position.x, cc->Position.y, cc->Position.z); + auto joltPosition = JPH::Vec3(cc->Position.x, cc->Position.y, cc->Position.z); const Quat& bodyRotation = cc->Rotation; const auto& joltRotation = JPH::Quat(bodyRotation.x, bodyRotation.y, bodyRotation.z, bodyRotation.w); @@ -487,14 +487,18 @@ namespace Nuake if(ts > minStepDuration) { +#ifdef NK_DEBUG Logger::Log("Large step detected: " + std::to_string(ts), "physics", WARNING); +#endif collisionSteps = static_cast(ts) / minStepDuration; } +#ifdef NK_DEBUG if (collisionSteps >= maxStepCount) { Logger::Log("Very large step detected: " + std::to_string(ts), "physics", WARNING); } +#endif // Prevents having too many steps and running out of jobs collisionSteps = std::min(collisionSteps, maxStepCount); @@ -502,7 +506,6 @@ namespace Nuake // Step the world try { - // TODO: Potential memory leak with new keyword. auto joltTempAllocator = CreateRef(); JPH::CharacterVirtual::ExtendedUpdateSettings joltUpdateSettings; @@ -563,11 +566,6 @@ namespace Nuake if (!_registeredCharacters.empty()) { - for (auto& character : _registeredCharacters) - { - //character.second->RemoveFromPhysicsSystem(); - } - _registeredCharacters.clear(); } } diff --git a/Nuake/src/Rendering/Buffers/VertexBufferLayout.h b/Nuake/src/Rendering/Buffers/VertexBufferLayout.h index 2434eb38..ab3db790 100644 --- a/Nuake/src/Rendering/Buffers/VertexBufferLayout.h +++ b/Nuake/src/Rendering/Buffers/VertexBufferLayout.h @@ -34,7 +34,6 @@ namespace Nuake { template void Push(unsigned int count) { - static_assert(false); } template<> diff --git a/Nuake/src/Rendering/PostFX/SSAO.cpp b/Nuake/src/Rendering/PostFX/SSAO.cpp index 5b7f7c7b..29c81f70 100644 --- a/Nuake/src/Rendering/PostFX/SSAO.cpp +++ b/Nuake/src/Rendering/PostFX/SSAO.cpp @@ -21,12 +21,12 @@ namespace Nuake _ssaoFramebuffer = CreateRef(false, Vector2(_size)); - auto& renderTarget = CreateRef(_size, GL_RGBA, GL_RGBA16F, GL_FLOAT); + auto renderTarget = CreateRef(_size, GL_RGBA, GL_RGBA16F, GL_FLOAT); _ssaoFramebuffer->SetTexture(renderTarget, GL_COLOR_ATTACHMENT0); _ssaoBlurFramebuffer = CreateRef(false, Vector2(_size)); - auto& renderTargetBlur = CreateRef(_size, GL_RGBA, GL_RGBA16F, GL_FLOAT); + auto renderTargetBlur = CreateRef(_size, GL_RGBA, GL_RGBA16F, GL_FLOAT); _ssaoBlurFramebuffer->SetTexture(renderTargetBlur); } diff --git a/Nuake/src/Rendering/Renderer2D.cpp b/Nuake/src/Rendering/Renderer2D.cpp index 7028cf11..1e3f0675 100644 --- a/Nuake/src/Rendering/Renderer2D.cpp +++ b/Nuake/src/Rendering/Renderer2D.cpp @@ -95,7 +95,7 @@ namespace Nuake float lineHeight = 0.0f; for (char const& c : str) { - Char& letter = style.font->GetChar((int)c); + Char letter = style.font->GetChar((int)c); if (letter.PlaneBounds.top - letter.PlaneBounds.bottom > lineHeight) lineHeight = letter.PlaneBounds.top - letter.PlaneBounds.bottom; @@ -104,7 +104,7 @@ namespace Nuake float advance = 0.0f; for (char const& c : str) { - Char& letter = style.font->GetChar((int)c); + Char letter = style.font->GetChar((int)c); advance += letter.Advance * style.fontSize; } return Vector2(advance, lineHeight * style.fontSize); @@ -121,7 +121,7 @@ namespace Nuake float lineHeight = 0.0f; for (char const& c : str) { - Char& letter = style.font->GetChar((int)c); + Char letter = style.font->GetChar((int)c); if (letter.PlaneBounds.top - letter.PlaneBounds.bottom > lineHeight) lineHeight = letter.PlaneBounds.top - letter.PlaneBounds.bottom; @@ -130,7 +130,7 @@ namespace Nuake float advance = 0.0f; for (char const& c : str) { - Char& letter = style.font->GetChar((int)c); + Char letter = style.font->GetChar((int)c); Matrix4 mat = glm::translate(model, Vector3(advance, (-(letter.PlaneBounds.top ) + (lineHeight)) * style.fontSize, 0.f)); float scaleX = letter.PlaneBounds.right - letter.PlaneBounds.left; diff --git a/Nuake/src/Rendering/SceneRenderer.cpp b/Nuake/src/Rendering/SceneRenderer.cpp index 60dad487..95422edf 100644 --- a/Nuake/src/Rendering/SceneRenderer.cpp +++ b/Nuake/src/Rendering/SceneRenderer.cpp @@ -235,7 +235,7 @@ namespace Nuake if (!visibility.Visible || !sprite.SpriteMesh) continue; - auto& finalQuadTransform = transform.GetGlobalTransform(); + auto finalQuadTransform = transform.GetGlobalTransform(); if (sprite.Billboard) { finalQuadTransform = glm::inverse(mView); @@ -358,7 +358,7 @@ namespace Nuake if (!visibility.Visible || !sprite.SpriteMesh) continue; - auto& finalQuadTransform = transform.GetGlobalTransform(); + auto finalQuadTransform = transform.GetGlobalTransform(); if (sprite.Billboard) { finalQuadTransform = glm::inverse(mView); diff --git a/Nuake/src/Rendering/Textures/Texture.cpp b/Nuake/src/Rendering/Textures/Texture.cpp index 06b06bd1..64a64984 100644 --- a/Nuake/src/Rendering/Textures/Texture.cpp +++ b/Nuake/src/Rendering/Textures/Texture.cpp @@ -71,7 +71,7 @@ namespace Nuake { m_RendererId = 0; int channels = 0; - m_LocalBuffer = stbi_load_from_memory(data, len, &m_Width, &m_Height, &channels, 0); + m_LocalBuffer = stbi_load_from_memory(data, len, &m_Width, &m_Height, &channels, 4); glGenTextures(1, &m_RendererId); glBindTexture(GL_TEXTURE_2D, m_RendererId); glGenerateMipmap(GL_TEXTURE_2D); diff --git a/Nuake/src/Resource/AudioResource.h b/Nuake/src/Resource/AudioResource.h new file mode 100644 index 00000000..e997821f --- /dev/null +++ b/Nuake/src/Resource/AudioResource.h @@ -0,0 +1,12 @@ +#pragma once +#include "src/Resource/Resource.h" + +namespace Nuake { + + class AudioResource : public Resource + { + public: + std::string Path; + + }; +} \ No newline at end of file diff --git a/Nuake/src/Resource/ModelLoader.cpp b/Nuake/src/Resource/ModelLoader.cpp index 7aece8b2..2efb289f 100644 --- a/Nuake/src/Resource/ModelLoader.cpp +++ b/Nuake/src/Resource/ModelLoader.cpp @@ -147,7 +147,7 @@ namespace Nuake SkeletonNode rootSkeletonNode; ProcessAnimationNode(rootSkeletonNode, scene->mRootNode); - model->SetSkeletonRootNode(std::move(rootSkeletonNode)); + model->SetSkeletonRootNode(rootSkeletonNode); model->SetAnimations(std::move(animations)); } @@ -189,10 +189,10 @@ namespace Nuake Ref ModelLoader::ProcessSkinnedMesh(aiMesh* node, const aiScene* scene) { - auto& vertices = ProcessSkinnedVertices(node); - auto& indices = ProcessIndices(node); - auto& material = ProcessMaterials(scene, node); - auto& bones = std::vector(); + auto vertices = ProcessSkinnedVertices(node); + auto indices = ProcessIndices(node); + auto material = ProcessMaterials(scene, node); + auto bones = std::vector(); if (node->HasBones()) { diff --git a/Nuake/src/Scene/Components/AudioEmitterComponent.cpp b/Nuake/src/Scene/Components/AudioEmitterComponent.cpp index 17550e8b..35b75249 100644 --- a/Nuake/src/Scene/Components/AudioEmitterComponent.cpp +++ b/Nuake/src/Scene/Components/AudioEmitterComponent.cpp @@ -1,13 +1,20 @@ #include "AudioEmitterComponent.h" namespace Nuake { + json AudioEmitterComponent::Serialize() { BEGIN_SERIALIZE(); SERIALIZE_VAL(FilePath); + SERIALIZE_VAL(IsPlaying); SERIALIZE_VAL(Volume); SERIALIZE_VAL(Pan); SERIALIZE_VAL(PlaybackSpeed); + SERIALIZE_VAL(Spatialized); + SERIALIZE_VAL(MinDistance); + SERIALIZE_VAL(MaxDistance); + SERIALIZE_VAL(AttenuationFactor); + SERIALIZE_VAL(Loop); END_SERIALIZE(); } @@ -15,8 +22,14 @@ namespace Nuake { { DESERIALIZE_VAL(FilePath); DESERIALIZE_VAL(Volume); + DESERIALIZE_VAL(IsPlaying); DESERIALIZE_VAL(Pan); DESERIALIZE_VAL(PlaybackSpeed); + DESERIALIZE_VAL(Spatialized); + DESERIALIZE_VAL(MinDistance); + DESERIALIZE_VAL(MaxDistance); + DESERIALIZE_VAL(AttenuationFactor); + DESERIALIZE_VAL(Loop); return true; } } \ No newline at end of file diff --git a/Nuake/src/Scene/Components/AudioEmitterComponent.h b/Nuake/src/Scene/Components/AudioEmitterComponent.h index c4d04a82..52d609b7 100644 --- a/Nuake/src/Scene/Components/AudioEmitterComponent.h +++ b/Nuake/src/Scene/Components/AudioEmitterComponent.h @@ -7,11 +7,19 @@ namespace Nuake { class AudioEmitterComponent { public: + std::string FilePath; + + bool IsPlaying = false; + bool Loop = false; + float Volume = 1.0f; float Pan = 0.0f; float PlaybackSpeed = 1.0f; - bool IsPlaying = false; - std::string FilePath; + + bool Spatialized = false; + float MinDistance = 1.0f; + float MaxDistance = 10.0f; + float AttenuationFactor = 1.0f; json Serialize(); bool Deserialize(const json& j); diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index b3e2985d..daff8511 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -464,7 +464,7 @@ namespace Nuake if (!parentComponent.HasParent) continue; - auto& entity = Entity{ e, this }; + auto entity = Entity{ e, this }; auto parentEntity = GetEntityByID(parentComponent.ParentID); parentEntity.AddChild(entity); } diff --git a/Nuake/src/Scene/Scene.h b/Nuake/src/Scene/Scene.h index cd9afff6..cd19b16a 100644 --- a/Nuake/src/Scene/Scene.h +++ b/Nuake/src/Scene/Scene.h @@ -80,11 +80,6 @@ namespace Nuake Ref GetEnvironment() const; void SetEnvironment(Ref env); - template - Ref GetResource(const UUID& uuid) - { - return m_Resources[uuid]; - } bool Save(); bool SaveAs(const std::string& path); diff --git a/Nuake/src/Scene/Systems/AnimationSystem.cpp b/Nuake/src/Scene/Systems/AnimationSystem.cpp index f384d495..24a9336e 100644 --- a/Nuake/src/Scene/Systems/AnimationSystem.cpp +++ b/Nuake/src/Scene/Systems/AnimationSystem.cpp @@ -47,7 +47,7 @@ namespace Nuake { auto& animationTrack = animation->GetTrack(bone.Name); - Entity& boneEnt = m_Scene->GetEntityByID(bone.EntityHandle); + Entity boneEnt = m_Scene->GetEntityByID(bone.EntityHandle); if (boneEnt.IsValid()) { auto& transformComponent = boneEnt.GetComponent(); diff --git a/Nuake/src/Scene/Systems/AudioSystem.cpp b/Nuake/src/Scene/Systems/AudioSystem.cpp index 7c821b61..49e7a9a0 100644 --- a/Nuake/src/Scene/Systems/AudioSystem.cpp +++ b/Nuake/src/Scene/Systems/AudioSystem.cpp @@ -1,5 +1,6 @@ #include "AudioSystem.h" +#include "Engine.h" #include "src/Scene/Scene.h" #include "src/Scene/Entities/Entity.h" #include "src/Scene/Components/AudioEmitterComponent.h" @@ -23,6 +24,19 @@ namespace Nuake void AudioSystem::Update(Timestep ts) { + auto& audioManager = AudioManager::Get(); + + // Update 3D listener of the audio system + auto currentCamera = m_Scene->GetCurrentCamera(); + + Vector3 direction = currentCamera->GetDirection(); + if (Engine::IsPlayMode()) + { + direction *= Vector3(-1, -1, -1); + } + + audioManager.SetListenerPosition(currentCamera->GetTranslation(), std::move(direction), currentCamera->GetUp()); + auto view = m_Scene->m_Registry.view(); for (auto& e : view) { @@ -30,21 +44,50 @@ namespace Nuake if (audioEmitterComponent.FilePath.empty()) { + // Doesn't have a file continue; } - if (audioEmitterComponent.IsPlaying) + const bool isPlaying = audioEmitterComponent.IsPlaying; + const std::string absoluteFilePath = FileSystem::RelativeToAbsolute(audioEmitterComponent.FilePath); + const bool isVoiceActive = audioManager.IsVoiceActive(absoluteFilePath); + + AudioRequest audioRequest; + audioRequest.audioFile = absoluteFilePath; + audioRequest.pan = audioEmitterComponent.Pan; + audioRequest.volume = audioEmitterComponent.Volume; + audioRequest.speed = audioEmitterComponent.PlaybackSpeed; + audioRequest.spatialized = audioEmitterComponent.Spatialized; + audioRequest.Loop = audioEmitterComponent.Loop; + audioRequest.position = transformComponent.GetGlobalTransform()[3]; + audioRequest.MinDistance = audioEmitterComponent.MinDistance; + audioRequest.MaxDistance = audioEmitterComponent.MaxDistance; + audioRequest.AttenuationFactor = audioEmitterComponent.AttenuationFactor; + + if (isVoiceActive) { - const std::string absoluteFilePath = FileSystem::RelativeToAbsolute(audioEmitterComponent.FilePath); - - AudioRequest audioRequest; - audioRequest.audioFile = absoluteFilePath; - audioRequest.pan = audioEmitterComponent.Pan; - audioRequest.volume = audioEmitterComponent.Volume; - audioRequest.speed = audioEmitterComponent.PlaybackSpeed; - - AudioManager::Get().QueueWavAudio(std::move(audioRequest)); - audioEmitterComponent.IsPlaying = false; + if (!isPlaying && audioEmitterComponent.Loop) + { + audioManager.StopVoice(absoluteFilePath); // Stop audio + } + else + { + // Update the active voice with new params + audioManager.UpdateVoice(audioRequest); + } + } + else if (isPlaying) + { + // Reset the play status to false since the audio has been fired + if (!audioEmitterComponent.Loop) + { + audioManager.QueueWavAudio(std::move(audioRequest)); + audioEmitterComponent.IsPlaying = false; + } + else if (!isVoiceActive) + { + audioManager.QueueWavAudio(std::move(audioRequest)); + } } } } diff --git a/Nuake/src/Scene/Systems/ParticleSystem.cpp b/Nuake/src/Scene/Systems/ParticleSystem.cpp index aa8d0ac0..a23a45e9 100644 --- a/Nuake/src/Scene/Systems/ParticleSystem.cpp +++ b/Nuake/src/Scene/Systems/ParticleSystem.cpp @@ -19,7 +19,7 @@ namespace Nuake void ParticleSystem::Update(Timestep ts) { - auto& view = m_Scene->m_Registry.view(); + auto view = m_Scene->m_Registry.view(); for (auto& e : view) { auto [transformComponent, emitterComponent] = view.get(e); @@ -42,7 +42,7 @@ namespace Nuake void ParticleSystem::FixedUpdate(Timestep ts) { - auto& view = m_Scene->m_Registry.view(); + auto view = m_Scene->m_Registry.view(); for (auto& e : view) { auto [transformComponent, emitterComponent] = view.get(e); diff --git a/Nuake/src/Scene/Systems/ScriptingSystem.cpp b/Nuake/src/Scene/Systems/ScriptingSystem.cpp index 4b9d3578..cfba62d3 100644 --- a/Nuake/src/Scene/Systems/ScriptingSystem.cpp +++ b/Nuake/src/Scene/Systems/ScriptingSystem.cpp @@ -15,7 +15,7 @@ namespace Nuake { Logger::Log("Initializing ScriptingSystem"); - auto& entities = m_Scene->m_Registry.view(); + auto entities = m_Scene->m_Registry.view(); for (auto& e : entities) { WrenScriptComponent& wren = entities.get(e); diff --git a/Nuake/src/Scripting/WrenScript.cpp b/Nuake/src/Scripting/WrenScript.cpp index 61bacc56..827681d9 100644 --- a/Nuake/src/Scripting/WrenScript.cpp +++ b/Nuake/src/Scripting/WrenScript.cpp @@ -25,7 +25,7 @@ namespace Nuake { bool hasFoundModule = false; - auto& splits = String::Split(fileContent, ' '); + auto splits = String::Split(fileContent, ' '); for (unsigned int i = 0; i < splits.size(); i++) { std::string s = splits[i]; diff --git a/Runtime/Runtime.cpp b/Runtime/Runtime.cpp index f8674e7c..81d769ae 100644 --- a/Runtime/Runtime.cpp +++ b/Runtime/Runtime.cpp @@ -22,14 +22,14 @@ int ApplicationMain(int argc, char* argv[]) if (!FileSystem::FileExists(projectPath)) { Logger::Log("game.project not found", "runtime", CRITICAL); - return; + return -1; } const std::string& projectfileContent = FileSystem::ReadFile(projectPath, true); if (projectfileContent.empty()) { Logger::Log("game.project was empty", "runtime", CRITICAL); - return; + return -1; } project->Deserialize(json::parse(projectfileContent)); @@ -90,7 +90,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR cdmline, int cmds #else -void main(int argc, char* argv[]) +int main(int argc, char* argv[]) { return ApplicationMain(argc, argv); } diff --git a/premake5.lua b/premake5.lua index 61a6a499..ae5690c4 100644 --- a/premake5.lua +++ b/premake5.lua @@ -73,7 +73,7 @@ project "Nuake" } filter "system:windows" - cppdialect "C++17" + cppdialect "C++20" staticruntime "On" defines { "NK_WIN" @@ -154,7 +154,7 @@ project "NuakeRuntime" } filter "system:windows" - cppdialect "C++17" + cppdialect "C++20" staticruntime "On" defines { "NK_WIN" @@ -243,7 +243,7 @@ project "Editor" } filter "system:windows" - cppdialect "C++17" + cppdialect "C++20" staticruntime "On" filter "configurations:Debug"