Skip to content

Commit

Permalink
Added SoundComponent, polished AudioManager
Browse files Browse the repository at this point in the history
  • Loading branch information
denyskryvytskyi committed Mar 26, 2024
1 parent 0b6db57 commit 03a62b2
Show file tree
Hide file tree
Showing 13 changed files with 174 additions and 55 deletions.
52 changes: 51 additions & 1 deletion Engine/src/Editor/Panels/SceneHierarchyPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "Scene/Components/StaticMeshComponent.h"
#include "Scene/SceneManager.h"

#include "Resources/AudioManager.h"
#include "Resources/MeshLibrary.h"
#include "Resources/TextureManager.h"

Expand Down Expand Up @@ -207,6 +208,7 @@ void SceneHierarchyPanel::DrawProperties()
DisplayAddComponentEntry<TextComponent>("Text");
DisplayAddComponentEntry<RectTransformComponent>("UI Transform");
DisplayAddComponentEntry<SpriteComponent>("Sprite");
DisplayAddComponentEntry<SoundComponent>("Sound");

ImGui::EndPopup();
}
Expand Down Expand Up @@ -398,7 +400,8 @@ void SceneHierarchyPanel::DrawProperties()
DrawComponent<DirectionalLightComponent>("Directional Light", m_selectedEntity, m_context, [](DirectionalLightComponent& component) {
ImGui::Checkbox("Enabled", &component.enabled);

editor::DrawVec3Control("direction", "direction", component.direction);
editor::DrawVec3Control("direction", "Direction", component.direction);
ImGui::Spacing();
editor::DrawRGBColorControl("ambient", component.ambient);
editor::DrawRGBColorControl("diffuse", component.diffuse);
editor::DrawRGBColorControl("specular", component.specular);
Expand Down Expand Up @@ -449,6 +452,53 @@ void SceneHierarchyPanel::DrawProperties()
DrawComponent<SpriteComponent>("Sprite", m_selectedEntity, m_context, [](SpriteComponent& component) {
editor::DrawRGBAColorControl("color##sprite", component.color);
});

// ====== SOUND ======
DrawComponent<SoundComponent>("Sound", m_selectedEntity, m_context, [](SoundComponent& component) {
if (ImGui::Button("Play")) {
component.Play();
}

ImGui::SameLine();
if (ImGui::Button("Pause")) {
component.Pause();
}

ImGui::SameLine();
if (ImGui::Button("Stop")) {
component.Stop();
}

ImGui::Checkbox("Loop", &component.isLooped);

if (editor::DrawSliderFloat("Volume", 0.0f, 1.0f, component.volume)) {
component.UpdateVolume();
}

const auto sounds = gAudioManager.GetSounds();
static std::uint64_t currentSoundIndex = 0;

if (!component.soundName.empty()) {
auto it = std::find(sounds.begin(), sounds.end(), component.soundName);
if (it != sounds.end()) {
currentSoundIndex = std::distance(sounds.begin(), it);
}
}

if (ImGui::BeginCombo("Sound", component.soundName.c_str())) {
for (int i = 0; i < sounds.size(); ++i) {
const bool is_selected = (currentSoundIndex == i);
if (ImGui::Selectable(sounds[i].c_str(), is_selected)) {
currentSoundIndex = i;
component.soundName = sounds[currentSoundIndex];
}

if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
});
}

template<typename ComponentType>
Expand Down
51 changes: 34 additions & 17 deletions Engine/src/Resources/AudioManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ void AudioManager::Init()
void AudioManager::Shutdown()
{
for (auto it : m_sounds) {
if (it.second) {
it.second->drop();
if (it.second.sound) {
it.second.sound->drop();
}
}

Expand All @@ -28,21 +28,21 @@ void AudioManager::Shutdown()

void AudioManager::AddSound(const std::string& name, const std::string& path)
{
irrklang::ISound* sound = nullptr;
irrklang::ISoundSource* source = nullptr;
{
PROFILE_SCOPE(fmt::format("Audio file {} is loaded in:", name));
sound = m_engine->play2D(fmt::format("{}{}", fileSystem::SOUNDS_PATH, path).c_str(), false, true, true);
source = m_engine->addSoundSourceFromFile(fmt::format("{}{}", fileSystem::SOUNDS_PATH, path).c_str(), irrklang::ESM_AUTO_DETECT, true);
}
if (sound) {
m_sounds.insert({ name, sound });
if (source) {
m_sounds.insert({ name, { nullptr, source } });
}
}

void AudioManager::SetVolume(const std::string& name, float volume)
{
auto it = m_sounds.find(name);
if (it != m_sounds.end()) {
it->second->setVolume(volume);
if (it != m_sounds.end() && it->second.sound) {
it->second.sound->setVolume(volume);
} else {
EL_CORE_WARN("Set volume failed: {0} sound isn't exist.", name);
}
Expand All @@ -52,11 +52,16 @@ void AudioManager::Play(const std::string& name, bool looped)
{
auto it = m_sounds.find(name);
if (it != m_sounds.end()) {
auto sound = it->second;
if (sound->isFinished()) {
m_engine->play2D(sound->getSoundSource(), looped, false, true);
} else if (sound->getIsPaused()) {
sound->setIsPaused(false);
if (it->second.sound) {
auto sound = it->second.sound;
if (sound->isFinished()) {
m_engine->play2D(sound->getSoundSource(), looped, false, false);
} else if (sound->getIsPaused()) {
sound->setIsPaused(false);
}
} else {
// first play of the sound using preloaded sound source
it->second.sound = m_engine->play2D(it->second.soundSource, looped, false, true);
}
} else {
EL_CORE_WARN("Audio play failed: {0} isn't exist.", name);
Expand All @@ -66,8 +71,8 @@ void AudioManager::Play(const std::string& name, bool looped)
void AudioManager::Pause(const std::string& name)
{
auto it = m_sounds.find(name);
if (it != m_sounds.end()) {
it->second->setIsPaused(true);
if (it != m_sounds.end() && it->second.sound) {
it->second.sound->setIsPaused(true);
} else {
EL_CORE_WARN("Audio play failed: {0} isn't exist.", name);
}
Expand All @@ -76,10 +81,22 @@ void AudioManager::Pause(const std::string& name)
void AudioManager::Stop(const std::string& name)
{
auto it = m_sounds.find(name);
if (it != m_sounds.end()) {
it->second->stop();
if (it != m_sounds.end() && it->second.sound) {
it->second.sound->stop();
it->second.sound->drop();
it->second.sound = nullptr;
} else {
EL_CORE_WARN("Audio play failed: {0} isn't exist.", name);
}
}
std::vector<std::string> AudioManager::GetSounds() const
{
std::vector<std::string> names;

for (const auto soundInfo : m_sounds) {
names.emplace_back(soundInfo.first);
}

return names;
}
} // namespace elv
11 changes: 10 additions & 1 deletion Engine/src/Resources/AudioManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@ class ISound;
}; // namespace irrklang

namespace elv {

class AudioManager {
private:
struct SoundInfo {
irrklang::ISound* sound { nullptr };
irrklang::ISoundSource* soundSource { nullptr };
};

public:
AudioManager() = default;
AudioManager(const AudioManager&) = delete;
Expand All @@ -23,9 +30,11 @@ class AudioManager {
void Pause(const std::string& name);
void Stop(const std::string& name);

std::vector<std::string> GetSounds() const;

private:
irrklang::ISoundEngine* m_engine { nullptr };
std::unordered_map<std::string, irrklang::ISound*> m_sounds;
std::unordered_map<std::string, SoundInfo> m_sounds;
};

extern AudioManager gAudioManager;
Expand Down
22 changes: 22 additions & 0 deletions Engine/src/Scene/Components/SceneComponents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Core/StringId.h"
#include "Events/EventManager.h"
#include "Events/TextureEvent.h"
#include "Resources/AudioManager.h"
#include "Resources/TextureManager.h"

namespace elv {
Expand Down Expand Up @@ -82,4 +83,25 @@ void from_json(const nlohmann::json& j, TextComponent& t)
j.at("color").get_to(t.color);
j.at("is_visible").get_to(t.isVisible);
}

void SoundComponent::Play()
{
gAudioManager.Play(soundName, isLooped);
}

void SoundComponent::Pause()
{
gAudioManager.Pause(soundName);
}

void SoundComponent::Stop()
{
gAudioManager.Stop(soundName);
}

void SoundComponent::UpdateVolume()
{
gAudioManager.SetVolume(soundName, volume);
}

} // namespace elv
13 changes: 13 additions & 0 deletions Engine/src/Scene/Components/SceneComponents.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,4 +214,17 @@ struct TagComponent {
std::string tag;
};

struct SoundComponent {

void Play();
void Pause();
void Stop();

void UpdateVolume();

bool isLooped { true };
float volume { 0.5f };
std::string soundName;
};

} // namespace elv
1 change: 1 addition & 0 deletions Engine/src/Scene/Scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ void Scene::OnInit()
RegisterComponent<DirectionalLightComponent>();
RegisterComponent<SpotLightComponent>();
RegisterComponent<StaticMeshComponent>();
RegisterComponent<SoundComponent>();
if (gEngineSettings.enableSceneGraph) {
RegisterComponent<SceneNodeComponent>();
}
Expand Down
14 changes: 8 additions & 6 deletions Engine/src/Scene/Systems/RenderSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,16 @@ void RenderSystem::OnRender(float dt)
continue;
}

const auto entity = pointLightsPool->GetEntity(i);
if (m_pScene->HasComponent<TransformComponent>(entity)) {
auto& transform = m_pScene->GetComponent<TransformComponent>(entity);
if (pointLight.debugRender) {
const auto entity = pointLightsPool->GetEntity(i);
if (m_pScene->HasComponent<TransformComponent>(entity)) {
auto& transform = m_pScene->GetComponent<TransformComponent>(entity);

m_lightShader->SetVector3f("u_Color.ambient", pointLight.ambient);
m_lightShader->SetVector3f("u_Color.diffuse", pointLight.diffuse);
m_lightShader->SetVector3f("u_Color.ambient", pointLight.ambient);
m_lightShader->SetVector3f("u_Color.diffuse", pointLight.diffuse);

Renderer::Submit(m_lightShader, m_debugLightMesh, transform.worldMatrix);
Renderer::Submit(m_lightShader, m_debugLightMesh, transform.worldMatrix);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020-2023 Denys Kryvytskyi
Copyright (c) 2020-2024 Denys Kryvytskyi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ Elven Engine is primarily a 2D/3D game engine that is being developed from scrat
+ [x] Just cool stuff
- [x] Orthographic camera controller (OrthographicCameraController), that can be used if needed
- [x] Fly(FPS-like) 3D camera support (CameraController)
- [x] Editor camera controller to move on the scene in editor mode.
+ [ ] Multithreading support
- [x] async resources loading: texture, mesh
- [ ] Thread pool
Expand Down
Binary file added Sandbox3D/assets/sounds/back.mp3
Binary file not shown.
Binary file added Sandbox3D/assets/sounds/test.wav
Binary file not shown.
56 changes: 31 additions & 25 deletions Sandbox3D/src/MeshModelSandbox.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#include "MeshModelSandbox.h"

#include <Core/Profiler.h>
#include <Renderer/Mesh.h>
#include <Renderer/RenderTopology.h>
#include <Resources/MeshLibrary.h>
// #include <Renderer/Mesh.h>
// #include <Renderer/RenderTopology.h>
#include <Resources/AudioManager.h>
// #include <Resources/MeshLibrary.h>
#include <Scene/Components/LightComponent.h>
#include <Scene/Components/StaticMeshComponent.h>

Expand All @@ -29,7 +30,7 @@ MeshModelSandbox::MeshModelSandbox()
scene.AddComponent<elv::StaticMeshComponent>(knight, "knight", fmt::format("{}{}", elv::fileSystem::MODELS_PATH, "dark_knight/scene.gltf"));
}

if (false) {
if (true) {
const auto walle = scene.CreateEntity();
m_models.emplace_back(walle);
scene.AddComponent<elv::TagComponent>(walle, "Walle");
Expand Down Expand Up @@ -91,22 +92,26 @@ MeshModelSandbox::MeshModelSandbox()
dirLightComponent.direction = lia::vec3(0.0f, -1.0f, 0.0f);
dirLightComponent.enabled = true;

m_flashLightEntity = scene.CreateEntity();
scene.AddComponent<elv::TagComponent>(m_flashLightEntity, "Spot light");
scene.AddComponent<elv::TransformComponent>(m_flashLightEntity);
auto& spotLightComponent = scene.AddComponent<elv::SpotLightComponent>(m_flashLightEntity);
spotLightComponent.enabled = false;
/* m_flashLightEntity = scene.CreateEntity();
scene.AddComponent<elv::TagComponent>(m_flashLightEntity, "Spot light");
scene.AddComponent<elv::TransformComponent>(m_flashLightEntity);
auto& spotLightComponent = scene.AddComponent<elv::SpotLightComponent>(m_flashLightEntity);
spotLightComponent.enabled = false;
for (size_t i = 0; i < kPointLightsAmount; ++i) {
m_pointLightEntities[i] = scene.CreateEntity();
scene.AddComponent<elv::TagComponent>(m_pointLightEntities[i], fmt::format("Point light {}", i));
auto& transform = scene.AddComponent<elv::TransformComponent>(m_pointLightEntities[i], kPointLightPositions[i]);
auto& pointLightComponent = scene.AddComponent<elv::PointLightComponent>(m_pointLightEntities[i]);
pointLightComponent.enabled = false;
}
for (size_t i = 0; i < kPointLightsAmount; ++i) {
m_pointLightEntities[i] = scene.CreateEntity();
scene.AddComponent<elv::TagComponent>(m_pointLightEntities[i], fmt::format("Point light {}", i));
scene.AddComponent<elv::TransformComponent>(m_pointLightEntities[i], kPointLightPositions[i]);
auto& pointLightComponent = scene.AddComponent<elv::PointLightComponent>(m_pointLightEntities[i]);
pointLightComponent.enabled = false;
}*/

// default environment
SetEnvironment(0);

// audio
elv::gAudioManager.AddSound("background music", "back.mp3");
elv::gAudioManager.AddSound("test", "test.wav");
}

void MeshModelSandbox::OnUpdate(float dt)
Expand Down Expand Up @@ -164,18 +169,19 @@ void MeshModelSandbox::SetEnvironment(const int envIndex)
dirLight.specular = env.dirLight.specular;
dirLight.direction = env.dirLight.direction;

// flashlight
auto& flashLight = scene.GetComponent<elv::SpotLightComponent>(m_flashLightEntity);
flashLight.ambient = env.spotLight.ambient;
flashLight.diffuse = env.spotLight.diffuse;
flashLight.specular = env.spotLight.specular;
// spotlights
for (auto& spotlight : scene.GetComponents<elv::SpotLightComponent>()) {
spotlight.ambient = env.spotLight.ambient;
spotlight.diffuse = env.spotLight.diffuse;
spotlight.specular = env.spotLight.specular;
}

// point lights
auto& pointLights = scene.GetComponents<elv::PointLightComponent>();
for (size_t i = 0; i < kPointLightsAmount; ++i) {
auto& pointLight = scene.GetComponent<elv::PointLightComponent>(m_pointLightEntities[i]);
pointLight.ambient = env.pointLightColors[i] * 0.1f;
pointLight.diffuse = env.pointLightColors[i];
pointLight.specular = env.pointLightColors[i];
pointLights[i].ambient = env.pointLightColors[i] * 0.1f;
pointLights[i].diffuse = env.pointLightColors[i];
pointLights[i].specular = env.pointLightColors[i];
}
}

Expand Down
Loading

0 comments on commit 03a62b2

Please sign in to comment.