Replace float/UInt64 durations by a more precise Time class (#388)

Improve Clock class with atomic RestartIfOver method and allows to choose required precision
This commit is contained in:
Jérôme Leclercq 2022-12-29 21:31:46 +01:00 committed by GitHub
parent 1de5f65536
commit dd421a6385
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
84 changed files with 1278 additions and 663 deletions

View File

@ -1063,16 +1063,16 @@ int main()
window.EnableEventPolling(true);
Nz::Clock updateClock;
Nz::Clock secondClock;
Nz::MillisecondClock updateClock;
Nz::MillisecondClock fpsClock;
unsigned int fps = 0;
std::size_t totalFrameCount = 0;
Nz::Mouse::SetRelativeMouseMode(true);
float elapsedTime = 0.f;
Nz::UInt64 time = Nz::GetElapsedMicroseconds();
Nz::Time elapsedTime = Nz::Time::Zero();
Nz::Time time = Nz::GetElapsedNanoseconds();
auto ComputeLightAnimationSpeed = [](const Nz::Vector3f& position)
{
@ -1095,9 +1095,9 @@ int main()
while (window.IsOpen())
{
Nz::UInt64 now = Nz::GetElapsedMicroseconds();
Nz::Time now = Nz::GetElapsedNanoseconds();
if (lightAnimation)
elapsedTime += (now - time) / 1'000'000.f;
elapsedTime += now - time;
time = now;
Nz::WindowEvent event;
@ -1129,13 +1129,14 @@ int main()
{
if (event.key.scancode == Nz::Keyboard::Scancode::Space)
{
float elapsedSeconds = elapsedTime.AsSeconds();
float rotationSpeed = ComputeLightAnimationSpeed(viewerPos);
auto& spotLight = spotLights.emplace_back();
spotLight.color = Nz::Color(0.4f, 0.4f, 1.f);
spotLight.radius = 5.f;
spotLight.position = AnimateLightPosition(viewerPos, rotationSpeed, -elapsedTime);
spotLight.direction = AnimateLightDirection(camQuat * Nz::Vector3f::Forward(), rotationSpeed, -elapsedTime);
spotLight.position = AnimateLightPosition(viewerPos, rotationSpeed, -elapsedSeconds);
spotLight.direction = AnimateLightDirection(camQuat * Nz::Vector3f::Forward(), rotationSpeed, -elapsedSeconds);
lightUpdate = true;
}
@ -1163,10 +1164,9 @@ int main()
}
}
if (updateClock.GetMilliseconds() > 1000 / 60)
if (std::optional<Nz::Time> deltaTime = updateClock.RestartIfOver(Nz::Time::TickDuration(60)))
{
float cameraSpeed = 2.f * updateClock.GetSeconds();
updateClock.Restart();
float cameraSpeed = 2.f * deltaTime->AsSeconds();
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Up) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Z))
viewerPos += camQuat * Nz::Vector3f::Forward() * cameraSpeed;
@ -1465,7 +1465,9 @@ int main()
modelInstance2.OnTransfer(frame, builder);
planeInstance.OnTransfer(frame, builder);
Nz::EulerAnglesf flareRotation(0.f, 0.f, elapsedTime * 10.f);
float elapsedSeconds = elapsedTime.AsSeconds();
Nz::EulerAnglesf flareRotation(0.f, 0.f, elapsedSeconds * 10.f);
flareInstance.UpdateWorldMatrix(Nz::Matrix4f::Transform(viewerPos + flarePosition, flareRotation));
flareInstance.OnTransfer(frame, builder);
@ -1481,8 +1483,8 @@ int main()
{
float rotationSpeed = ComputeLightAnimationSpeed(spotLight.position);
Nz::Vector3f position = AnimateLightPosition(spotLight.position, rotationSpeed, elapsedTime);
Nz::Vector3f direction = AnimateLightDirection(spotLight.direction, rotationSpeed, elapsedTime);
Nz::Vector3f position = AnimateLightPosition(spotLight.position, rotationSpeed, elapsedSeconds);
Nz::Vector3f direction = AnimateLightDirection(spotLight.direction, rotationSpeed, elapsedSeconds);
Nz::AccessByOffset<Nz::Vector3f&>(lightDataPtr, colorOffset) = Nz::Vector3f(spotLight.color.r, spotLight.color.g, spotLight.color.b);
Nz::AccessByOffset<Nz::Vector3f&>(lightDataPtr, positionOffset) = position;
@ -1565,23 +1567,10 @@ int main()
fps++;
totalFrameCount++;
if (secondClock.GetMilliseconds() >= 1000) // Toutes les secondes
if (fpsClock.RestartIfOver(Nz::Time::Second()))
{
// Et on insère ces données dans le titre de la fenêtre
window.SetTitle(windowTitle + " - " + Nz::NumberToString(fps) + " FPS");
/*
Note: En C++11 il est possible d'insérer de l'Unicode de façon standard, quel que soit l'encodage du fichier,
via quelque chose de similaire à u8"Cha\u00CEne de caract\u00E8res".
Cependant, si le code source est encodé en UTF-8 (Comme c'est le cas dans ce fichier),
cela fonctionnera aussi comme ceci : "Chaîne de caractères".
*/
// Et on réinitialise le compteur de FPS
fps = 0;
// Et on relance l'horloge pour refaire ça dans une seconde
secondClock.Restart();
}
}

View File

@ -53,17 +53,17 @@ int main()
sound.Play();
// La boucle du programme (Pour déplacer le son)
Nz::Clock clock;
Nz::MillisecondClock clock;
while (sound.GetStatus() == Nz::SoundStatus::Playing)
{
// Comme le son se joue dans un thread séparé, on peut mettre en pause le principal régulièrement
int sleepTime = int(1000/60 - clock.GetMilliseconds()); // 60 FPS
Nz::Time sleepTime = Nz::Time::TickDuration(60) - clock.GetElapsedTime(); // 60 FPS
if (sleepTime > 0)
std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
if (sleepTime > Nz::Time::Millisecond())
std::this_thread::sleep_for(sleepTime.AsDuration<std::chrono::milliseconds>());
// On bouge la source du son en fonction du temps depuis chaque mise à jour
Nz::Vector3f pos = sound.GetPosition() + sound.GetVelocity()*clock.GetSeconds();
Nz::Vector3f pos = sound.GetPosition() + sound.GetVelocity() * clock.GetElapsedTime().AsSeconds();
sound.SetPosition(pos);
std::cout << "Sound position: " << pos << std::endl;

View File

@ -104,8 +104,8 @@ int main()
window.EnableEventPolling(true);
Nz::Clock updateClock;
Nz::Clock secondClock;
Nz::MillisecondClock updateClock;
Nz::MillisecondClock fpsClock;
unsigned int fps = 0;
Nz::Mouse::SetRelativeMouseMode(true);
@ -161,10 +161,9 @@ int main()
}
}
if (updateClock.GetMilliseconds() > 1000 / 60)
if (std::optional<Nz::Time> deltaTime = updateClock.RestartIfOver(Nz::Time::TickDuration(60)))
{
float cameraSpeed = 2.f * updateClock.GetSeconds();
updateClock.Restart();
float cameraSpeed = 2.f * deltaTime->AsSeconds();
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Up) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Z))
viewerPos += camQuat * Nz::Vector3f::Forward() * cameraSpeed;
@ -209,23 +208,10 @@ int main()
// On incrémente le compteur de FPS improvisé
fps++;
if (secondClock.GetMilliseconds() >= 1000) // Toutes les secondes
if (fpsClock.RestartIfOver(Nz::Time::Second()))
{
// Et on insère ces données dans le titre de la fenêtre
window.SetTitle(windowTitle + " - " + Nz::NumberToString(fps) + " FPS");
/*
Note: En C++11 il est possible d'insérer de l'Unicode de façon standard, quel que soit l'encodage du fichier,
via quelque chose de similaire à u8"Cha\u00CEne de caract\u00E8res".
Cependant, si le code source est encodé en UTF-8 (Comme c'est le cas dans ce fichier),
cela fonctionnera aussi comme ceci : "Chaîne de caractères".
*/
// Et on réinitialise le compteur de FPS
fps = 0;
// Et on relance l'horloge pour refaire ça dans une seconde
secondClock.Restart();
}
}

View File

