diff --git a/examples/DopplerEffect/main.cpp b/examples/DopplerEffect/main.cpp index cceaf07f6..778fdaef5 100644 --- a/examples/DopplerEffect/main.cpp +++ b/examples/DopplerEffect/main.cpp @@ -12,10 +12,8 @@ #include #include #include +#include #include -#include -#include -#include #include #include #include @@ -27,6 +25,7 @@ int main() resourceDir = "../.." / resourceDir; Nz::Application app; + app.AddComponent(); Nz::Sound sound; if (!sound.LoadFromFile(resourceDir / "Audio/siren.wav")) @@ -36,44 +35,33 @@ int main() return 1; } - std::cout << "Demonstration de l'effet doppler avec Nazara" << std::endl; - std::cout << "Appuyez sur entree pour demarrer" << std::endl; - std::cout << "Appuyez sur echap pour arreter" << std::endl; + std::cout << "Doppler effect demo" << std::endl; + std::cout << "Press enter to start" << std::endl; std::getchar(); - // On fait en sorte de répéter le son + // Make a repeating sound, located to the left (and a bit forward so it doesn't switch from left to right speaker brutally) with a right velocity sound.EnableLooping(true); - - // La source du son se situe vers la gauche (Et un peu en avant) sound.SetPosition(Nz::Vector3f::Left() * 50.f + Nz::Vector3f::Forward() * 5.f); - - // Et possède une vitesse de 10 par seconde vers la droite sound.SetVelocity(Nz::Vector3f::Right() * 10.f); - // On joue le son sound.Play(); - Nz::MillisecondClock clock; - app.AddUpdaterFunc([&] + app.AddUpdaterFunc([&](Nz::Time elapsedTime) { std::this_thread::sleep_for(std::chrono::milliseconds(1000 / 30)); if (sound.GetStatus() != Nz::SoundStatus::Playing) - { - // On arrête le son et l'application - sound.Stop(); app.Quit(); - } - // On bouge la source du son en fonction du temps depuis chaque mise à jour - Nz::Vector3f pos = sound.GetPosition() + sound.GetVelocity() * clock.Restart().AsSeconds(); + // Move sound position according to its velocity + Nz::Vector3f pos = sound.GetPosition() + sound.GetVelocity() * elapsedTime.AsSeconds(); sound.SetPosition(pos); std::cout << "Position: " << pos.x << std::endl; - // Si la position de la source atteint une certaine position, ou si l'utilisateur appuie sur echap - if (pos.x > Nz::Vector3f::Right().x * 50.f || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Escape)) + // Stop once far enough + if (pos.x > Nz::Vector3f::Right().x * 50.f) { sound.Stop(); app.Quit(); diff --git a/examples/DopplerEffect/xmake.lua b/examples/DopplerEffect/xmake.lua index 6852238e4..19b0b26b4 100644 --- a/examples/DopplerEffect/xmake.lua +++ b/examples/DopplerEffect/xmake.lua @@ -1,3 +1,3 @@ target("DopplerEffect") - add_deps("NazaraAudio", "NazaraPlatform") - add_files("main.cpp") \ No newline at end of file + add_deps("NazaraAudio") + add_files("main.cpp") diff --git a/examples/PlayMusic/main.cpp b/examples/PlayMusic/main.cpp index 5bee8ab77..f00d9f5ed 100644 --- a/examples/PlayMusic/main.cpp +++ b/examples/PlayMusic/main.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -20,6 +21,7 @@ int main() resourceDir = "../.." / resourceDir; Nz::Application app; + app.AddComponent(); Nz::SoundStreamParams streamParams; streamParams.forceMono = false; diff --git a/include/Nazara/Core/ApplicationBase.hpp b/include/Nazara/Core/ApplicationBase.hpp index 930bd8461..9936a49cb 100644 --- a/include/Nazara/Core/ApplicationBase.hpp +++ b/include/Nazara/Core/ApplicationBase.hpp @@ -27,7 +27,7 @@ namespace Nz ApplicationBase(int argc, const Pointer* argv); ApplicationBase(const ApplicationBase&) = delete; ApplicationBase(ApplicationBase&&) = delete; - ~ApplicationBase() = default; + ~ApplicationBase(); inline void AddUpdater(std::unique_ptr&& functor); template void AddUpdaterFunc(F&& functor); @@ -48,6 +48,8 @@ namespace Nz ApplicationBase& operator=(const ApplicationBase&) = delete; ApplicationBase& operator=(ApplicationBase&&) = delete; + static inline ApplicationBase* Instance(); + protected: template T& AddComponent(Args&&... args); @@ -66,6 +68,8 @@ namespace Nz std::vector m_updaters; HighPrecisionClock m_clock; Time m_currentTime; + + static ApplicationBase* s_instance; }; } diff --git a/include/Nazara/Core/ApplicationBase.inl b/include/Nazara/Core/ApplicationBase.inl index 6128977c8..249aeeb03 100644 --- a/include/Nazara/Core/ApplicationBase.inl +++ b/include/Nazara/Core/ApplicationBase.inl @@ -74,7 +74,12 @@ namespace Nz { m_running = false; } - + + inline ApplicationBase* ApplicationBase::Instance() + { + return s_instance; + } + template T& ApplicationBase::AddComponent(Args&&... args) { diff --git a/include/Nazara/Core/SignalHandlerAppComponent.hpp b/include/Nazara/Core/SignalHandlerAppComponent.hpp new file mode 100644 index 000000000..36187d817 --- /dev/null +++ b/include/Nazara/Core/SignalHandlerAppComponent.hpp @@ -0,0 +1,35 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_CORE_SIGNALHANDLERAPPCOMPONENT_HPP +#define NAZARA_CORE_SIGNALHANDLERAPPCOMPONENT_HPP + +#include +#include + +namespace Nz +{ + class NAZARA_CORE_API SignalHandlerAppComponent : public ApplicationComponent + { + public: + inline SignalHandlerAppComponent(ApplicationBase& app); + SignalHandlerAppComponent(const SignalHandlerAppComponent&) = delete; + SignalHandlerAppComponent(SignalHandlerAppComponent&&) = delete; + ~SignalHandlerAppComponent() = default; + + SignalHandlerAppComponent& operator=(const SignalHandlerAppComponent&) = delete; + SignalHandlerAppComponent& operator=(SignalHandlerAppComponent&&) = delete; + + private: + void InstallSignalHandler(); + + static void HandleInterruptSignal(const char* signalName); + }; +} + +#include + +#endif // NAZARA_CORE_SIGNALHANDLERAPPCOMPONENT_HPP diff --git a/include/Nazara/Core/SignalHandlerAppComponent.inl b/include/Nazara/Core/SignalHandlerAppComponent.inl new file mode 100644 index 000000000..5c9e4c725 --- /dev/null +++ b/include/Nazara/Core/SignalHandlerAppComponent.inl @@ -0,0 +1,16 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +namespace Nz +{ + SignalHandlerAppComponent::SignalHandlerAppComponent(ApplicationBase& app) : + ApplicationComponent(app) + { + InstallSignalHandler(); + } +} + +#include diff --git a/src/Nazara/Core/ApplicationBase.cpp b/src/Nazara/Core/ApplicationBase.cpp index 2b6e3e018..f7b1dc289 100644 --- a/src/Nazara/Core/ApplicationBase.cpp +++ b/src/Nazara/Core/ApplicationBase.cpp @@ -15,6 +15,14 @@ namespace Nz m_running(true), m_currentTime(Time::Zero()) { + NazaraAssert(s_instance == nullptr, "only one instance of ApplicationBase can exist at a given time"); + s_instance = this; + } + + ApplicationBase::~ApplicationBase() + { + assert(s_instance == this); + s_instance = nullptr; } int ApplicationBase::Run() @@ -90,4 +98,6 @@ namespace Nz return m_running; } + + ApplicationBase* ApplicationBase::s_instance = nullptr; } diff --git a/src/Nazara/Core/SignalHandlerAppComponent.cpp b/src/Nazara/Core/SignalHandlerAppComponent.cpp new file mode 100644 index 000000000..0d0712d95 --- /dev/null +++ b/src/Nazara/Core/SignalHandlerAppComponent.cpp @@ -0,0 +1,71 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +#if defined(NAZARA_PLATFORM_WINDOWS) +#include +#elif defined(NAZARA_PLATFORM_POSIX) +#include +#include +#endif + +#include + +namespace Nz +{ + void SignalHandlerAppComponent::InstallSignalHandler() + { + bool succeeded = false; + +#if defined(NAZARA_PLATFORM_WINDOWS) + succeeded = ::SetConsoleCtrlHandler([](DWORD ctrlType) -> BOOL + { + switch (ctrlType) + { + case CTRL_C_EVENT: HandleInterruptSignal("CTRL_C"); break; + case CTRL_BREAK_EVENT: HandleInterruptSignal("CTRL_BREAK"); break; + case CTRL_CLOSE_EVENT: HandleInterruptSignal("CTRL_CLOSE"); break; + case CTRL_LOGOFF_EVENT: HandleInterruptSignal("CTRL_LOGOFF"); break; + case CTRL_SHUTDOWN_EVENT: HandleInterruptSignal("CTRL_SHUTDOWN"); break; + default: + { + std::string signalName = ""; + HandleInterruptSignal(signalName.c_str()); + } + } + + return TRUE; + }, TRUE); +#elif defined(NAZARA_PLATFORM_POSIX) + struct sigaction action; + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + action.sa_handler = [](int sig) + { + HandleInterruptSignal(strsignal(sig)); + }; + + if (sigaction(SIGINT, &action, nullptr) != 0) + succeeded = false; + + if (sigaction(SIGTERM, &action, nullptr) != 0) + succeeded = false; +#endif + + if (!succeeded) + NazaraError("failed to install interruption signal handlers"); + } + + void SignalHandlerAppComponent::HandleInterruptSignal(const char* signalName) + { + assert(ApplicationBase::Instance()); + NazaraNotice("received interruption signal " + std::string(signalName) + ", exiting..."); + + ApplicationBase::Instance()->Quit(); + } +}