@ -68,8 +68,8 @@ int main()
texParams.renderDevice = device;
texParams.loadFormat = Nz::PixelFormat::RGBA8;
std::shared_ptr<Nz::MaterialInstance> material = Nz::Graphics::Instance()->GetDefaultMaterials().phongMaterial->Instantiate();
material->SetTextureProperty("BaseColorMap", Nz::Texture::LoadFromFile(resourceDir / "box.png", texParams));
std::shared_ptr<Nz::MaterialInstance> spriteMaterial = Nz::Graphics::Instance()->GetDefaultMaterials().phongMaterial->Instantiate();
spriteMaterial->SetTextureProperty("BaseColorMap", Nz::Texture::LoadFromFile(resourceDir / "box.png", texParams));
for (std::size_t y = 0; y < 30; ++y)
{
@ -77,7 +77,7 @@ int main()
{
entt::entity spriteEntity = registry.create();
{
std::shared_ptr<Nz::Sprite> sprite = std::make_shared<Nz::Sprite>(material);
std::shared_ptr<Nz::Sprite> sprite = std::make_shared<Nz::Sprite>(spriteMaterial);
sprite->SetSize({ 32.f, 32.f });
sprite->SetOrigin({ 0.5f, 0.5f });
@ -97,10 +97,10 @@ int main()
tilemap->SetOrigin({ 0.5f, 0.5f });
for (std::size_t i = 0; i < 18; ++i)
{
std::shared_ptr<Nz::MaterialInstance> material = Nz::Graphics::Instance()->GetDefaultMaterials().basicTransparent->Clone();
material->SetTextureProperty("BaseColorMap", Nz::Texture::LoadFromFile(resourceDir / "tiles" / (std::to_string(i + 1) + ".png"), texParams));
std::shared_ptr<Nz::MaterialInstance> tileMaterial = Nz::Graphics::Instance()->GetDefaultMaterials().basicTransparent->Clone();
tileMaterial->SetTextureProperty("BaseColorMap", Nz::Texture::LoadFromFile(resourceDir / "tiles" / (std::to_string(i + 1) + ".png"), texParams));
tilemap->SetMaterial(i, material);
tilemap->SetMaterial(i, tileMaterial);
}
for (unsigned int y = 0; y < 20; ++y)
@ -122,14 +122,12 @@ int main()
window.EnableEventPolling(true);
Nz::Clock updateClock;
Nz::Clock secondClock;
Nz::MillisecondClock secondClock;
unsigned int fps = 0;
//Nz::Mouse::SetRelativeMouseMode(true);
float elapsedTime = 0.f;
Nz::UInt64 time = Nz::GetElapsedMicroseconds();
Nz::PidController<Nz::Vector3f> headingController(0.5f, 0.f, 0.05f);
Nz::PidController<Nz::Vector3f> upController(1.f, 0.f, 0.1f);
@ -137,10 +135,6 @@ int main()
bool showColliders = false;
while (window.IsOpen())
{
Nz::UInt64 now = Nz::GetElapsedMicroseconds();
elapsedTime = (now - time) / 1'000'000.f;
time = now;
Nz::WindowEvent event;
while (window.PollEvent(&event))
{
@ -165,13 +159,10 @@ int main()
fps++;
if (secondClock.GetMilliseconds() >= 1000)
if (secondClock.RestartIfOver(Nz::Time::Second()))
{
window.SetTitle(windowTitle + " - " + Nz::NumberToString(fps) + " FPS" + " - " + Nz::NumberToString(registry.alive()) + " entities");
fps = 0;
secondClock.Restart();
}
}

View File

@ -198,25 +198,18 @@ int main()
window.EnableEventPolling(true);
Nz::Clock updateClock;
Nz::Clock secondClock;
Nz::MillisecondClock updateClock;
Nz::MillisecondClock fpsClock;
unsigned int fps = 0;
Nz::Mouse::SetRelativeMouseMode(true);
float elapsedTime = 0.f;
Nz::UInt64 time = Nz::GetElapsedMicroseconds();
Nz::PidController<Nz::Vector3f> headingController(0.3f, 0.f, 0.1f);
Nz::PidController<Nz::Vector3f> upController(1.f, 0.f, 0.1f);
bool showColliders = false;
while (window.IsOpen())
{
Nz::UInt64 now = Nz::GetElapsedMicroseconds();
elapsedTime = (now - time) / 1'000'000.f;
time = now;
Nz::WindowEvent event;
while (window.PollEvent(&event))
{
@ -286,8 +279,10 @@ int main()
}
}
if (updateClock.GetMilliseconds() > 1000 / 60)
if (std::optional<Nz::Time> deltaTime = updateClock.RestartIfOver(Nz::Time::TickDuration(60)))
{
float elapsedTime = deltaTime->AsSeconds();
auto spaceshipView = registry.view<Nz::NodeComponent, Nz::RigidBody3DComponent>();
for (auto&& [entity, node, _] : spaceshipView.each())
{
@ -338,13 +333,10 @@ int main()
fps++;
if (secondClock.GetMilliseconds() >= 1000)
if (fpsClock.RestartIfOver(Nz::Time::Second()))
{
window.SetTitle(windowTitle + " - " + Nz::NumberToString(fps) + " FPS" + " - " + Nz::NumberToString(registry.alive()) + " entities");
fps = 0;
secondClock.Restart();
}
}

View File

@ -357,12 +357,11 @@ int main()
window.EnableEventPolling(true);
Nz::Clock fpsClock, updateClock;
Nz::MillisecondClock fpsClock, updateClock;
float incr = 0.f;
unsigned int currentFrame = 0;
unsigned int nextFrame = 1;
Nz::EulerAnglesf camAngles = Nz::EulerAnglesf(-30.f, 0.f, 0.f);
Nz::UInt64 lastTime = Nz::GetElapsedMicroseconds();
Nz::UInt64 fps = 0;
bool paused = false;
@ -409,9 +408,9 @@ int main()
}
}
if (updateClock.GetMilliseconds() > 1000 / 60)
if (std::optional<Nz::Time> deltaTime = updateClock.RestartIfOver(Nz::Time::TickDuration(60)))
{
float updateTime = updateClock.Restart() / 1'000'000.f;
float updateTime = deltaTime->AsSeconds();
/*auto& playerBody = registry.get<Nz::RigidBody3DComponent>(playerEntity);
@ -533,12 +532,9 @@ int main()
fps++;
if (fpsClock.GetMilliseconds() >= 1000)
if (fpsClock.RestartIfOver(Nz::Time::Second()))
{
fpsClock.Restart();
window.SetTitle(windowTitle + " - " + Nz::NumberToString(fps) + " FPS" + " - " + Nz::NumberToString(registry.alive()) + " entities");
fps = 0;
}
}

View File

@ -127,19 +127,11 @@ int main()
mainWindow.EnableEventPolling(true);
Nz::Clock updateClock;
Nz::Clock secondClock;
Nz::MillisecondClock fpsClock;
unsigned int fps = 0;
float elapsedTime = 0.f;
Nz::UInt64 time = Nz::GetElapsedMicroseconds();
while (mainWindow.IsOpen())
{
Nz::UInt64 now = Nz::GetElapsedMicroseconds();
elapsedTime = (now - time) / 1'000'000.f;
time = now;
Nz::WindowEvent event;
while (mainWindow.PollEvent(&event))
{
@ -158,13 +150,10 @@ int main()
fps++;
if (secondClock.GetMilliseconds() >= 1000)
if (fpsClock.RestartIfOver(Nz::Time::Second()))
{
mainWindow.SetTitle(windowTitle + " - " + Nz::NumberToString(fps) + " FPS" + " - " + Nz::NumberToString(registry.alive()) + " entities");
fps = 0;
secondClock.Restart();
}
}

View File

@ -10,6 +10,7 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Audio/Config.hpp>
#include <Nazara/Audio/Enums.hpp>
#include <Nazara/Core/Time.hpp>
#include <Nazara/Math/Vector3.hpp>
namespace Nz
@ -34,6 +35,7 @@ namespace Nz
virtual float GetAttenuation() const = 0;
virtual float GetMinDistance() const = 0;
virtual float GetPitch() const = 0;
virtual Time GetPlayingOffset() const = 0;
virtual Vector3f GetPosition() const = 0;
virtual UInt32 GetSampleOffset() const = 0;
virtual OffsetWithLatency GetSampleOffsetAndLatency() const = 0;
@ -53,6 +55,7 @@ namespace Nz
virtual void SetBuffer(std::shared_ptr<AudioBuffer> audioBuffer) = 0;
virtual void SetMinDistance(float minDistance) = 0;
virtual void SetPitch(float pitch) = 0;
virtual void SetPlayingOffset(Time offset) = 0;
virtual void SetPosition(const Vector3f& position) = 0;
virtual void SetSampleOffset(UInt32 offset) = 0;
virtual void SetVelocity(const Vector3f& velocity) = 0;
@ -70,7 +73,7 @@ namespace Nz
struct OffsetWithLatency
{
UInt64 sampleOffset;
UInt64 sourceLatency;
Time sourceLatency;
};
private:

View File

@ -11,6 +11,7 @@
#include <Nazara/Audio/AudioBuffer.hpp>
#include <Nazara/Audio/Config.hpp>
#include <Nazara/Audio/Enums.hpp>
#include <Nazara/Core/Time.hpp>
namespace Nz
{
@ -23,7 +24,7 @@ namespace Nz
~DummyAudioBuffer() = default;
AudioFormat GetAudioFormat() const;
UInt32 GetDuration() const;
Time GetDuration() const;
UInt64 GetSampleCount() const override;
UInt64 GetSize() const override;
UInt32 GetSampleRate() const override;

View File

@ -30,6 +30,7 @@ namespace Nz
float GetAttenuation() const override;
float GetMinDistance() const override;
float GetPitch() const override;
Time GetPlayingOffset() const override;
Vector3f GetPosition() const override;
UInt32 GetSampleOffset() const override;
OffsetWithLatency GetSampleOffsetAndLatency() const override;
@ -49,6 +50,7 @@ namespace Nz
void SetBuffer(std::shared_ptr<AudioBuffer> audioBuffer) override;
void SetMinDistance(float minDistance) override;
void SetPitch(float pitch) override;
void SetPlayingOffset(Time offset) override;
void SetPosition(const Vector3f& position) override;
void SetSampleOffset(UInt32 offset) override;
void SetVelocity(const Vector3f& velocity) override;
@ -65,11 +67,11 @@ namespace Nz
private:
void RequeueBuffers();
UInt64 UpdateTime() const;
Time UpdateTime() const;
mutable std::vector<std::shared_ptr<DummyAudioBuffer>> m_queuedBuffers;
mutable std::vector<std::shared_ptr<DummyAudioBuffer>> m_processedBuffers;
mutable Clock m_playClock;
mutable MillisecondClock m_playClock;
mutable SoundStatus m_status;
Vector3f m_position;
Vector3f m_velocity;

View File

@ -9,7 +9,7 @@ namespace Nz
{
inline DummyAudioSource::DummyAudioSource(std::shared_ptr<AudioDevice> device) :
AudioSource(std::move(device)),
m_playClock(0, true),
m_playClock(Time::Zero(), true),
m_status(SoundStatus::Stopped),
m_position(Vector3f::Zero()),
m_velocity(Vector3f::Zero()),

View File

@ -22,7 +22,7 @@ namespace Nz
{
class AudioBuffer;
class NAZARA_AUDIO_API Music : public Resource, public SoundEmitter
class NAZARA_AUDIO_API Music final : public Resource, public SoundEmitter
{
public:
Music();
@ -36,11 +36,12 @@ namespace Nz
void EnableLooping(bool loop) override;
UInt32 GetDuration() const override;
Time GetDuration() const override;
AudioFormat GetFormat() const;
UInt32 GetPlayingOffset() const override;
Time GetPlayingOffset() const;
UInt64 GetSampleCount() const;
UInt32 GetSampleRate() const;
UInt64 GetSampleOffset() const override;
UInt32 GetSampleRate() const override;
SoundStatus GetStatus() const override;
bool IsLooping() const override;
@ -52,7 +53,7 @@ namespace Nz
void Pause() override;
void Play() override;
void SetPlayingOffset(UInt32 offset);
void SeekToSampleOffset(UInt64 offset);
void Stop() override;

View File

@ -34,6 +34,7 @@ namespace Nz
float GetAttenuation() const override;
float GetMinDistance() const override;
float GetPitch() const override;
Time GetPlayingOffset() const override;
Vector3f GetPosition() const override;
UInt32 GetSampleOffset() const override;
OffsetWithLatency GetSampleOffsetAndLatency() const override;
@ -53,6 +54,7 @@ namespace Nz
void SetBuffer(std::shared_ptr<AudioBuffer> audioBuffer) override;
void SetMinDistance(float minDistance) override;
void SetPitch(float pitch) override;
void SetPlayingOffset(Time offset) override;
void SetPosition(const Vector3f& position) override;
void SetSampleOffset(UInt32 offset) override;
void SetVelocity(const Vector3f& velocity) override;

View File

@ -14,7 +14,7 @@
namespace Nz
{
class NAZARA_AUDIO_API Sound : public SoundEmitter
class NAZARA_AUDIO_API Sound final : public SoundEmitter
{
public:
using SoundEmitter::SoundEmitter;
@ -27,8 +27,10 @@ namespace Nz
void EnableLooping(bool loop) override;
const std::shared_ptr<SoundBuffer>& GetBuffer() const;
UInt32 GetDuration() const override;
UInt32 GetPlayingOffset() const override;
Time GetDuration() const override;
Time GetPlayingOffset() const override;
UInt64 GetSampleOffset() const override;
UInt32 GetSampleRate() const override;
SoundStatus GetStatus() const override;
bool IsLooping() const override;
@ -42,7 +44,8 @@ namespace Nz
void Play() override;
void SetBuffer(std::shared_ptr<SoundBuffer> soundBuffer);
void SetPlayingOffset(UInt32 offset);
void SeekToSampleOffset(UInt64 offset) override;
void Stop() override;

View File

@ -16,6 +16,7 @@
#include <Nazara/Core/ResourceLoader.hpp>
#include <Nazara/Core/ResourceManager.hpp>
#include <Nazara/Core/ResourceParameters.hpp>
#include <Nazara/Core/Time.hpp>
#include <memory>
#include <unordered_map>
@ -52,7 +53,7 @@ namespace Nz
const std::shared_ptr<AudioBuffer>& GetAudioBuffer(AudioDevice* device);
inline UInt32 GetDuration() const;
inline Time GetDuration() const;
inline AudioFormat GetFormat() const;
inline const Int16* GetSamples() const;
inline UInt64 GetSampleCount() const;
@ -76,7 +77,7 @@ namespace Nz
std::unordered_map<AudioDevice*, AudioDeviceEntry> m_audioBufferByDevice;
std::unique_ptr<Int16[]> m_samples;
AudioFormat m_format;
UInt32 m_duration;
Time m_duration;
UInt32 m_sampleRate;
UInt64 m_sampleCount;
};

View File

@ -10,10 +10,8 @@ namespace Nz
/*!
* \brief Gets the duration of the sound buffer
* \return Duration of the sound buffer in milliseconds
*
* \remark Produces a NazaraError if there is no sound buffer with NAZARA_AUDIO_SAFE defined
*/
inline UInt32 SoundBuffer::GetDuration() const
inline Time SoundBuffer::GetDuration() const
{
return m_duration;
}

View File

@ -10,6 +10,7 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Audio/Config.hpp>
#include <Nazara/Audio/Enums.hpp>
#include <Nazara/Core/Time.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <limits>
@ -32,11 +33,13 @@ namespace Nz
void EnableSpatialization(bool spatialization);
float GetAttenuation() const;
virtual UInt32 GetDuration() const = 0;
virtual Time GetDuration() const = 0;
float GetMinDistance() const;
float GetPitch() const;
virtual UInt32 GetPlayingOffset() const = 0;
virtual Time GetPlayingOffset() const = 0;
Vector3f GetPosition() const;
virtual UInt64 GetSampleOffset() const = 0;
virtual UInt32 GetSampleRate() const = 0;
Vector3f GetVelocity() const;
virtual SoundStatus GetStatus() const = 0;
float GetVolume() const;
@ -48,6 +51,9 @@ namespace Nz
virtual void Pause() = 0;
virtual void Play() = 0;
virtual void SeekToPlayingOffset(Time offset);
virtual void SeekToSampleOffset(UInt64 offset) = 0;
void SetAttenuation(float attenuation);
void SetMinDistance(float minDistance);
void SetPitch(float pitch);

View File

@ -13,6 +13,7 @@
#include <Nazara/Core/Resource.hpp>
#include <Nazara/Core/ResourceLoader.hpp>
#include <Nazara/Core/ResourceParameters.hpp>
#include <Nazara/Core/Time.hpp>
#include <mutex>
namespace Nz
@ -35,7 +36,7 @@ namespace Nz
SoundStream() = default;
virtual ~SoundStream();
virtual UInt32 GetDuration() const = 0;
virtual Time GetDuration() const = 0;
virtual AudioFormat GetFormat() const = 0;
virtual std::mutex& GetMutex() = 0;
virtual UInt64 GetSampleCount() const = 0;

View File

@ -9,40 +9,46 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Config.hpp>
#include <Nazara/Core/Time.hpp>
#include <optional>
namespace Nz
{
class NAZARA_CORE_API Clock
template<bool HighPrecision>
class Clock
{
public:
Clock(UInt64 startingValue = 0, bool paused = false);
Clock(Time startingValue = Time::Zero(), bool paused = false);
Clock(const Clock& clock) = default;
Clock(Clock&& clock) = default;
Clock(Clock&& clock) noexcept = default;
~Clock() = default;
float GetSeconds() const;
UInt64 GetMicroseconds() const;
UInt64 GetMilliseconds() const;
Time GetElapsedTime() const;
bool IsPaused() const;
void Pause();
UInt64 Restart(UInt64 startingValue = 0, bool paused = false);
Time Restart(Time startingPoint = Time::Zero(), bool paused = false);
std::optional<Time> RestartIfOver(Time time);
void Unpause();
Clock& operator=(const Clock& clock) = default;
Clock& operator=(Clock&& clock) = default;
Clock& operator=(Clock&& clock) noexcept = default;
static Time Now();
private:
UInt64 m_elapsedTime;
UInt64 m_refTime;
Time m_elapsedTime;
Time m_refTime;
bool m_paused;
};
using ClockFunction = UInt64 (*)();
extern NAZARA_CORE_API ClockFunction GetElapsedMicroseconds;
extern NAZARA_CORE_API ClockFunction GetElapsedMilliseconds;
using HighPrecisionClock = Clock<true>;
using MillisecondClock = Clock<false>;
}
#include <Nazara/Core/Clock.inl>
#endif // NAZARA_CORE_CLOCK_HPP

View File

@ -0,0 +1,151 @@
// Copyright (C) 2022 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 <Nazara/Core/Clock.hpp>
#include <Nazara/Core/Debug.hpp>
namespace Nz
{
/*!
* \ingroup core
* \class Nz::Clock
* \brief Utility class that measure the elapsed time
*/
/*!
* \brief Constructs a Clock object
*
* \param startingValue The starting time value, in microseconds
* \param paused The clock pause state
*/
template<bool HighPrecision>
Clock<HighPrecision>::Clock(Time startingValue, bool paused) :
m_elapsedTime(startingValue),
m_refTime(Now()),
m_paused(paused)
{
}
/*!
* Returns the elapsed time
* \return Duration elapsed
*/
template<bool HighPrecision>
Time Clock<HighPrecision>::GetElapsedTime() const
{
Time elapsedNanoseconds = m_elapsedTime;
if (!m_paused)
elapsedNanoseconds += Now() - m_refTime;
return elapsedNanoseconds;
}
/*!
* Returns the current pause state of the clock
* \return Boolean indicating if the clock is currently paused
*
* \see Pause, Unpause
*/
template<bool HighPrecision>
bool Clock<HighPrecision>::IsPaused() const
{
return m_paused;
}
/*!
* \brief Pause the clock
*
* Pauses the clock, making the time retrieving functions to always return the value at the time the clock was paused
* This has no effect if the clock is already paused
*
* \see IsPaused, Unpause
*/
template<bool HighPrecision>
void Clock<HighPrecision>::Pause()
{
if (!m_paused)
{
m_elapsedTime += Now() - m_refTime;
m_paused = true;
}
}
/*!
* \brief Restart the clock
* \return Time elapsed since creation or last restart call
*
* Restarts the clock, putting its time counter back to the starting value
* It also compute the elapsed microseconds since the last Restart() call without any time loss (a problem that the combination of GetElapsedTime and Restart have).
*/
template<bool HighPrecision>
Time Clock<HighPrecision>::Restart(Time startingValue, bool paused)
{
Time now = Now();
Time elapsedTime = m_elapsedTime;
if (!m_paused)
elapsedTime += now - m_refTime;
m_elapsedTime = startingValue;
m_refTime = now;
m_paused = paused;
return elapsedTime;
}
/*!
* \brief Restart the clock if more than time elapsed
* \return If more than time elapsed since creation or last restart call
*
* Restarts the clock, putting its time counter back to zero
* This function allows to check the elapsed time of a clock and restart it if over some value in a single call, preventing some loss between GetElapsedTime and Restart
*/
template<bool HighPrecision>
std::optional<Time> Clock<HighPrecision>::RestartIfOver(Time time)
{
Time now = Now();
Time elapsedTime = m_elapsedTime;
if (!m_paused)
elapsedTime += now - m_refTime;
if (elapsedTime < time)
return std::nullopt;
m_elapsedTime = Time::Zero();
m_refTime = now;
return elapsedTime;
}
/*!
* \brief Unpause the clock
*
* Unpauses the clock, making the clock continue to measure the time
* This has no effect if the clock is already unpaused
*
* \see IsPaused, Unpause
*/
template<bool HighPrecision>
void Clock<HighPrecision>::Unpause()
{
if (m_paused)
{
m_refTime = Now();
m_paused = false;
}
}
template<bool HighPrecision>
Time Clock<HighPrecision>::Now()
{
if constexpr (HighPrecision)
return GetElapsedNanoseconds();
else
return GetElapsedMilliseconds();
}
}
#include <Nazara/Core/DebugOff.hpp>

View File

@ -8,6 +8,7 @@
#define NAZARA_CORE_COMPONENTS_LIFETIMECOMPONENT_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Time.hpp>
#include <Nazara/Utility/Config.hpp>
namespace Nz
@ -15,14 +16,14 @@ namespace Nz
class LifetimeComponent
{
public:
inline LifetimeComponent(float lifetime);
inline LifetimeComponent(Time lifetime);
LifetimeComponent(const LifetimeComponent&) = default;
LifetimeComponent(LifetimeComponent&&) = default;
~LifetimeComponent() = default;
inline void DecreaseLifetime(float elapsedTime);
inline void DecreaseLifetime(Time elapsedTime);
inline float GetRemainingLifeTime() const;
inline Time GetRemainingLifeTime() const;
inline bool IsAlive() const;
@ -30,7 +31,7 @@ namespace Nz
LifetimeComponent& operator=(LifetimeComponent&&) = default;
private:
float m_remainingLifetime;
Time m_remainingLifetime;
};
}

View File

@ -7,24 +7,24 @@
namespace Nz
{
inline LifetimeComponent::LifetimeComponent(float lifetime) :
inline LifetimeComponent::LifetimeComponent(Time lifetime) :
m_remainingLifetime(lifetime)
{
}
inline void LifetimeComponent::DecreaseLifetime(float elapsedTime)
inline void LifetimeComponent::DecreaseLifetime(Time elapsedTime)
{
m_remainingLifetime -= elapsedTime;
}
inline float LifetimeComponent::GetRemainingLifeTime() const
inline Time LifetimeComponent::GetRemainingLifeTime() const
{
return m_remainingLifetime;
}
inline bool LifetimeComponent::IsAlive() const
{
return m_remainingLifetime >= 0.f;
return m_remainingLifetime >= Time::Zero();
}
}

View File

@ -9,6 +9,7 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Config.hpp>
#include <Nazara/Core/Time.hpp>
#include <Nazara/Utils/TypeList.hpp>
#include <entt/entt.hpp>
@ -26,7 +27,7 @@ namespace Nz
LifetimeSystem(LifetimeSystem&&) = delete;
~LifetimeSystem() = default;
void Update(float elapsedTime);
void Update(Time elapsedTime);
LifetimeSystem& operator=(const LifetimeSystem&) = delete;
LifetimeSystem& operator=(LifetimeSystem&&) = delete;

View File

@ -31,7 +31,7 @@ namespace Nz
template<typename T> T& GetSystem() const;
void Update();
void Update(float elapsedTime);
void Update(Time elapsedTime);
SystemGraph& operator=(const SystemGraph&) = delete;
SystemGraph& operator=(SystemGraph&&) = delete;
@ -41,7 +41,7 @@ namespace Nz
{
virtual ~NodeBase();
virtual void Update(float elapsedTime) = 0;
virtual void Update(Time elapsedTime) = 0;
Int64 executionOrder;
};
@ -51,7 +51,7 @@ namespace Nz
{
template<typename... Args> Node(Args&&... args);
void Update(float elapsedTime) override;
void Update(Time elapsedTime) override;
T system;
};
@ -60,7 +60,7 @@ namespace Nz
std::vector<NodeBase*> m_orderedNodes;
std::vector<std::unique_ptr<NodeBase>> m_nodes;
entt::registry& m_registry;
Nz::Clock m_clock;
Nz::HighPrecisionClock m_clock;
bool m_systemOrderUpdated;
};
}

View File

@ -32,7 +32,7 @@ namespace Nz
}
template<typename T>
void SystemGraph::Node<T>::Update(float elapsedTime)
void SystemGraph::Node<T>::Update(Time elapsedTime)
{
system.Update(elapsedTime);
}

View File

@ -0,0 +1,104 @@
// Copyright (C) 2022 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_TIME_HPP
#define NAZARA_CORE_TIME_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Core/Config.hpp>
#include <chrono>
#include <ostream>
#include <type_traits>
namespace Nz
{
struct SerializationContext;
class Time
{
public:
Time() = default;
Time(const Time&) = default;
Time(Time&&) = default;
~Time() = default;
template<typename T> constexpr T AsDuration() const;
template<typename T = float> constexpr T AsSeconds() const;
constexpr Int64 AsMicroseconds() const;
constexpr Int64 AsMilliseconds() const;
constexpr Int64 AsNanoseconds() const;
Time& operator=(const Time&) = default;
Time& operator=(Time&&) = default;
constexpr Time& operator+=(Time time);
constexpr Time& operator-=(Time time);
constexpr Time& operator*=(Time time);
constexpr Time& operator/=(Time time);
constexpr Time& operator%=(Time time);
constexpr explicit operator Int64() const;
template<class Rep, class Period> static constexpr Time FromDuration(const std::chrono::duration<Rep, Period>& d);
static constexpr Time Microsecond();
static constexpr Time Microseconds(Int64 microseconds);
static constexpr Time Millisecond();
static constexpr Time Milliseconds(Int64 milliseconds);
static constexpr Time Nanosecond();
static constexpr Time Nanoseconds(Int64 nanoseconds);
static constexpr Time Second();
template<typename T> static constexpr Time Seconds(T seconds);
static constexpr Time TickDuration(Int64 tickRate);
static constexpr Time Zero();
// External part
friend constexpr Time operator+(Time time);
friend constexpr Time operator-(Time time);
friend constexpr Time operator+(Time lhs, Time rhs);
friend constexpr Time operator-(Time lhs, Time rhs);
friend constexpr Time operator*(Time lhs, Time rhs);
friend constexpr Time operator/(Time lhs, Time rhs);
friend constexpr Time operator%(Time lhs, Time rhs);
friend constexpr bool operator==(Time lhs, Time rhs);
friend constexpr bool operator!=(Time lhs, Time rhs);
friend constexpr bool operator<(Time lhs, Time rhs);
friend constexpr bool operator<=(Time lhs, Time rhs);
friend constexpr bool operator>(Time lhs, Time rhs);
friend constexpr bool operator>=(Time lhs, Time rhs);
friend inline std::ostream& operator<<(std::ostream& out, Time time);
friend inline bool Serialize(SerializationContext& context, Time time, TypeTag<Time>);
friend inline bool Unserialize(SerializationContext& context, Time* time, TypeTag<Time>);
private:
constexpr explicit Time(Int64 nanoseconds);
Int64 m_nanoseconds;
};
namespace Literals
{
constexpr Time operator ""_ms(unsigned long long milliseconds);
constexpr Time operator ""_ns(unsigned long long nanoseconds);
constexpr Time operator ""_us(unsigned long long microseconds);
constexpr Time operator ""_s(long double seconds);
constexpr Time operator ""_s(unsigned long long seconds);
}
using GetElapsedTimeFunction = Time(*)();
extern NAZARA_CORE_API GetElapsedTimeFunction GetElapsedMilliseconds;
extern NAZARA_CORE_API GetElapsedTimeFunction GetElapsedNanoseconds;
}
#include <Nazara/Core/Time.inl>
#endif // NAZARA_CORE_TIME_HPP

View File

@ -0,0 +1,270 @@
// Copyright (C) 2022 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 <Nazara/Core/Time.hpp>
#include <Nazara/Core/Debug.hpp>
namespace Nz
{
constexpr Time::Time(Int64 microseconds) :
m_nanoseconds(microseconds)
{
}
template<typename T>
constexpr T Time::AsDuration() const
{
if constexpr (std::is_same_v<T, std::chrono::nanoseconds>)
return std::chrono::nanoseconds(m_nanoseconds); //< make sure it's a no-op
else
return std::chrono::duration_cast<T>(std::chrono::nanoseconds(m_nanoseconds));
}
template<typename T>
constexpr T Time::AsSeconds() const
{
static_assert(std::is_floating_point_v<T>);
// TODO: Improve precision
return AsMicroseconds() / T(1'000'000.0) + (m_nanoseconds % 1000) / T(1'000'000'000);
}
constexpr Int64 Time::AsMicroseconds() const
{
return m_nanoseconds / 1'000;
}
constexpr Int64 Time::AsMilliseconds() const
{
return m_nanoseconds / 1'000'000;
}
constexpr Int64 Time::AsNanoseconds() const
{
return m_nanoseconds;
}
constexpr Time& Time::operator+=(Time time)
{
m_nanoseconds += time.m_nanoseconds;
return *this;
}
constexpr Time& Time::operator-=(Time time)
{
m_nanoseconds -= time.m_nanoseconds;
return *this;
}
constexpr Time& Time::operator*=(Time time)
{
m_nanoseconds *= time.m_nanoseconds;
return *this;
}
constexpr Time& Time::operator/=(Time time)
{
m_nanoseconds /= time.m_nanoseconds;
return *this;
}
constexpr Time& Time::operator%=(Time time)
{
m_nanoseconds %= time.m_nanoseconds;
return *this;
}
constexpr Time::operator Int64() const
{
return m_nanoseconds;
}
template<class Rep, class Period>
constexpr Time Time::FromDuration(const std::chrono::duration<Rep, Period>& d)
{
return Nanoseconds(std::chrono::duration_cast<std::chrono::nanoseconds>(d).count());
}
constexpr Time Time::Microsecond()
{
return Time(1'000);
}
constexpr Time Time::Microseconds(Int64 microseconds)
{
return Time(microseconds * 1'000);
}
constexpr Time Time::Millisecond()
{
return Time(1'000'000);
}
constexpr Time Time::Milliseconds(Int64 milliseconds)
{
return Time(milliseconds * 1'000'000);
}
constexpr Time Time::Nanosecond()
{
return Time(1);
}
constexpr Time Time::Nanoseconds(Int64 nanoseconds)
{
return Time(nanoseconds);
}
constexpr Time Time::Second()
{
return Time(1'000'000'000ull);
}
template<typename T>
constexpr Time Time::Seconds(T seconds)
{
if constexpr (std::is_floating_point_v<T>)
return Nanoseconds(static_cast<UInt64>(seconds * T(1'000'000'000.0)));
else if constexpr (std::is_integral_v<T>)
return Nanoseconds(seconds * 1'000'000'000LL);
else
static_assert(AlwaysFalse<T>(), "not an arithmetic type");
}
constexpr Time Time::TickDuration(Int64 tickRate)
{
return Second() / Nanoseconds(tickRate);
}
constexpr Time Time::Zero()
{
return Time(0);
}
constexpr Time operator+(Time time)
{
return time;
}
constexpr Time operator-(Time time)
{
return Time(-time.m_nanoseconds);
}
constexpr Time operator+(Time lhs, Time rhs)
{
return Time(lhs.m_nanoseconds + rhs.m_nanoseconds);
}
constexpr Time operator-(Time lhs, Time rhs)
{
return Time(lhs.m_nanoseconds - rhs.m_nanoseconds);
}
constexpr Time operator*(Time lhs, Time rhs)
{
return Time(lhs.m_nanoseconds * rhs.m_nanoseconds);
}
constexpr Time operator/(Time lhs, Time rhs)
{
return Time(lhs.m_nanoseconds / rhs.m_nanoseconds);
}
constexpr Time operator%(Time lhs, Time rhs)
{
return Time(lhs.m_nanoseconds % rhs.m_nanoseconds);
}
constexpr bool operator==(Time lhs, Time rhs)
{
return lhs.m_nanoseconds == rhs.m_nanoseconds;
}
constexpr bool operator!=(Time lhs, Time rhs)
{
return lhs.m_nanoseconds != rhs.m_nanoseconds;
}
constexpr bool operator<(Time lhs, Time rhs)
{
return lhs.m_nanoseconds < rhs.m_nanoseconds;
}
constexpr bool operator<=(Time lhs, Time rhs)
{
return lhs.m_nanoseconds <= rhs.m_nanoseconds;
}
constexpr bool operator>(Time lhs, Time rhs)
{
return lhs.m_nanoseconds > rhs.m_nanoseconds;
}
constexpr bool operator>=(Time lhs, Time rhs)
{
return lhs.m_nanoseconds >= rhs.m_nanoseconds;
}
inline std::ostream& operator<<(std::ostream& out, Time time)
{
if (time > Time::Second())
return out << time.AsSeconds<double>() << "s";
else
{
Int64 ns = time.AsNanoseconds();
if (time > Time::Millisecond())
return out << ns / 1'000'000.0 << "ms";
else if (time > Time::Microsecond())
return out << ns / 1'000.0 << "us";
else
return out << ns << "ns";
}
}
inline bool Serialize(SerializationContext& context, Time time, TypeTag<Time>)
{
if (!Serialize(context, time.m_nanoseconds))
return false;
return true;
}
inline bool Unserialize(SerializationContext& context, Time* time, TypeTag<Time>)
{
if (!Unserialize(context, &time->m_nanoseconds))
return false;
return true;
}
namespace Literals
{
constexpr Time operator ""_ms(unsigned long long milliseconds)
{
return Time::Milliseconds(static_cast<Int64>(milliseconds));
}
constexpr Time operator ""_ns(unsigned long long nanoseconds)
{
return Time::Nanoseconds(static_cast<Int64>(nanoseconds));
}
constexpr Time operator ""_us(unsigned long long microseconds)
{
return Time::Microseconds(static_cast<Int64>(microseconds));
}
constexpr Time operator ""_s(long double milliseconds)
{
return Time::Seconds(milliseconds);
}
constexpr Time operator ""_s(unsigned long long milliseconds)
{
return Time::Seconds(milliseconds);
}
}
}
#include <Nazara/Core/DebugOff.hpp>

View File

@ -8,6 +8,7 @@
#define NAZARA_GRAPHICS_SYSTEMS_RENDERSYSTEM_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Time.hpp>
#include <Nazara/Graphics/ElementRendererRegistry.hpp>
#include <Nazara/Graphics/Graphics.hpp>
#include <Nazara/Graphics/Components/GraphicsComponent.hpp>
@ -45,7 +46,7 @@ namespace Nz
inline FramePipeline& GetFramePipeline();
inline const FramePipeline& GetFramePipeline() const;
void Update(float elapsedTime);
void Update(Time elapsedTime);
RenderSystem& operator=(const RenderSystem&) = delete;
RenderSystem& operator=(RenderSystem&&) = delete;

View File

@ -111,8 +111,8 @@ namespace Nz
inline void ENetHost::UpdateServiceTime()
{
// Compute service time as microseconds for extra precision
m_serviceTime = static_cast<UInt32>(GetElapsedMicroseconds() / 1000);
// Use high precision clock for extra precision
m_serviceTime = static_cast<UInt32>(GetElapsedNanoseconds().AsMilliseconds());
}
}

View File

@ -9,6 +9,7 @@
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Color.hpp>
#include <Nazara/Core/Time.hpp>
#include <Nazara/Math/Angle.hpp>
#include <Nazara/Math/Vector2.hpp>
#include <Nazara/Physics2D/Config.hpp>
@ -59,7 +60,7 @@ namespace Nz
cpSpace* GetHandle() const;
std::size_t GetIterationCount() const;
std::size_t GetMaxStepCount() const;
float GetStepSize() const;
Time GetStepSize() const;
bool NearestBodyQuery(const Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RigidBody2D** nearestBody = nullptr);
bool NearestBodyQuery(const Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result);
@ -78,10 +79,10 @@ namespace Nz
void SetGravity(const Vector2f& gravity);
void SetIterationCount(std::size_t iterationCount);
void SetMaxStepCount(std::size_t maxStepCount);
void SetSleepTime(float sleepTime);
void SetStepSize(float stepSize);
void SetSleepTime(Time sleepTime);
void SetStepSize(Time stepSize);
void Step(float timestep);
void Step(Time timestep);
void UseSpatialHash(float cellSize, std::size_t entityCount);
@ -156,8 +157,8 @@ namespace Nz
std::unordered_map<cpCollisionHandler*, std::unique_ptr<Callback>> m_callbacks;
std::unordered_map<RigidBody2D*, PostStepContainer> m_rigidPostSteps;
cpSpace* m_handle;
float m_stepSize;
float m_timestepAccumulator;
Time m_stepSize;
Time m_timestepAccumulator;
};
}

View File

@ -8,6 +8,7 @@
#define NAZARA_PHYSICS2D_SYSTEMS_PHYSICS2DSYSTEM_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Time.hpp>
#include <Nazara/Physics2D/PhysWorld2D.hpp>
#include <Nazara/Physics2D/Components/RigidBody2DComponent.hpp>
#include <Nazara/Utils/TypeList.hpp>
@ -31,7 +32,7 @@ namespace Nz
inline PhysWorld2D& GetPhysWorld();
inline const PhysWorld2D& GetPhysWorld() const;
void Update(float elapsedTime);
void Update(Time elapsedTime);
Physics2DSystem& operator=(const Physics2DSystem&) = delete;
Physics2DSystem& operator=(Physics2DSystem&&) = delete;

View File

@ -8,6 +8,7 @@
#define NAZARA_PHYSICS3D_PHYSWORLD3D_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Time.hpp>
#include <Nazara/Math/Box.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <Nazara/Physics3D/Config.hpp>
@ -44,12 +45,12 @@ namespace Nz
NewtonWorld* GetHandle() const;
int GetMaterial(const std::string& name);
std::size_t GetMaxStepCount() const;
float GetStepSize() const;
Time GetStepSize() const;
unsigned int GetThreadCount() const;
void SetGravity(const Vector3f& gravity);
void SetMaxStepCount(std::size_t maxStepCount);
void SetStepSize(float stepSize);
void SetStepSize(Time stepSize);
void SetThreadCount(unsigned int threadCount);
void SetMaterialCollisionCallback(int firstMaterial, int secondMaterial, AABBOverlapCallback aabbOverlapCallback, CollisionCallback collisionCallback);
@ -59,7 +60,7 @@ namespace Nz
void SetMaterialDefaultSoftness(int firstMaterial, int secondMaterial, float softness);
void SetMaterialSurfaceThickness(int firstMaterial, int secondMaterial, float thickness);
void Step(float timestep);
void Step(Time timestep);
PhysWorld3D& operator=(const PhysWorld3D&) = delete;
PhysWorld3D& operator=(PhysWorld3D&&) noexcept;
@ -79,8 +80,8 @@ namespace Nz
std::size_t m_maxStepCount;
MovablePtr<NewtonWorld> m_world;
Vector3f m_gravity;
float m_stepSize;
float m_timestepAccumulator;
Time m_stepSize;
Time m_timestepAccumulator;
};
}

View File

@ -8,6 +8,7 @@
#define NAZARA_PHYSICS3D_SYSTEMS_PHYSICS3DSYSTEM_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Time.hpp>
#include <Nazara/Physics3D/PhysWorld3D.hpp>
#include <Nazara/Physics3D/Components/RigidBody3DComponent.hpp>
#include <Nazara/Utils/TypeList.hpp>
@ -31,7 +32,7 @@ namespace Nz
inline PhysWorld3D& GetPhysWorld();
inline const PhysWorld3D& GetPhysWorld() const;
void Update(float elapsedTime);
void Update(Time elapsedTime);
Physics3DSystem& operator=(const Physics3DSystem&) = delete;
Physics3DSystem& operator=(Physics3DSystem&&) = delete;

View File

@ -56,7 +56,7 @@ namespace Nz
std::shared_ptr<RenderDevice> m_renderDevice;
std::unique_ptr<RenderSurface> m_surface;
std::unique_ptr<RenderWindowImpl> m_impl;
Clock m_clock;
MillisecondClock m_clock;
RenderWindowParameters m_parameters;
unsigned int m_framerateLimit;
};

View File

@ -8,6 +8,7 @@
#define NAZARA_UTILITY_SYSTEMS_SKELETONSYSTEM_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Time.hpp>
#include <Nazara/Utility/Config.hpp>
#include <entt/entt.hpp>
@ -24,7 +25,7 @@ namespace Nz
SkeletonSystem(SkeletonSystem&&) = delete;
~SkeletonSystem();
void Update(float elapsedTime);
void Update(Time elapsedTime);
SkeletonSystem& operator=(const SkeletonSystem&) = delete;
SkeletonSystem& operator=(SkeletonSystem&&) = delete;

View File

@ -81,7 +81,6 @@ namespace Nz
Vk::QueueHandle m_presentQueue;
Vk::QueueHandle m_transferQueue;
Vk::Swapchain m_swapchain;
Clock m_clock;
RenderWindow& m_owner;
Vector2ui m_swapchainSize;
VkFormat m_depthStencilFormat;

View File

@ -15,9 +15,9 @@ namespace Nz
return m_format;
}
UInt32 DummyAudioBuffer::GetDuration() const
Time DummyAudioBuffer::GetDuration() const
{
return SafeCast<UInt32>((1000ULL * m_sampleCount / (GetChannelCount(m_format) * m_sampleRate)));
return Time::Microseconds((1'000'000LL * m_sampleCount / (GetChannelCount(m_format) * m_sampleRate)));
}
UInt64 DummyAudioBuffer::GetSampleCount() const

View File

@ -39,6 +39,27 @@ namespace Nz
return m_pitch;
}
Time DummyAudioSource::GetPlayingOffset() const
{
if (m_status == SoundStatus::Stopped)
return Time::Zero(); //< Always return 0 when stopped, to mimic OpenAL behavior
Time bufferTime = UpdateTime();
Time playingOffset = Time::Zero();
// All processed buffers count
for (const auto& processedBuffer : m_processedBuffers)
playingOffset += processedBuffer->GetDuration();
if (!m_queuedBuffers.empty())
{
auto& frontBuffer = m_queuedBuffers.front();
playingOffset += std::min(bufferTime, frontBuffer->GetDuration());
}
return playingOffset;
}
Vector3f DummyAudioSource::GetPosition() const
{
return m_position;
@ -49,7 +70,7 @@ namespace Nz
if (m_status == SoundStatus::Stopped)
return 0; //< Always return 0 when stopped, to mimic OpenAL behavior
UInt64 bufferTime = UpdateTime();
Time bufferTime = UpdateTime();
UInt64 sampleOffset = 0;
// All processed buffers count in sample offset
@ -59,7 +80,7 @@ namespace Nz
if (!m_queuedBuffers.empty())
{
auto& frontBuffer = m_queuedBuffers.front();
UInt64 bufferOffset = bufferTime * frontBuffer->GetSampleRate() / 1000;
UInt64 bufferOffset = bufferTime.AsMicroseconds() * frontBuffer->GetSampleRate() / 1'000'000ll;
UInt64 bufferDuration = frontBuffer->GetSampleCount() / GetChannelCount(frontBuffer->GetAudioFormat());
sampleOffset += std::min(bufferOffset, bufferDuration);
@ -72,7 +93,7 @@ namespace Nz
{
OffsetWithLatency info;
info.sampleOffset = GetSampleOffset() * 1000;
info.sourceLatency = 0;
info.sourceLatency = Time::Zero();
return info;
}
@ -120,19 +141,19 @@ namespace Nz
void DummyAudioSource::Play()
{
if (m_status == SoundStatus::Paused)
m_playClock.Unpause();
else
if (m_status != SoundStatus::Paused)
{
// playing or stopped, restart
RequeueBuffers();
// special case, we are stopped but SetSampleOffset has been called
if (m_status == SoundStatus::Stopped && m_playClock.GetMilliseconds() != 0)
if (m_status == SoundStatus::Stopped && m_playClock.GetElapsedTime() != Time::Zero())
m_playClock.Unpause();
else
m_playClock.Restart(); //< already playing or stopped, restart from beginning
}
else
m_playClock.Unpause();
m_status = SoundStatus::Playing;
}
@ -161,6 +182,13 @@ namespace Nz
m_pitch = pitch;
}
void DummyAudioSource::SetPlayingOffset(Time offset)
{
// Next UpdateTime call will handle this properly
RequeueBuffers();
m_playClock.Restart(offset, m_playClock.IsPaused());
}
void DummyAudioSource::SetPosition(const Vector3f& position)
{
m_position = position;
@ -187,7 +215,7 @@ namespace Nz
if (!m_queuedBuffers.empty())
{
UInt64 timeOffset = 1'000'000ULL * offset / m_queuedBuffers.front()->GetSampleRate();
Time timeOffset = Time::Microseconds(1'000'000ll * offset / m_queuedBuffers.front()->GetSampleRate());
m_playClock.Restart(timeOffset, m_playClock.IsPaused());
}
else
@ -206,7 +234,7 @@ namespace Nz
void DummyAudioSource::Stop()
{
m_playClock.Restart(0, true);
m_playClock.Restart(Time::Zero(), true);
m_status = SoundStatus::Stopped;
}
@ -246,9 +274,10 @@ namespace Nz
}
}
UInt64 DummyAudioSource::UpdateTime() const
Time DummyAudioSource::UpdateTime() const
{
UInt64 currentTime = m_playClock.GetMilliseconds();
Time currentTime = m_playClock.GetElapsedTime();
bool isPaused = m_playClock.IsPaused();
while (!m_queuedBuffers.empty() && currentTime >= m_queuedBuffers.front()->GetDuration())
{
@ -278,10 +307,14 @@ namespace Nz
}
}
else
{
m_status = SoundStatus::Stopped;
currentTime = Time::Zero();
isPaused = m_playClock.IsPaused();
}
}
m_playClock.Restart(currentTime * 1000, m_playClock.IsPaused()); //< Adjust time
m_playClock.Restart(currentTime, isPaused); //< Adjust time
return currentTime;
}
}

View File

@ -105,7 +105,7 @@ namespace Nz
drwav_uninit(&m_decoder);
}
UInt32 GetDuration() const override
Time GetDuration() const override
{
return m_duration;
}
@ -172,7 +172,7 @@ namespace Nz
m_format = *formatOpt;
m_duration = static_cast<UInt32>(1000ULL * m_decoder.totalPCMFrameCount / m_decoder.sampleRate);
m_duration = Time::Microseconds(1'000'000LL * m_decoder.totalPCMFrameCount / m_decoder.sampleRate);
m_sampleCount = m_decoder.totalPCMFrameCount * m_decoder.channels;
m_sampleRate = m_decoder.sampleRate;
@ -230,7 +230,7 @@ namespace Nz
std::vector<Int16> m_mixBuffer;
AudioFormat m_format;
drwav m_decoder;
UInt32 m_duration;
Time m_duration;
UInt32 m_sampleRate;
UInt64 m_readSampleCount;
UInt64 m_sampleCount;

View File

@ -265,7 +265,7 @@ namespace Nz
}
}
UInt32 GetDuration() const override
Time GetDuration() const override
{
return m_duration;
}
@ -333,7 +333,7 @@ namespace Nz
m_sampleCount = frameCount * m_channelCount;
m_sampleRate = meta->data.stream_info.sample_rate;
m_duration = UInt32(1000ULL * frameCount / m_sampleRate);
m_duration = Time::Microseconds(1'000'000LL * frameCount / m_sampleRate);
};
FLAC__StreamDecoderInitStatus status = FLAC__stream_decoder_init_stream(decoder, &FlacReadCallback, &FlacSeekCallback, &FlacTellCallback, &FlacLengthCallback, &FlacEofCallback, &WriteCallback, &MetadataCallback, &ErrorCallback, &m_userData);
@ -477,8 +477,8 @@ namespace Nz
FLAC__StreamDecoder* m_decoder;
AudioFormat m_format;
FlacUserdata m_userData;
Time m_duration;
UInt32 m_channelCount;
UInt32 m_duration;
UInt32 m_sampleRate;
UInt64 m_readSampleCount;
UInt64 m_sampleCount;

View File

@ -184,7 +184,7 @@ namespace Nz
ov_clear(&m_decoder);
}
UInt32 GetDuration() const override
Time GetDuration() const override
{
return m_duration;
}
@ -258,7 +258,7 @@ namespace Nz
UInt64 frameCount = UInt64(ov_pcm_total(&m_decoder, -1));
m_channelCount = info->channels;
m_duration = UInt32(1000ULL * frameCount / info->rate);
m_duration = Time::Microseconds(1'000'000LL * frameCount / info->rate);
m_sampleCount = UInt64(frameCount * info->channels);
m_sampleRate = info->rate;
@ -319,8 +319,8 @@ namespace Nz
std::vector<Int16> m_mixBuffer;
AudioFormat m_format;
OggVorbis_File m_decoder;
Time m_duration;
UInt32 m_channelCount;
UInt32 m_duration;
UInt32 m_sampleRate;
UInt64 m_sampleCount;
bool m_mixToMono;

View File

@ -130,7 +130,7 @@ namespace Nz
mp3dec_ex_close(&m_decoder);
}
UInt32 GetDuration() const override
Time GetDuration() const override
{
return m_duration;
}
@ -214,7 +214,7 @@ namespace Nz
m_format = *formatOpt;
m_duration = static_cast<UInt32>(1000ULL * m_decoder.samples / (m_decoder.info.hz * m_decoder.info.channels));
m_duration = Time::Microseconds(1'000'000LL * m_decoder.samples / (m_decoder.info.hz * m_decoder.info.channels));
m_sampleCount = m_decoder.samples;
m_sampleRate = m_decoder.info.hz;
@ -275,7 +275,7 @@ namespace Nz
AudioFormat m_format;
mp3dec_ex_t m_decoder;
mp3dec_io_t m_io;
UInt32 m_duration;
Time m_duration;
UInt32 m_sampleRate;
UInt64 m_readSampleCount;
UInt64 m_sampleCount;

View File

@ -67,7 +67,7 @@ namespace Nz
m_chunkSamples.resize(GetChannelCount(format) * m_sampleRate); // One second of samples
m_stream = std::move(soundStream);
SetPlayingOffset(0);
SeekToSampleOffset(0);
return true;
}
@ -102,7 +102,7 @@ namespace Nz
*
* \remark Music must be valid when calling this function
*/
UInt32 Music::GetDuration() const
Time Music::GetDuration() const
{
NazaraAssert(m_stream, "Music not created");
@ -123,30 +123,30 @@ namespace Nz
}
/*!
* \brief Gets the current offset in the music
* \return Offset in milliseconds (works with entire seconds)
*
* \remark Music must be valid when calling this function
* \brief Gets the current playing offset of the music
* \return Time offset
*/
UInt32 Music::GetPlayingOffset() const
Time Music::GetPlayingOffset() const
{
NazaraAssert(m_stream, "Music not created");
if (!m_streaming)
return 0;
return Time::Zero();
// Prevent music thread from enqueuing new buffers while we're getting the count
std::lock_guard<std::recursive_mutex> lock(m_sourceLock);
UInt32 sampleOffset = m_source->GetSampleOffset();
UInt32 playingOffset = SafeCast<UInt32>((1000ULL * (sampleOffset + (m_processedSamples / GetChannelCount(m_stream->GetFormat())))) / m_sampleRate);
UInt32 duration = m_stream->GetDuration();
if (playingOffset > duration)
Time playingOffset = m_source->GetPlayingOffset();
Time processedTime = Time::Microseconds(1'000'000ll * m_processedSamples / (GetChannelCount(m_stream->GetFormat()) * m_sampleRate));
playingOffset += processedTime;
Time sampleCount = m_stream->GetDuration();
if (playingOffset > sampleCount)
{
if (m_looping)
playingOffset %= duration;
playingOffset %= sampleCount;
else
playingOffset = 0; //< stopped
playingOffset = Time::Zero(); //< stopped
}
return playingOffset;
@ -165,6 +165,33 @@ namespace Nz
return m_stream->GetSampleCount();
}
/*!
* \brief Gets the current offset in the music
* \return Offset in samples
*/
UInt64 Music::GetSampleOffset() const
{
NazaraAssert(m_stream, "Music not created");
if (!m_streaming)
return 0;
// Prevent music thread from enqueuing new buffers while we're getting the count
std::lock_guard<std::recursive_mutex> lock(m_sourceLock);
UInt64 sampleOffset = m_processedSamples + m_source->GetSampleOffset();
UInt64 sampleCount = m_stream->GetSampleCount();
if (sampleOffset > sampleCount)
{
if (m_looping)
sampleOffset %= sampleCount;
else
sampleOffset = 0; //< stopped
}
return sampleOffset;
}
/*!
* \brief Gets the rates of sample in the music
* \return Rate of sample in Hertz (Hz)
@ -296,7 +323,7 @@ namespace Nz
switch (GetStatus())
{
case SoundStatus::Playing:
SetPlayingOffset(0);
SeekToSampleOffset(0);
break;
case SoundStatus::Paused:
@ -325,11 +352,11 @@ namespace Nz
*
* If the music is not playing, this sets the playing offset for the next Play call
*
* \param offset The offset in milliseconds
* \param offset The offset in samples
*
* \remark Music must be valid when calling this function
*/
void Music::SetPlayingOffset(UInt32 offset)
void Music::SeekToSampleOffset(UInt64 offset)
{
NazaraAssert(m_stream, "Music not created");
@ -339,7 +366,7 @@ namespace Nz
if (isPlaying)
StopThread();
UInt64 sampleOffset = UInt64(offset) * m_sampleRate * GetChannelCount(m_stream->GetFormat()) / 1000ULL;
UInt64 sampleOffset = offset * GetChannelCount(m_stream->GetFormat());
m_processedSamples = sampleOffset;
m_streamOffset = sampleOffset;
@ -356,7 +383,7 @@ namespace Nz
void Music::Stop()
{
StopThread();
SetPlayingOffset(0);
SeekToSampleOffset(0);
}
bool Music::FillAndQueueBuffer(std::shared_ptr<AudioBuffer> buffer)

View File

@ -62,6 +62,29 @@ namespace Nz
return pitch;
}
Time OpenALSource::GetPlayingOffset() const
{
GetDevice().MakeContextCurrent();
#ifdef AL_SOFT_source_latency
if (GetDevice().IsExtensionSupported(OpenALExtension::SourceLatency))
{
// alGetSourcedvSOFT has extra precision thanks to double
ALdouble playingOffset;
m_library.alGetSourcedvSOFT(m_sourceId, AL_SEC_OFFSET, &playingOffset);
return Time::Seconds(playingOffset);
}
else
#endif
{
ALfloat playingOffset;
m_library.alGetSourcefv(m_sourceId, AL_SEC_OFFSET, &playingOffset);
return Time::Seconds(playingOffset);
}
}
Vector3f OpenALSource::GetPosition() const
{
GetDevice().MakeContextCurrent();
@ -94,14 +117,14 @@ namespace Nz
m_library.alGetSourcei64vSOFT(m_sourceId, AL_SAMPLE_OFFSET_LATENCY_SOFT, values.data());
offsetWithLatency.sampleOffset = ((values[0] & 0xFFFFFFFF00000000) >> 32) * 1'000;
offsetWithLatency.sourceLatency = values[1] / 1'000;
offsetWithLatency.sourceLatency = Time::Nanoseconds(values[1] / 1'000);
}
else
#endif
{
offsetWithLatency.sampleOffset = GetSampleOffset() * 1'000;
offsetWithLatency.sourceLatency = 0;
offsetWithLatency.sourceLatency = Time::Zero();
}
return offsetWithLatency;
@ -239,6 +262,19 @@ namespace Nz
m_library.alSourcef(m_sourceId, AL_PITCH, pitch);
}
void OpenALSource::SetPlayingOffset(Time offset)
{
GetDevice().MakeContextCurrent();
#ifdef AL_SOFT_source_latency
if (GetDevice().IsExtensionSupported(OpenALExtension::SourceLatency))
// alGetSourcedvSOFT has extra precision thanks to double
m_library.alSourcedSOFT(m_sourceId, AL_SEC_OFFSET, offset.AsSeconds<ALdouble>());
else
#endif
m_library.alSourcef(m_sourceId, AL_SEC_OFFSET, offset.AsSeconds<ALfloat>());
}
void OpenALSource::SetPosition(const Vector3f& position)
{
GetDevice().MakeContextCurrent();

View File

@ -72,7 +72,7 @@ namespace Nz
*
* \remark Produces a NazaraError if there is no buffer
*/
UInt32 Sound::GetDuration() const
Time Sound::GetDuration() const
{
NazaraAssert(m_buffer, "Invalid sound buffer");
@ -80,13 +80,30 @@ namespace Nz
}
/*!
* \brief Gets the current offset in the sound
* \return Offset in milliseconds (works with entire seconds)
* \brief Gets the current playing offset of the sound
* \return Offset
*/
UInt32 Sound::GetPlayingOffset() const
Time Sound::GetPlayingOffset() const
{
UInt32 sampleCount = m_source->GetSampleOffset();
return SafeCast<UInt32>(1000ULL * sampleCount / m_buffer->GetSampleRate());
return m_source->GetPlayingOffset();
}
/*!
* \brief Gets the current sample offset of the sound
* \return Offset
*/
UInt64 Sound::GetSampleOffset() const
{
return m_source->GetSampleOffset();
}
/*!
* \brief Gets the sample rate of the sound
* \return Offset
*/
UInt32 Sound::GetSampleRate() const
{
return m_buffer->GetSampleRate();
}
/*!
@ -220,19 +237,17 @@ namespace Nz
}
/*!
* \brief Sets the playing offset for the sound
* \brief Sets the source to a sample offset
*
* \param offset Offset in the sound in milliseconds
* \param offset Sample offset
*/
void Sound::SetPlayingOffset(UInt32 offset)
void Sound::SeekToSampleOffset(UInt64 offset)
{
m_source->SetSampleOffset(SafeCast<UInt32>(UInt64(offset) * m_buffer->GetSampleRate() / 1000));
m_source->SetSampleOffset(SafeCast<UInt32>(offset));
}
/*!
* \brief Stops the sound
*
* \remark This is one of the only function that can be called on a moved sound (and does nothing)
*/
void Sound::Stop()
{

View File

@ -47,7 +47,7 @@ namespace Nz
NazaraAssert(sampleRate > 0, "sample rate must be different from zero");
NazaraAssert(samples, "invalid samples");
m_duration = SafeCast<UInt32>((1000ULL*sampleCount / (GetChannelCount(format) * sampleRate)));
m_duration = Time::Microseconds((1'000'000LL * sampleCount / (GetChannelCount(format) * sampleRate)));
m_format = format;
m_sampleCount = sampleCount;
m_sampleRate = sampleRate;

View File

@ -105,6 +105,17 @@ namespace Nz
return m_source->IsSpatializationEnabled();
}
/*!
* \brief Seek the sound to a point in time
*
* \param offset Time offset to seek
*/
void SoundEmitter::SeekToPlayingOffset(Time offset)
{
UInt64 microseconds = static_cast<UInt64>(std::max(offset.AsMicroseconds(), Int64(0)));
SeekToSampleOffset(SafeCast<UInt32>(microseconds * GetSampleRate() / 1'000'000));
}
/*!
* \brief Sets the attenuation
*

View File

@ -1,162 +0,0 @@
// Copyright (C) 2022 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 <Nazara/Core/Clock.hpp>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Core/Win32/ClockImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Core/Posix/ClockImpl.hpp>
#else
#error OS not handled
#endif
#include <Nazara/Core/Debug.hpp>
namespace Nz
{
namespace Detail
{
UInt64 GetMicrosecondsLowPrecision()
{
return ClockImplGetElapsedMilliseconds()*1000ULL;
}
UInt64 GetElapsedMicrosecondsFirstRun()
{
if (ClockImplInitializeHighPrecision())
GetElapsedMicroseconds = ClockImplGetElapsedMicroseconds;
else
GetElapsedMicroseconds = GetMicrosecondsLowPrecision;
return GetElapsedMicroseconds();
}
}
/*!
* \ingroup core
* \class Nz::Clock
* \brief Utility class that measure the elapsed time
*/
/*!
* \brief Constructs a Clock object
*
* \param startingValue The starting time value, in microseconds
* \param paused The clock pause state
*/
Clock::Clock(UInt64 startingValue, bool paused) :
m_elapsedTime(startingValue),
m_refTime(GetElapsedMicroseconds()),
m_paused(paused)
{
}
/*!
* Returns the elapsed time in seconds
* \return Seconds elapsed
*
* \see GetMicroseconds, GetMilliseconds
*/
float Clock::GetSeconds() const
{
return GetMicroseconds()/1'000'000.f;
}
/*!
* Returns the elapsed time in microseconds
* \return Microseconds elapsed
*
* \see GetMilliseconds, GetSeconds
*/
UInt64 Clock::GetMicroseconds() const
{
UInt64 elapsedMicroseconds = m_elapsedTime;
if (!m_paused)
elapsedMicroseconds += (GetElapsedMicroseconds() - m_refTime);
return elapsedMicroseconds;
}
/*!
* Returns the elapsed time in milliseconds
* \return Milliseconds elapsed
*
* \see GetMicroseconds, GetSeconds
*/
UInt64 Clock::GetMilliseconds() const
{
return GetMicroseconds()/1000;
}
/*!
* Returns the current pause state of the clock
* \return Boolean indicating if the clock is currently paused
*
* \see Pause, Unpause
*/
bool Clock::IsPaused() const
{
return m_paused;
}
/*!
* \brief Pause the clock
*
* Pauses the clock, making the time retrieving functions to always return the value at the time the clock was paused
* This has no effect if the clock is already paused
*
* \see IsPaused, Unpause
*/
void Clock::Pause()
{
if (!m_paused)
{
m_elapsedTime += GetElapsedMicroseconds() - m_refTime;
m_paused = true;
}
}
/*!
* \brief Restart the clock
* \return Microseconds elapsed
*
* Restarts the clock, putting it's time counter back to zero (as if the clock got constructed).
* It also compute the elapsed microseconds since the last Restart() call without any time loss (a problem that the combination of GetElapsedMicroseconds and Restart have).
*/
UInt64 Clock::Restart(UInt64 startingValue, bool paused)
{
Nz::UInt64 now = GetElapsedMicroseconds();
Nz::UInt64 elapsedTime = m_elapsedTime;
if (!m_paused)
elapsedTime += (now - m_refTime);
m_elapsedTime = startingValue;
m_refTime = now;
m_paused = paused;
return elapsedTime;
}
/*!
* \brief Unpause the clock
*
* Unpauses the clock, making the clock continue to measure the time
* This has no effect if the clock is already unpaused
*
* \see IsPaused, Unpause
*/
void Clock::Unpause()
{
if (m_paused)
{
m_refTime = GetElapsedMicroseconds();
m_paused = false;
}
}
ClockFunction GetElapsedMicroseconds = Detail::GetElapsedMicrosecondsFirstRun;
ClockFunction GetElapsedMilliseconds = ClockImplGetElapsedMilliseconds;
}

View File

@ -0,0 +1,29 @@
// Copyright (C) 2022 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 <Nazara/Core/Darwin/TimeImpl.hpp>
#include <time.h>
#include <Nazara/Core/Debug.hpp>
namespace Nz
{
bool InitializeHighPrecisionTimer()
{
return true; //< No initialization required
}
Time GetElapsedNanosecondsImpl()
{
UInt64 nanoseconds = clock_gettime_nsec_np(CLOCK_MONOTONIC_RAW);
return Time::Nanoseconds(static_cast<Int64>(nanoseconds));
}
Time GetElapsedMillisecondsImpl()
{
timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
return Time::Seconds(time.tv_sec) + Time::Nanoseconds(time.tv_nsec);
}
}

View File

@ -0,0 +1,20 @@
// Copyright (C) 2022 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_DARWIN_TIMEIMPL_HPP
#define NAZARA_CORE_DARWIN_TIMEIMPL_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Time.hpp>
namespace Nz
{
bool InitializeHighPrecisionTimer();
Time GetElapsedNanosecondsImpl();
Time GetElapsedMillisecondsImpl();
}
#endif // NAZARA_CORE_DARWIN_TIMEIMPL_HPP

View File

@ -1,29 +0,0 @@
// Copyright (C) 2022 Alexandre Janniaux
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Posix/ClockImpl.hpp>
#include <sys/time.h>
#include <Nazara/Core/Debug.hpp>
namespace Nz
{
bool ClockImplInitializeHighPrecision()
{
return true; // No initialization needed
}
UInt64 ClockImplGetElapsedMicroseconds()
{
timeval clock;
gettimeofday(&clock, nullptr);
return static_cast<UInt64>(clock.tv_sec*1000000 + clock.tv_usec);
}
UInt64 ClockImplGetElapsedMilliseconds()
{
timeval clock;
gettimeofday(&clock, nullptr);
return static_cast<UInt64>(clock.tv_sec*1000 + (clock.tv_usec/1000));
}
}

View File

@ -1,19 +0,0 @@
// Copyright (C) 2022 Alexandre Janniaux
// 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_POSIX_CLOCKIMPL_HPP
#define NAZARA_CORE_POSIX_CLOCKIMPL_HPP
#include <Nazara/Prerequisites.hpp>
namespace Nz
{
bool ClockImplInitializeHighPrecision();
UInt64 ClockImplGetElapsedMicroseconds();
UInt64 ClockImplGetElapsedMilliseconds();
}
#endif // NAZARA_CORE_POSIX_CLOCKIMPL_HPP

View File

@ -0,0 +1,31 @@
// Copyright (C) 2022 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 <Nazara/Core/Posix/TimeImpl.hpp>
#include <time.h>
#include <Nazara/Core/Debug.hpp>
namespace Nz
{
bool InitializeHighPrecisionTimer()
{
return true; //< No initialization required
}
Time GetElapsedNanosecondsImpl()
{
timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
return Time::Seconds(time.tv_sec) + Time::Nanoseconds(time.tv_nsec);
}
Time GetElapsedMillisecondsImpl()
{
timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
return Time::Seconds(time.tv_sec) + Time::Nanoseconds(time.tv_nsec);
}
}

View File

@ -4,16 +4,17 @@
#pragma once
#ifndef NAZARA_CORE_WIN32_CLOCKIMPL_HPP
#define NAZARA_CORE_WIN32_CLOCKIMPL_HPP
#ifndef NAZARA_CORE_POSIX_TIMEIMPL_HPP
#define NAZARA_CORE_POSIX_TIMEIMPL_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Time.hpp>
namespace Nz
{
bool ClockImplInitializeHighPrecision();
UInt64 ClockImplGetElapsedMicroseconds();
UInt64 ClockImplGetElapsedMilliseconds();
bool InitializeHighPrecisionTimer();
Time GetElapsedNanosecondsImpl();
Time GetElapsedMillisecondsImpl();
}
#endif // NAZARA_CORE_WIN32_CLOCKIMPL_HPP
#endif // NAZARA_CORE_POSIX_TIMEIMPL_HPP

View File

@ -8,7 +8,7 @@
namespace Nz
{
void LifetimeSystem::Update(float elapsedTime)
void LifetimeSystem::Update(Time elapsedTime)
{
auto view = m_registry.view<LifetimeComponent>();
for (auto [entity, lifetimeComponent] : view.each())

View File

@ -11,10 +11,10 @@ namespace Nz
void SystemGraph::Update()
{
return Update(m_clock.Restart() / 1'000'000.f);
return Update(m_clock.Restart());
}
void SystemGraph::Update(float elapsedTime)
void SystemGraph::Update(Time elapsedTime)
{
if (!m_systemOrderUpdated)
{

36
src/Nazara/Core/Time.cpp Normal file
View File

@ -0,0 +1,36 @@
// Copyright (C) 2022 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 <Nazara/Core/Time.hpp>
#if defined(NAZARA_PLATFORM_WINDOWS)
#include <Nazara/Core/Win32/TimeImpl.hpp>
#elif defined(NAZARA_PLATFORM_MACOS) || defined(NAZARA_PLATFORM_IOS)
#include <Nazara/Core/Darwin/TimeImpl.hpp>
#elif defined(NAZARA_PLATFORM_POSIX)
#include <Nazara/Core/Posix/TimeImpl.hpp>
#else
#error OS not handled
#endif
#include <Nazara/Core/Debug.hpp>
namespace Nz
{
namespace NAZARA_ANONYMOUS_NAMESPACE
{
Time GetElapsedNanosecondsFirstRun()
{
if (InitializeHighPrecisionTimer())
GetElapsedNanoseconds = GetElapsedNanosecondsImpl;
else
GetElapsedNanoseconds = GetElapsedMillisecondsImpl;
return GetElapsedNanoseconds();
}
}
GetElapsedTimeFunction GetElapsedMilliseconds = GetElapsedMillisecondsImpl;
GetElapsedTimeFunction GetElapsedNanoseconds = NAZARA_ANONYMOUS_NAMESPACE_PREFIX(GetElapsedNanosecondsFirstRun);
}

View File

@ -1,51 +0,0 @@
// Copyright (C) 2022 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 <Nazara/Core/Win32/ClockImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <ctime>
#include <windows.h>
#include <Nazara/Core/Debug.hpp>
namespace Nz
{
namespace NAZARA_ANONYMOUS_NAMESPACE
{
LARGE_INTEGER s_frequency; // La fréquence ne varie pas pas au cours de l'exécution
}
bool ClockImplInitializeHighPrecision()
{
NAZARA_USE_ANONYMOUS_NAMESPACE
return QueryPerformanceFrequency(&s_frequency) != 0;
}
UInt64 ClockImplGetElapsedMicroseconds()
{
NAZARA_USE_ANONYMOUS_NAMESPACE
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644904(v=vs.85).aspx
//HANDLE thread = GetCurrentThread();
//DWORD oldMask = SetThreadAffinityMask(thread, 1);
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
//SetThreadAffinityMask(thread, oldMask);
return time.QuadPart*1000000ULL / s_frequency.QuadPart;
}
UInt64 ClockImplGetElapsedMilliseconds()
{
#ifdef NAZARA_PLATFORM_WINDOWS_VISTA
return GetTickCount64();
#else
return GetTickCount();
#endif
}
}
#include <Nazara/Core/AntiWindows.hpp>

View File

@ -5,7 +5,7 @@
#include <Nazara/Core/Win32/FileImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <Nazara/Core/StringExt.hpp>
#include <Nazara/Core/Win32/Time.hpp>
#include <Nazara/Core/Win32/Utils.hpp>
#include <Nazara/Utils/CallOnExit.hpp>
#include <memory>
#include <Nazara/Core/Debug.hpp>

View File

@ -0,0 +1,62 @@
// Copyright (C) 2022 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 <Nazara/Core/Win32/TimeImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <ctime>
#include <windows.h>
#include <Nazara/Core/Debug.hpp>
namespace Nz
{
namespace NAZARA_ANONYMOUS_NAMESPACE
{
LARGE_INTEGER s_frequency; // The frequency of the performance counter is fixed at system boot and is consistent across all processors
}
bool InitializeHighPrecisionTimer()
{
NAZARA_USE_ANONYMOUS_NAMESPACE
return QueryPerformanceFrequency(&s_frequency) != 0 && s_frequency.QuadPart != 0;
}
Time GetElapsedNanosecondsImpl()
{
NAZARA_USE_ANONYMOUS_NAMESPACE
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
if (s_frequency.QuadPart == 10'000'000) //< seems to be a common value
return Time::Nanoseconds(100ll * time.QuadPart);
else
{
// Compute using 128bits precisions
// https://stackoverflow.com/questions/23378063/how-can-i-use-mach-absolute-time-without-overflowing
UInt64 num = 1'000'000'000ll;
UInt64 denom = s_frequency.QuadPart;
UInt64 value = time.QuadPart;
UInt64 high = (value >> 32) * num;
UInt64 low = (value & 0xFFFFFFFFull) * num / denom;
UInt64 highRem = ((high % denom) << 32) / denom;
high /= denom;
return Time::Nanoseconds(SafeCast<Int64>((high << 32) + highRem + low));
}
}
Time GetElapsedMillisecondsImpl()
{
#ifdef NAZARA_UTILS_WINDOWS_NT6
return Time::Milliseconds(GetTickCount64());
#else
return Time::Milliseconds(GetTickCount());
#endif
}
}
#include <Nazara/Core/AntiWindows.hpp>

View File

@ -0,0 +1,20 @@
// Copyright (C) 2022 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_WIN32_TIMEIMPL_HPP
#define NAZARA_CORE_WIN32_TIMEIMPL_HPP
#include <Nazara/Prerequisites.hpp>
#include <Nazara/Core/Time.hpp>
namespace Nz
{
bool InitializeHighPrecisionTimer();
Time GetElapsedNanosecondsImpl();
Time GetElapsedMillisecondsImpl();
}
#endif // NAZARA_CORE_WIN32_TIMEIMPL_HPP

View File

@ -2,7 +2,7 @@
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/Win32/Time.hpp>
#include <Nazara/Core/Win32/Utils.hpp>
#include <Nazara/Core/Debug.hpp>
namespace Nz

View File

@ -4,8 +4,8 @@
#pragma once
#ifndef NAZARA_CORE_WIN32_TIME_HPP
#define NAZARA_CORE_WIN32_TIME_HPP
#ifndef NAZARA_CORE_WIN32_UTILS_HPP
#define NAZARA_CORE_WIN32_UTILS_HPP
#include <Nazara/Prerequisites.hpp>
#include <ctime>
@ -16,4 +16,4 @@ namespace Nz
time_t FileTimeToTime(FILETIME* time);
}
#endif // NAZARA_CORE_WIN32_TIME_HPP
#endif // NAZARA_CORE_WIN32_UTILS_HPP

View File

@ -48,7 +48,7 @@ namespace Nz
m_pipeline.reset();
}
void RenderSystem::Update(float /*elapsedTime*/)
void RenderSystem::Update(Time /*elapsedTime*/)
{
UpdateObservers();
UpdateVisibility();

View File

@ -1245,7 +1245,7 @@ namespace Nz
void ENetHost::ThrottleBandwidth()
{
UInt32 currentTime = UInt32(GetElapsedMilliseconds());
UInt32 currentTime = UInt32(GetElapsedMilliseconds().AsMilliseconds());
UInt32 elapsedTime = currentTime - m_bandwidthThrottleEpoch;
if (elapsedTime < ENetConstants::ENetHost_BandwidthThrottleInterval)

View File

@ -80,8 +80,8 @@ namespace Nz
PhysWorld2D::PhysWorld2D() :
m_maxStepCount(50),
m_stepSize(0.005f),
m_timestepAccumulator(0.f)
m_stepSize(Time::TickDuration(200)),
m_timestepAccumulator(Time::Zero())
{
m_handle = cpSpaceNew();
cpSpaceSetUserData(m_handle, this);
@ -154,7 +154,7 @@ namespace Nz
return m_maxStepCount;
}
float PhysWorld2D::GetStepSize() const
Time PhysWorld2D::GetStepSize() const
{
return m_stepSize;
}
@ -328,7 +328,7 @@ namespace Nz
void PhysWorld2D::SetIterationCount(std::size_t iterationCount)
{
cpSpaceSetIterations(m_handle, int(iterationCount));
cpSpaceSetIterations(m_handle, SafeCast<int>(iterationCount));
}
void PhysWorld2D::SetMaxStepCount(std::size_t maxStepCount)
@ -336,30 +336,32 @@ namespace Nz
m_maxStepCount = maxStepCount;
}
void PhysWorld2D::SetSleepTime(float sleepTime)
void PhysWorld2D::SetSleepTime(Time sleepTime)
{
if (sleepTime > 0)
cpSpaceSetSleepTimeThreshold(m_handle, cpFloat(sleepTime));
if (sleepTime > Time::Zero())
cpSpaceSetSleepTimeThreshold(m_handle, sleepTime.AsSeconds<cpFloat>());
else
cpSpaceSetSleepTimeThreshold(m_handle, std::numeric_limits<cpFloat>::infinity());
}
void PhysWorld2D::SetStepSize(float stepSize)
void PhysWorld2D::SetStepSize(Time stepSize)
{
m_stepSize = stepSize;
}
void PhysWorld2D::Step(float timestep)
void PhysWorld2D::Step(Time timestep)
{
m_timestepAccumulator += timestep;
std::size_t stepCount = std::min(static_cast<std::size_t>(m_timestepAccumulator / m_stepSize), m_maxStepCount);
std::size_t stepCount = std::min(static_cast<std::size_t>(static_cast<Int64>(m_timestepAccumulator / m_stepSize)), m_maxStepCount);
float invStepCount = 1.f / stepCount;
cpFloat dt = m_stepSize.AsSeconds<float>(); //< FIXME: AsSeconds<cpFloat> is more precise but it fails unit tests on Linux
for (std::size_t i = 0; i < stepCount; ++i)
{
OnPhysWorld2DPreStep(this, invStepCount);
cpSpaceStep(m_handle, m_stepSize);
cpSpaceStep(m_handle, dt);
OnPhysWorld2DPostStep(this, invStepCount);
if (!m_rigidPostSteps.empty())

View File

@ -33,7 +33,7 @@ namespace Nz
rigidBodyComponent.Destroy();
}
void Physics2DSystem::Update(float elapsedTime)
void Physics2DSystem::Update(Time elapsedTime)
{
m_physWorld.Step(elapsedTime);

View File

@ -13,8 +13,8 @@ namespace Nz
PhysWorld3D::PhysWorld3D() :
m_maxStepCount(50),
m_gravity(Vector3f::Zero()),
m_stepSize(1.f / 120.f),
m_timestepAccumulator(0.f)
m_stepSize(Time::TickDuration(120)),
m_timestepAccumulator(Time::Zero())
{
m_world = NewtonCreate();
NewtonWorldSetUserData(m_world, this);
@ -86,7 +86,7 @@ namespace Nz
return m_maxStepCount;
}
float PhysWorld3D::GetStepSize() const
Time PhysWorld3D::GetStepSize() const
{
return m_stepSize;
}
@ -106,7 +106,7 @@ namespace Nz
m_maxStepCount = maxStepCount;
}
void PhysWorld3D::SetStepSize(float stepSize)
void PhysWorld3D::SetStepSize(Time stepSize)
{
m_stepSize = stepSize;
}
@ -159,14 +159,16 @@ namespace Nz
NewtonMaterialSetSurfaceThickness(m_world, firstMaterial, secondMaterial, thickness);
}
void PhysWorld3D::Step(float timestep)
void PhysWorld3D::Step(Time timestep)
{
m_timestepAccumulator += timestep;
std::size_t stepCount = 0;
float dt = m_stepSize.AsSeconds<float>();
while (m_timestepAccumulator >= m_stepSize && stepCount < m_maxStepCount)
{
NewtonUpdate(m_world, m_stepSize);
NewtonUpdate(m_world, dt);
m_timestepAccumulator -= m_stepSize;
stepCount++;
}

View File

@ -22,7 +22,7 @@ namespace Nz
rigidBodyComponent.Destroy();
}
void Physics3DSystem::Update(float elapsedTime)
void Physics3DSystem::Update(Time elapsedTime)
{
m_physWorld.Step(elapsedTime);

View File

@ -22,7 +22,7 @@ namespace Nz
if (m_framerateLimit > 0)
{
int remainingTime = 1000 / static_cast<int>(m_framerateLimit) - static_cast<int>(m_clock.GetMilliseconds());
int remainingTime = 1000 / static_cast<int>(m_framerateLimit) - static_cast<int>(m_clock.GetElapsedTime().AsMilliseconds());
if (remainingTime > 0)
std::this_thread::sleep_for(std::chrono::milliseconds(remainingTime));

View File

@ -23,7 +23,7 @@ namespace Nz
m_skeletonConstructObserver.disconnect();
}
void SkeletonSystem::Update(float /*elapsedTime*/)
void SkeletonSystem::Update(Time /*elapsedTime*/)
{
m_sharedSkeletonConstructObserver.each([&](entt::entity entity)
{

View File

@ -277,8 +277,6 @@ namespace Nz
return false;
}
m_clock.Restart();
return true;
}

View File

@ -133,7 +133,7 @@ int main()
SpriteRenderData spriteRenderData1 = BuildSpriteData(*device, spriteRenderPipeline, Nz::Rectf(margin, windowSize.y - margin - textureSize, textureSize, textureSize), Nz::Vector2f(windowSize), *texture, *textureSampler);
SpriteRenderData spriteRenderData2 = BuildSpriteData(*device, spriteRenderPipeline, Nz::Rectf(windowSize.x - textureSize - margin, windowSize.y - margin - textureSize, textureSize, textureSize), Nz::Vector2f(windowSize), *targetTexture, *textureSampler);
Nz::Clock secondClock;
Nz::MillisecondClock fpsClock;
unsigned int fps = 0;
while (window.IsOpen())
@ -205,13 +205,10 @@ int main()
fps++;
if (secondClock.GetMilliseconds() >= 1000)
if (fpsClock.RestartIfOver(Nz::Time::Second()))
{
window.SetTitle(windowTitle + " - " + Nz::NumberToString(fps) + " FPS");
fps = 0;
secondClock.Restart();
}
}

View File

@ -116,8 +116,8 @@ int main()
window.EnableEventPolling(true);
Nz::Clock updateClock;
Nz::Clock secondClock;
Nz::MillisecondClock updateClock;
Nz::MillisecondClock fpsClock;
unsigned int fps = 0;
Nz::Mouse::SetRelativeMouseMode(true);
@ -181,10 +181,9 @@ int main()
}
}
if (updateClock.GetMilliseconds() > 1000 / 60)
if (std::optional<Nz::Time> deltaTime = updateClock.RestartIfOver(Nz::Time::TickDuration(60)))
{
float cameraSpeed = 2.f * updateClock.GetSeconds();
updateClock.Restart();
float cameraSpeed = 2.f * deltaTime->AsSeconds();
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Up) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Z))
viewerPos += camQuat * Nz::Vector3f::Forward() * cameraSpeed;
@ -231,23 +230,10 @@ int main()
// On incrémente le compteur de FPS improvisé
fps++;
if (secondClock.GetMilliseconds() >= 1000) // Toutes les secondes
if (fpsClock.RestartIfOver(Nz::Time::Second()))
{
// Et on insère ces données dans le titre de la fenêtre
window.SetTitle(windowTitle + " - " + Nz::NumberToString(fps) + " FPS");
/*
Note: En C++11 il est possible d'insérer de l'Unicode de façon standard, quel que soit l'encodage du fichier,
via quelque chose de similaire à u8"Cha\u00CEne de caract\u00E8res".
Cependant, si le code source est encodé en UTF-8 (Comme c'est le cas dans ce fichier),
cela fonctionnera aussi comme ceci : "Chaîne de caractères".
*/
// Et on réinitialise le compteur de FPS
fps = 0;
// Et on relance l'horloge pour refaire ça dans une seconde
secondClock.Restart();
}
}

View File

@ -253,8 +253,8 @@ int main()
window.EnableEventPolling(true);
Nz::Clock updateClock;
Nz::Clock secondClock;
Nz::MillisecondClock updateClock;
Nz::MillisecondClock secondClock;
unsigned int fps = 0;
bool uboUpdate = true;
@ -304,10 +304,9 @@ int main()
}
}
if (updateClock.GetMilliseconds() > 1000 / 60)
if (std::optional<Nz::Time> deltaTime = updateClock.RestartIfOver(Nz::Time::TickDuration(60)))
{
float cameraSpeed = 2.f * updateClock.GetSeconds();
updateClock.Restart();
float cameraSpeed = 2.f * deltaTime->AsSeconds();
if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Up) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Z))
viewerPos += camQuat * Nz::Vector3f::Forward() * cameraSpeed;
@ -412,7 +411,7 @@ int main()
// On incrémente le compteur de FPS improvisé
fps++;
if (secondClock.GetMilliseconds() >= 1000) // Toutes les secondes
if (secondClock.RestartIfOver(Nz::Time::Second()))
{
// Et on insère ces données dans le titre de la fenêtre
window.SetTitle(windowTitle + " - " + Nz::NumberToString(fps) + " FPS");
@ -426,9 +425,6 @@ int main()
// Et on réinitialise le compteur de FPS
fps = 0;
// Et on relance l'horloge pour refaire ça dans une seconde
secondClock.Restart();
}
}

View File

@ -9,6 +9,8 @@ std::filesystem::path GetAssetDir();
SCENARIO("Music", "[AUDIO][MUSIC]")
{
using namespace Nz::Literals;
GIVEN("A music")
{
Nz::Music music;
@ -19,9 +21,9 @@ SCENARIO("Music", "[AUDIO][MUSIC]")
THEN("We can ask the informations of the file")
{
CHECK(music.GetDuration() == 63059); // 1 min 03 = 63s = 63000ms
CHECK(music.GetDuration() == 63'059'591_us); // 1 min 03 = 63s = 63000ms
CHECK(music.GetFormat() == Nz::AudioFormat::I16_Stereo);
CHECK(music.GetPlayingOffset() == 0);
CHECK(music.GetPlayingOffset() == 0_ms);
CHECK(music.GetSampleCount() <= 64 * 44100 * 2); // * 2 (stereo)
CHECK(music.GetSampleCount() >= 63 * 44100 * 2); // * 2 (stereo)
CHECK(music.GetSampleRate() == 44100 /* Hz */);
@ -30,7 +32,7 @@ SCENARIO("Music", "[AUDIO][MUSIC]")
CHECK(music.IsSpatializationEnabled());
CHECK(music.GetMinDistance() == 1.f);
CHECK(music.GetPitch() == 1.f);
CHECK(music.GetPlayingOffset() == 0);
CHECK(music.GetPlayingOffset() == 0_ms);
CHECK(music.GetPosition() == Nz::Vector3f::Zero());
CHECK(music.GetVelocity() == Nz::Vector3f::Zero());
CHECK(music.GetVolume() == 1.f);
@ -42,53 +44,54 @@ SCENARIO("Music", "[AUDIO][MUSIC]")
music.Play();
CHECK(music.GetStatus() == Nz::SoundStatus::Playing);
std::this_thread::sleep_for(std::chrono::seconds(1));
CHECK(music.GetPlayingOffset() >= 950);
std::this_thread::sleep_for(std::chrono::seconds(1));
Nz::Time t = music.GetPlayingOffset();
CHECK(music.GetPlayingOffset() >= 950_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
CHECK(music.GetPlayingOffset() <= 1500);
CHECK(music.GetPlayingOffset() <= 1500_ms);
music.SetPlayingOffset(4200);
music.SeekToPlayingOffset(4200_ms);
CHECK(music.GetStatus() == Nz::SoundStatus::Playing);
CHECK(music.GetPlayingOffset() >= 4150);
CHECK(music.GetPlayingOffset() < 4500);
CHECK(music.GetPlayingOffset() >= 4150_ms);
CHECK(music.GetPlayingOffset() < 4500_ms);
CHECK(music.GetStatus() == Nz::SoundStatus::Playing);
music.Pause();
Nz::UInt32 playingOffset = music.GetPlayingOffset();
Nz::Time playingOffset = music.GetPlayingOffset();
CHECK(music.GetStatus() == Nz::SoundStatus::Paused);
std::this_thread::sleep_for(std::chrono::milliseconds(50));
CHECK(music.GetStatus() == Nz::SoundStatus::Paused);
CHECK(music.GetPlayingOffset() == playingOffset);
music.SetPlayingOffset(3500);
music.SeekToPlayingOffset(3500_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
CHECK(music.GetPlayingOffset() == 3500);
CHECK(music.GetPlayingOffset() == 3500_ms);
music.Play();
std::this_thread::sleep_for(std::chrono::milliseconds(200));
CHECK(music.GetStatus() == Nz::SoundStatus::Playing);
CHECK(music.GetPlayingOffset() >= 3650);
CHECK(music.GetPlayingOffset() >= 3650_ms);
AND_WHEN("We let the sound stop by itself")
{
REQUIRE(music.GetDuration() == 63059);
REQUIRE(music.GetDuration() == 63'059'591_us);
music.SetPlayingOffset(62900);
music.SeekToPlayingOffset(62900_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
CHECK(music.GetStatus() == Nz::SoundStatus::Stopped);
CHECK(music.GetPlayingOffset() == 0);
CHECK(music.GetPlayingOffset() == 0_ms);
music.SetPlayingOffset(64000);
music.SeekToPlayingOffset(64000_ms);
music.Play();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
CHECK(music.GetStatus() == Nz::SoundStatus::Playing);
CHECK(music.GetPlayingOffset() < 100);
CHECK(music.GetPlayingOffset() < 100_ms);
music.Stop();
music.SetPlayingOffset(62900);
music.SeekToPlayingOffset(62900_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(50));
CHECK(music.GetStatus() == Nz::SoundStatus::Stopped);
CHECK(music.GetPlayingOffset() == 0); //< playing offset has no effect until Play()
CHECK(music.GetPlayingOffset() == 0_ms); //< playing offset has no effect until Play()
AND_WHEN("We enable looping")
{
@ -96,10 +99,10 @@ SCENARIO("Music", "[AUDIO][MUSIC]")
CHECK(music.IsLooping());
music.Play();
CHECK(music.GetStatus() == Nz::SoundStatus::Playing);
CHECK(music.GetPlayingOffset() >= 62900);
CHECK(music.GetPlayingOffset() >= 62900_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
CHECK(music.GetStatus() == Nz::SoundStatus::Playing);
CHECK(music.GetPlayingOffset() < 300);
CHECK(music.GetPlayingOffset() < 300_ms);
}
}
Nz::Audio::Instance()->GetDefaultDevice()->SetGlobalVolume(100.f);

View File

@ -6,6 +6,8 @@ std::filesystem::path GetAssetDir();
SCENARIO("SoundBuffer", "[AUDIO][SOUNDBUFFER]")
{
using namespace Nz::Literals;
GIVEN("A sound buffer")
{
WHEN("We load a .flac file")
@ -15,7 +17,7 @@ SCENARIO("SoundBuffer", "[AUDIO][SOUNDBUFFER]")
THEN("We can ask the informations of the file")
{
CHECK(soundBuffer->GetDuration() == 8192);
CHECK(soundBuffer->GetDuration() == 8192_ms);
CHECK(soundBuffer->GetFormat() == Nz::AudioFormat::I16_Stereo);
CHECK(soundBuffer->GetSampleRate() == 96000);
}
@ -28,7 +30,7 @@ SCENARIO("SoundBuffer", "[AUDIO][SOUNDBUFFER]")
THEN("We can ask the informations of the file")
{
CHECK(soundBuffer->GetDuration() == 27193);
CHECK(soundBuffer->GetDuration() == 27'193'468_us);
CHECK(soundBuffer->GetFormat() == Nz::AudioFormat::I16_Stereo);
CHECK(soundBuffer->GetSampleRate() == 32000);
}
@ -41,7 +43,7 @@ SCENARIO("SoundBuffer", "[AUDIO][SOUNDBUFFER]")
THEN("We can ask the informations of the file")
{
CHECK(soundBuffer->GetDuration() == 63059);
CHECK(soundBuffer->GetDuration() == 63'059'591_us);
CHECK(soundBuffer->GetFormat() == Nz::AudioFormat::I16_Stereo);
CHECK(soundBuffer->GetSampleRate() == 44100);
}
@ -54,7 +56,7 @@ SCENARIO("SoundBuffer", "[AUDIO][SOUNDBUFFER]")
THEN("We can ask the informations of the file")
{
CHECK(soundBuffer->GetDuration() == 2490);
CHECK(soundBuffer->GetDuration() == 2'490'340_us);
CHECK(soundBuffer->GetFormat() == Nz::AudioFormat::I16_Mono);
CHECK(soundBuffer->GetSampleRate() == 44100);
}

View File

@ -6,6 +6,8 @@ std::filesystem::path GetAssetDir();
SCENARIO("SoundStream", "[AUDIO][SoundStream]")
{
using namespace Nz::Literals;
GIVEN("A sound buffer")
{
WHEN("We load a .flac file")
@ -15,7 +17,7 @@ SCENARIO("SoundStream", "[AUDIO][SoundStream]")
THEN("We can ask the informations of the file")
{
CHECK(soundStream->GetDuration() == 8192);
CHECK(soundStream->GetDuration() == 8192_ms);
CHECK(soundStream->GetFormat() == Nz::AudioFormat::I16_Stereo);
CHECK(soundStream->GetSampleRate() == 96000);
}
@ -28,7 +30,7 @@ SCENARIO("SoundStream", "[AUDIO][SoundStream]")
THEN("We can ask the informations of the file")
{
CHECK(soundStream->GetDuration() == 27193);
CHECK(soundStream->GetDuration() == 27'193'468_us);
CHECK(soundStream->GetFormat() == Nz::AudioFormat::I16_Stereo);
CHECK(soundStream->GetSampleRate() == 32000);
}
@ -41,7 +43,7 @@ SCENARIO("SoundStream", "[AUDIO][SoundStream]")
THEN("We can ask the informations of the file")
{
CHECK(soundStream->GetDuration() == 63059);
CHECK(soundStream->GetDuration() == 63'059'591_us);
CHECK(soundStream->GetFormat() == Nz::AudioFormat::I16_Stereo);
CHECK(soundStream->GetSampleRate() == 44100);
}
@ -54,7 +56,7 @@ SCENARIO("SoundStream", "[AUDIO][SoundStream]")
THEN("We can ask the informations of the file")
{
CHECK(soundStream->GetDuration() == 2490);
CHECK(soundStream->GetDuration() == 2'490'340_us);
CHECK(soundStream->GetFormat() == Nz::AudioFormat::I16_Mono);
CHECK(soundStream->GetSampleRate() == 44100);
}

View File

@ -3,12 +3,15 @@
#include <catch2/catch_approx.hpp>
#include <catch2/catch_test_macros.hpp>
#include <chrono>
#include <iostream>
#include <thread>
std::filesystem::path GetAssetDir();
SCENARIO("Sound", "[AUDIO][SOUND]")
{
using namespace Nz::Literals;
GIVEN("A sound")
{
Nz::Sound sound;
@ -19,14 +22,14 @@ SCENARIO("Sound", "[AUDIO][SOUND]")
THEN("We can ask the informations of the file")
{
CHECK(sound.GetDuration() == 8192);
CHECK(sound.GetDuration() == 8192_ms);
CHECK(sound.GetStatus() == Nz::SoundStatus::Stopped);
CHECK_FALSE(sound.IsLooping());
CHECK(sound.IsPlayable());
CHECK(sound.IsSpatializationEnabled());
CHECK(sound.GetMinDistance() == 1.f);
CHECK(sound.GetPitch() == 1.f);
CHECK(sound.GetPlayingOffset() == 0);
CHECK(sound.GetPlayingOffset() == 0_ms);
CHECK(sound.GetPosition() == Nz::Vector3f::Zero());
CHECK(sound.GetVelocity() == Nz::Vector3f::Zero());
CHECK(sound.GetVolume() == 1.f);
@ -38,42 +41,45 @@ SCENARIO("Sound", "[AUDIO][SOUND]")
sound.Play();
std::this_thread::sleep_for(std::chrono::seconds(1));
CHECK(sound.GetPlayingOffset() >= 950);
CHECK(sound.GetPlayingOffset() >= 950_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
CHECK(sound.GetPlayingOffset() <= 1500);
CHECK(sound.GetPlayingOffset() <= 1500_ms);
sound.Pause();
Nz::UInt32 playingOffset = sound.GetPlayingOffset();
Nz::Time playingOffset = sound.GetPlayingOffset();
Nz::UInt64 sampleOffset = sound.GetSampleOffset();
CHECK(sound.GetStatus() == Nz::SoundStatus::Paused);
std::this_thread::sleep_for(std::chrono::milliseconds(50));
CHECK(sound.GetStatus() == Nz::SoundStatus::Paused);
CHECK(sound.GetPlayingOffset() == playingOffset);
CHECK(sound.GetSampleOffset() == sampleOffset);
sound.SetPlayingOffset(3500);
CHECK(sound.GetPlayingOffset() == 3500);
sound.SeekToPlayingOffset(3500_ms);
CHECK(sound.GetPlayingOffset() == 3500_ms);
sound.Play();
std::this_thread::sleep_for(std::chrono::milliseconds(200));
CHECK(sound.GetPlayingOffset() >= 1650);
CHECK(sound.GetPlayingOffset() >= 1650_ms);
AND_WHEN("We let the sound stop by itself")
{
REQUIRE(sound.GetDuration() == 8192);
REQUIRE(sound.GetDuration() == 8192_ms);
sound.SetPlayingOffset(8000);
sound.SeekToPlayingOffset(8000_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(200));
CHECK(sound.GetStatus() == Nz::SoundStatus::Stopped);
CHECK(sound.GetPlayingOffset() == 0);
CHECK(sound.GetPlayingOffset() == 0_ms);
sound.SetPlayingOffset(9000);
sound.SeekToPlayingOffset(9000_ms);
sound.Play();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
CHECK(sound.GetStatus() == Nz::SoundStatus::Playing);
sound.Stop();
sound.SetPlayingOffset(8000);
sound.SeekToPlayingOffset(8000_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(50));
CHECK(sound.GetStatus() == Nz::SoundStatus::Stopped);
CHECK(sound.GetPlayingOffset() == 0); //< playing offset has no effect until Play()
CHECK(sound.GetPlayingOffset() == 0_ms); //< playing offset has no effect until Play()
AND_WHEN("We enable looping")
{
@ -81,10 +87,10 @@ SCENARIO("Sound", "[AUDIO][SOUND]")
CHECK(sound.IsLooping());
sound.Play();
CHECK(sound.GetStatus() == Nz::SoundStatus::Playing);
CHECK(sound.GetPlayingOffset() >= 8000);
CHECK(sound.GetPlayingOffset() >= 8000_ms);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
CHECK(sound.GetStatus() == Nz::SoundStatus::Playing);
CHECK(sound.GetPlayingOffset() < 300);
CHECK(sound.GetPlayingOffset() < 300_ms);
}
}

View File

@ -8,14 +8,14 @@ SCENARIO("Clock", "[CORE][CLOCK]")
{
GIVEN("A clock paused")
{
Nz::UInt64 initialTime = 100;
Nz::Clock clock(initialTime, true);
Nz::Time initialTime = Nz::Time::Microseconds(100);
Nz::HighPrecisionClock clock(initialTime, true);
WHEN("We get time since it is paused")
{
THEN("Time must be the initialTime")
{
CHECK(clock.GetMicroseconds() == initialTime);
CHECK(clock.GetElapsedTime() == initialTime);
CHECK(clock.IsPaused());
}
}
@ -28,10 +28,11 @@ SCENARIO("Clock", "[CORE][CLOCK]")
THEN("Time must not be the initialTime")
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
Nz::UInt64 microSeconds = clock.GetMicroseconds();
CHECK(microSeconds != initialTime);
CHECK(microSeconds / 1000 <= clock.GetMilliseconds());
CHECK(microSeconds / (1000.f * 1000.f) <= clock.GetSeconds());
Nz::Time elapsedTime = clock.GetElapsedTime();
Nz::Int64 microseconds = elapsedTime.AsMicroseconds();
CHECK(microseconds != initialTime.AsMicroseconds());
CHECK(microseconds / 1000 <= elapsedTime.AsMilliseconds());
CHECK(microseconds / (1000.f * 1000.f) <= elapsedTime.AsSeconds());
}
}
@ -44,7 +45,7 @@ SCENARIO("Clock", "[CORE][CLOCK]")
CHECK(!clock.IsPaused());
clock.Pause();
CHECK(clock.IsPaused());
CHECK(clock.GetMicroseconds() != initialTime);
CHECK(clock.GetElapsedTime() != initialTime);
}
}
}

View File

@ -0,0 +1,52 @@
#include <Nazara/Core/Time.hpp>
#include <catch2/catch_approx.hpp>
#include <catch2/catch_test_macros.hpp>
#include <sstream>
#include <string>
SCENARIO("Time", "[CORE][Time]")
{
auto ToString = [](Nz::Time time) -> std::string
{
std::ostringstream ss;
ss << time;
return std::move(ss).str();
};
GIVEN("One second")
{
Nz::Time time = Nz::Time::Second();
CHECK(time.AsDuration<std::chrono::seconds>() == std::chrono::seconds(1));
CHECK(time.AsDuration<std::chrono::milliseconds>() == std::chrono::milliseconds(1'000));
CHECK(time.AsDuration<std::chrono::microseconds>() == std::chrono::microseconds(1'000'000));
CHECK(time.AsMicroseconds() == 1'000'000);
CHECK(time.AsMilliseconds() == 1'000);
CHECK(time.AsSeconds() == 1.f);
CHECK(time == Nz::Time::Second());
CHECK(time == Nz::Time::Seconds(1.f));
CHECK(time == Nz::Time::Milliseconds(1'000));
CHECK(time == Nz::Time::Seconds(2) - Nz::Time::Milliseconds(1'000));
CHECK(ToString(time) == "1000ms");
}
GIVEN("One arbitrary duration")
{
Nz::Time time = Nz::Time::FromDuration(std::chrono::nanoseconds(1'234'567'890ULL)) - Nz::Time::Nanoseconds(890);
CHECK(time == Nz::Time::Microseconds(1'234'567));
CHECK_FALSE(time == Nz::Time::Microseconds(1'234'568));
CHECK(time != Nz::Time::Microseconds(1'234'566));
CHECK_FALSE(time != Nz::Time::Microseconds(1'234'567));
CHECK(time > Nz::Time::Microseconds(1'234'000));
CHECK(time > Nz::Time::Zero());
CHECK(time >= Nz::Time::Microseconds(1'234'567));
CHECK(time >= Nz::Time::Microseconds(1'234'000));
CHECK(time < Nz::Time::Milliseconds(1'235));
CHECK(time <= Nz::Time::Microseconds(1'234'567));
CHECK(time <= Nz::Time::Seconds(2));
CHECK(ToString(time) == "1.23457s");
CHECK(ToString(time - Nz::Time::Second()) == "234.567ms");
CHECK(ToString(time - Nz::Time::Seconds(1.234f)) == "567us");
}
}

View File

@ -24,7 +24,7 @@ SCENARIO("PhysWorld2D", "[PHYSICS2D][PHYSWORLD2D]")
}
}
world.Step(1.f);
world.Step(Nz::Time::Second());
WHEN("We ask for the nearest body")
{
@ -130,7 +130,7 @@ SCENARIO("PhysWorld2D", "[PHYSICS2D][PHYSWORLD2D]")
Nz::RigidBody2D trigger(&world, 0.f, triggerBox);
trigger.SetPosition(Nz::Vector2f(2.f, 0.f));
world.Step(0.f);
world.Step(Nz::Time::Zero());
Nz::PhysWorld2D::Callback characterTriggerCallback;
characterTriggerCallback.startCallback = [&](Nz::PhysWorld2D&, Nz::Arbiter2D&, Nz::RigidBody2D&, Nz::RigidBody2D&, void*) -> bool {
@ -164,27 +164,29 @@ SCENARIO("PhysWorld2D", "[PHYSICS2D][PHYSWORLD2D]")
{
character.SetVelocity(Nz::Vector2f(1.f, 0.f));
for (int i = 0; i != 11; ++i)
world.Step(0.1f);
world.Step(Nz::Time::TickDuration(10));
THEN("It should trigger several collisions")
{
CHECK(statusTriggerCollision == 3);
for (int i = 0; i != 20; ++i)
world.Step(0.1f);
world.Step(Nz::Time::TickDuration(10));
CHECK(statusTriggerCollision == 11);
CHECK(character.GetPosition().x == Catch::Approx(3.1f).margin(0.01f));
for (int i = 0; i != 9; ++i)
world.Step(0.1f);
world.Step(Nz::Time::TickDuration(10));
CHECK(character.GetPosition().x == Catch::Approx(4.f).margin(0.01f));
world.Step(0.1f);
world.Step(Nz::Time::TickDuration(10));
CHECK(character.GetPosition().x == Catch::Approx(4.f).margin(0.01f));
CHECK(statusWallCollision == 1); // It should be close to the wall
character.SetVelocity(Nz::Vector2f(-2.f, 0.f));
for (int i = 0; i != 10; ++i)
world.Step(0.1f);
world.Step(Nz::Time::TickDuration(10));
CHECK(statusWallCollision == 3);
}
}

View File

@ -34,14 +34,14 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]")
bool userdata = false;
body.SetUserdata(&userdata);
world.Step(1.f);
world.Step(Nz::Time::Second());
WHEN("We copy construct the body")
{
body.AddForce(Nz::Vector2f(3.f, 5.f));
Nz::RigidBody2D copiedBody(body);
EQUALITY(copiedBody, body);
world.Step(1.f);
world.Step(Nz::Time::Second());
EQUALITY(copiedBody, body);
}
@ -72,7 +72,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]")
float radius = 5.f;
body.SetGeom(std::make_shared<Nz::CircleCollider2D>(radius));
world.Step(1.f);
world.Step(Nz::Time::Second());
THEN("The aabb should be updated")
{
@ -96,7 +96,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]")
tmp.push_back(CreateBody(world));
tmp.push_back(CreateBody(world));
world.Step(1.f);
world.Step(Nz::Time::Second());
THEN("They should be valid")
{
@ -124,7 +124,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]")
Nz::Vector2f position = Nz::Vector2f::Zero();
body.SetPosition(position);
world.Step(1.f);
world.Step(Nz::Time::Second());
WHEN("We retrieve standard information")
{
@ -150,7 +150,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]")
Nz::Vector2f velocity(Nz::Vector2f::Unit());
body.SetVelocity(velocity);
position += velocity;
world.Step(1.f);
world.Step(Nz::Time::Second());
THEN("We expect those to be true")
{
@ -164,7 +164,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]")
AND_THEN("We apply an impulse in the opposite direction")
{
body.AddImpulse(-velocity);
world.Step(1.f);
world.Step(Nz::Time::Second());
REQUIRE(body.GetVelocity() == Nz::Vector2f::Zero());
}
@ -174,23 +174,24 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]")
{
Nz::RadianAnglef angularSpeed = Nz::RadianAnglef::FromDegrees(90.f);
body.SetAngularVelocity(angularSpeed);
world.Step(1.f);
world.Step(Nz::Time::Second());
THEN("We expect those to be true")
{
CHECK(body.GetAngularVelocity() == angularSpeed);
CHECK(body.GetRotation() == angularSpeed);
CHECK(body.GetAABB() == Nz::Rectf(-6.f, 3.f, 2.f, 1.f));
CHECK(body.GetAABB().ApproxEquals(Nz::Rectf(-6.f, 3.f, 2.f, 1.f), 0.00001f));
world.Step(1.f);
world.Step(Nz::Time::Second());
CHECK(body.GetRotation() == 2.f * angularSpeed);
CHECK(body.GetAABB() == Nz::Rectf(-4.f, -6.f, 1.f, 2.f));
CHECK(body.GetAABB().ApproxEquals(Nz::Rectf(-4.f, -6.f, 1.f, 2.f), 0.00001f));
world.Step(1.f);
world.Step(Nz::Time::Second());
CHECK(body.GetRotation() == 3.f * angularSpeed);
CHECK(body.GetAABB() == Nz::Rectf(4.f, -4.f, 2.f, 1.f));
CHECK(body.GetAABB().ApproxEquals(Nz::Rectf(4.f, -4.f, 2.f, 1.f), 0.00001f));
world.Step(1.f);
world.Step(Nz::Time::Second());
CHECK(body.GetRotation() == 4.f * angularSpeed);
}
}
@ -198,7 +199,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]")
WHEN("We apply a torque")
{
body.AddTorque(Nz::DegreeAnglef(90.f));
world.Step(1.f);
world.Step(Nz::Time::Second());
THEN("It is also counter-clockwise")
{
@ -220,7 +221,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]")
Nz::RigidBody2D body(&world, mass);
body.SetGeom(circle, true, false);
world.Step(1.f);
world.Step(Nz::Time::Second());
WHEN("We ask for the aabb of the circle")
{
@ -251,7 +252,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]")
Nz::RigidBody2D body(&world, mass);
body.SetGeom(compound, true, false);
world.Step(1.f);
world.Step(Nz::Time::Second());
WHEN("We ask for the aabb of the compound")
{
@ -280,7 +281,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]")
Nz::RigidBody2D body(&world, mass);
body.SetGeom(convex, true, false);
world.Step(1.f);
world.Step(Nz::Time::Second());
WHEN("We ask for the aabb of the convex")
{
@ -304,7 +305,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]")
Nz::RigidBody2D body(&world, mass);
body.SetGeom(segment, true, false);
world.Step(1.f);
world.Step(Nz::Time::Second());
WHEN("We ask for the aabb of the segment")
{

View File

@ -69,6 +69,14 @@ local modules = {
add_packages("libuuid")
add_syslinks("dl", "pthread")
end
if is_plat("macosx", "iphoneos") then
add_headerfiles("src/Nazara/Core/Darwin/TimeImpl.hpp", { prefixdir = "private", install = false })
add_files("src/Nazara/Core/Darwin/TimeImpl.cpp")
remove_headerfiles("src/Nazara/Core/Posix/TimeImpl.hpp")
remove_files("src/Nazara/Core/Posix/TimeImpl.cpp")
end
end,
Packages = { "entt", "frozen" },
PublicPackages = { "nazarautils" }
@ -277,26 +285,24 @@ function ModuleTargetConfig(name, module)
end
-- Remove platform-specific files
if is_plat("windows", "mingw") then
for _, ext in ipairs(headerExts) do
remove_headerfiles("src/Nazara/" .. name .. "/Posix/**" .. ext)
end
remove_files("src/Nazara/" .. name .. "/Posix/**.cpp")
else
for _, ext in ipairs(headerExts) do
remove_headerfiles("src/Nazara/" .. name .. "/Posix/**" .. ext)
end
remove_files("src/Nazara/" .. name .. "/Win32/**.cpp")
if not is_plat("windows", "mingw") then
remove_headerfiles("src/Nazara/" .. name .. "/Win32/**")
remove_files("src/Nazara/" .. name .. "/Win32/**")
end
if not is_plat("linux") then
for _, ext in ipairs(headerExts) do
remove_headerfiles("src/Nazara/" .. name .. "/Linux/**" .. ext)
end
if not is_plat("linux", "android", "cross") then
remove_headerfiles("src/Nazara/" .. name .. "/Linux/**")
remove_files("src/Nazara/" .. name .. "/Linux/**")
end
remove_files("src/Nazara/" .. name .. "/Linux/**.cpp")
if not is_plat("macosx", "iphoneos") then
remove_headerfiles("src/Nazara/" .. name .. "/Darwin/**")
remove_files("src/Nazara/" .. name .. "/Darwin/**")
end
if not is_plat("linux", "macosx", "iphoneos", "android", "wasm", "cross") then
remove_headerfiles("src/Nazara/" .. name .. "/Posix/**")
remove_files("src/Nazara/" .. name .. "/Posix/**")
end
if module.Custom then