Merge branch 'master' into NDK-ShadowMapping
Former-commit-id: 83435ab51753299b30a102871fbcd5558d2ac4f1
This commit is contained in:
@@ -14,233 +14,236 @@
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
nzAudioFormat NzAudio::GetAudioFormat(unsigned int channelCount)
|
||||
namespace Nz
|
||||
{
|
||||
switch (channelCount)
|
||||
AudioFormat Audio::GetAudioFormat(unsigned int channelCount)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
return static_cast<nzAudioFormat>(channelCount);
|
||||
switch (channelCount)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
return static_cast<AudioFormat>(channelCount);
|
||||
|
||||
default:
|
||||
NazaraError("Invalid channel count: " + NzString::Number(channelCount));
|
||||
return nzAudioFormat_Unknown;
|
||||
default:
|
||||
NazaraError("Invalid channel count: " + String::Number(channelCount));
|
||||
return AudioFormat_Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float NzAudio::GetDopplerFactor()
|
||||
{
|
||||
return alGetFloat(AL_DOPPLER_FACTOR);
|
||||
}
|
||||
|
||||
float NzAudio::GetGlobalVolume()
|
||||
{
|
||||
ALfloat gain = 0.f;
|
||||
alGetListenerf(AL_GAIN, &gain);
|
||||
|
||||
return gain*100.f;
|
||||
}
|
||||
|
||||
NzVector3f NzAudio::GetListenerDirection()
|
||||
{
|
||||
ALfloat orientation[6];
|
||||
alGetListenerfv(AL_ORIENTATION, orientation);
|
||||
|
||||
return NzVector3f(orientation[0], orientation[1], orientation[2]);
|
||||
}
|
||||
|
||||
NzVector3f NzAudio::GetListenerPosition()
|
||||
{
|
||||
NzVector3f position;
|
||||
alGetListenerfv(AL_POSITION, position);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
NzQuaternionf NzAudio::GetListenerRotation()
|
||||
{
|
||||
ALfloat orientation[6];
|
||||
alGetListenerfv(AL_ORIENTATION, orientation);
|
||||
|
||||
NzVector3f forward(orientation[0], orientation[1], orientation[2]);
|
||||
|
||||
return NzQuaternionf::RotationBetween(NzVector3f::Forward(), forward);
|
||||
}
|
||||
|
||||
NzVector3f NzAudio::GetListenerVelocity()
|
||||
{
|
||||
NzVector3f velocity;
|
||||
alGetListenerfv(AL_VELOCITY, velocity);
|
||||
|
||||
return velocity;
|
||||
}
|
||||
|
||||
float NzAudio::GetSpeedOfSound()
|
||||
{
|
||||
return alGetFloat(AL_SPEED_OF_SOUND);
|
||||
}
|
||||
|
||||
bool NzAudio::Initialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter > 0)
|
||||
float Audio::GetDopplerFactor()
|
||||
{
|
||||
return alGetFloat(AL_DOPPLER_FACTOR);
|
||||
}
|
||||
|
||||
float Audio::GetGlobalVolume()
|
||||
{
|
||||
ALfloat gain = 0.f;
|
||||
alGetListenerf(AL_GAIN, &gain);
|
||||
|
||||
return gain*100.f;
|
||||
}
|
||||
|
||||
Vector3f Audio::GetListenerDirection()
|
||||
{
|
||||
ALfloat orientation[6];
|
||||
alGetListenerfv(AL_ORIENTATION, orientation);
|
||||
|
||||
return Vector3f(orientation[0], orientation[1], orientation[2]);
|
||||
}
|
||||
|
||||
Vector3f Audio::GetListenerPosition()
|
||||
{
|
||||
Vector3f position;
|
||||
alGetListenerfv(AL_POSITION, position);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
Quaternionf Audio::GetListenerRotation()
|
||||
{
|
||||
ALfloat orientation[6];
|
||||
alGetListenerfv(AL_ORIENTATION, orientation);
|
||||
|
||||
Vector3f forward(orientation[0], orientation[1], orientation[2]);
|
||||
|
||||
return Quaternionf::RotationBetween(Vector3f::Forward(), forward);
|
||||
}
|
||||
|
||||
Vector3f Audio::GetListenerVelocity()
|
||||
{
|
||||
Vector3f velocity;
|
||||
alGetListenerfv(AL_VELOCITY, velocity);
|
||||
|
||||
return velocity;
|
||||
}
|
||||
|
||||
float Audio::GetSpeedOfSound()
|
||||
{
|
||||
return alGetFloat(AL_SPEED_OF_SOUND);
|
||||
}
|
||||
|
||||
bool Audio::Initialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter > 0)
|
||||
{
|
||||
s_moduleReferenceCounter++;
|
||||
return true; // Déjà initialisé
|
||||
}
|
||||
|
||||
// Initialisation des dépendances
|
||||
if (!Core::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize core module");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_moduleReferenceCounter++;
|
||||
return true; // Déjà initialisé
|
||||
|
||||
// Initialisation du module
|
||||
CallOnExit onExit(Audio::Uninitialize);
|
||||
|
||||
// Initialisation d'OpenAL
|
||||
if (!OpenAL::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize OpenAL");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SoundBuffer::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize sound buffers");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Définition de l'orientation par défaut
|
||||
SetListenerDirection(Vector3f::Forward());
|
||||
|
||||
// Loaders
|
||||
Loaders::Register_sndfile();
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
NazaraNotice("Initialized: Audio module");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initialisation des dépendances
|
||||
if (!NzCore::Initialize())
|
||||
bool Audio::IsFormatSupported(AudioFormat format)
|
||||
{
|
||||
NazaraError("Failed to initialize core module");
|
||||
return false;
|
||||
if (format == AudioFormat_Unknown)
|
||||
return false;
|
||||
|
||||
return OpenAL::AudioFormat[format] != 0;
|
||||
}
|
||||
|
||||
s_moduleReferenceCounter++;
|
||||
|
||||
// Initialisation du module
|
||||
NzCallOnExit onExit(NzAudio::Uninitialize);
|
||||
|
||||
// Initialisation d'OpenAL
|
||||
if (!NzOpenAL::Initialize())
|
||||
bool Audio::IsInitialized()
|
||||
{
|
||||
NazaraError("Failed to initialize OpenAL");
|
||||
return false;
|
||||
return s_moduleReferenceCounter != 0;
|
||||
}
|
||||
|
||||
if (!NzSoundBuffer::Initialize())
|
||||
void Audio::SetDopplerFactor(float dopplerFactor)
|
||||
{
|
||||
NazaraError("Failed to initialize sound buffers");
|
||||
return false;
|
||||
alDopplerFactor(dopplerFactor);
|
||||
}
|
||||
|
||||
// Définition de l'orientation par défaut
|
||||
SetListenerDirection(NzVector3f::Forward());
|
||||
|
||||
// Loaders
|
||||
NzLoaders_sndfile_Register();
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
NazaraNotice("Initialized: Audio module");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzAudio::IsFormatSupported(nzAudioFormat format)
|
||||
{
|
||||
if (format == nzAudioFormat_Unknown)
|
||||
return false;
|
||||
|
||||
return NzOpenAL::AudioFormat[format] != 0;
|
||||
}
|
||||
|
||||
bool NzAudio::IsInitialized()
|
||||
{
|
||||
return s_moduleReferenceCounter != 0;
|
||||
}
|
||||
|
||||
void NzAudio::SetDopplerFactor(float dopplerFactor)
|
||||
{
|
||||
alDopplerFactor(dopplerFactor);
|
||||
}
|
||||
|
||||
void NzAudio::SetGlobalVolume(float volume)
|
||||
{
|
||||
alListenerf(AL_GAIN, volume*0.01f);
|
||||
}
|
||||
|
||||
void NzAudio::SetListenerDirection(const NzVector3f& direction)
|
||||
{
|
||||
NzVector3f up = NzVector3f::Up();
|
||||
|
||||
ALfloat orientation[6] =
|
||||
void Audio::SetGlobalVolume(float volume)
|
||||
{
|
||||
direction.x, direction.y, direction.z,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
void NzAudio::SetListenerDirection(float dirX, float dirY, float dirZ)
|
||||
{
|
||||
NzVector3f up = NzVector3f::Up();
|
||||
|
||||
ALfloat orientation[6] =
|
||||
{
|
||||
dirX, dirY, dirZ,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
void NzAudio::SetListenerPosition(const NzVector3f& position)
|
||||
{
|
||||
alListenerfv(AL_POSITION, position);
|
||||
}
|
||||
|
||||
void NzAudio::SetListenerPosition(float x, float y, float z)
|
||||
{
|
||||
alListener3f(AL_POSITION, x, y, z);
|
||||
}
|
||||
|
||||
void NzAudio::SetListenerRotation(const NzQuaternionf& rotation)
|
||||
{
|
||||
NzVector3f forward = rotation * NzVector3f::Forward();
|
||||
NzVector3f up = NzVector3f::Up();
|
||||
|
||||
ALfloat orientation[6] =
|
||||
{
|
||||
forward.x, forward.y, forward.z,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
void NzAudio::SetListenerVelocity(const NzVector3f& velocity)
|
||||
{
|
||||
alListenerfv(AL_VELOCITY, velocity);
|
||||
}
|
||||
|
||||
void NzAudio::SetListenerVelocity(float velX, float velY, float velZ)
|
||||
{
|
||||
alListener3f(AL_VELOCITY, velX, velY, velZ);
|
||||
}
|
||||
|
||||
void NzAudio::SetSpeedOfSound(float speed)
|
||||
{
|
||||
alSpeedOfSound(speed);
|
||||
}
|
||||
|
||||
void NzAudio::Uninitialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter != 1)
|
||||
{
|
||||
// Le module est soit encore utilisé, soit pas initialisé
|
||||
if (s_moduleReferenceCounter > 1)
|
||||
s_moduleReferenceCounter--;
|
||||
|
||||
return;
|
||||
alListenerf(AL_GAIN, volume*0.01f);
|
||||
}
|
||||
|
||||
// Libération du module
|
||||
s_moduleReferenceCounter = 0;
|
||||
void Audio::SetListenerDirection(const Vector3f& direction)
|
||||
{
|
||||
Vector3f up = Vector3f::Up();
|
||||
|
||||
// Loaders
|
||||
NzLoaders_sndfile_Unregister();
|
||||
ALfloat orientation[6] =
|
||||
{
|
||||
direction.x, direction.y, direction.z,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
NzSoundBuffer::Uninitialize();
|
||||
NzOpenAL::Uninitialize();
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
NazaraNotice("Uninitialized: Audio module");
|
||||
void Audio::SetListenerDirection(float dirX, float dirY, float dirZ)
|
||||
{
|
||||
Vector3f up = Vector3f::Up();
|
||||
|
||||
// Libération des dépendances
|
||||
NzCore::Uninitialize();
|
||||
ALfloat orientation[6] =
|
||||
{
|
||||
dirX, dirY, dirZ,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
void Audio::SetListenerPosition(const Vector3f& position)
|
||||
{
|
||||
alListenerfv(AL_POSITION, position);
|
||||
}
|
||||
|
||||
void Audio::SetListenerPosition(float x, float y, float z)
|
||||
{
|
||||
alListener3f(AL_POSITION, x, y, z);
|
||||
}
|
||||
|
||||
void Audio::SetListenerRotation(const Quaternionf& rotation)
|
||||
{
|
||||
Vector3f forward = rotation * Vector3f::Forward();
|
||||
Vector3f up = Vector3f::Up();
|
||||
|
||||
ALfloat orientation[6] =
|
||||
{
|
||||
forward.x, forward.y, forward.z,
|
||||
up.x, up.y, up.z
|
||||
};
|
||||
|
||||
alListenerfv(AL_ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
void Audio::SetListenerVelocity(const Vector3f& velocity)
|
||||
{
|
||||
alListenerfv(AL_VELOCITY, velocity);
|
||||
}
|
||||
|
||||
void Audio::SetListenerVelocity(float velX, float velY, float velZ)
|
||||
{
|
||||
alListener3f(AL_VELOCITY, velX, velY, velZ);
|
||||
}
|
||||
|
||||
void Audio::SetSpeedOfSound(float speed)
|
||||
{
|
||||
alSpeedOfSound(speed);
|
||||
}
|
||||
|
||||
void Audio::Uninitialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter != 1)
|
||||
{
|
||||
// Le module est soit encore utilisé, soit pas initialisé
|
||||
if (s_moduleReferenceCounter > 1)
|
||||
s_moduleReferenceCounter--;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Libération du module
|
||||
s_moduleReferenceCounter = 0;
|
||||
|
||||
// Loaders
|
||||
Loaders::Unregister_sndfile();
|
||||
|
||||
SoundBuffer::Uninitialize();
|
||||
OpenAL::Uninitialize();
|
||||
|
||||
NazaraNotice("Uninitialized: Audio module");
|
||||
|
||||
// Libération des dépendances
|
||||
Core::Uninitialize();
|
||||
}
|
||||
|
||||
unsigned int Audio::s_moduleReferenceCounter = 0;
|
||||
}
|
||||
|
||||
unsigned int NzAudio::s_moduleReferenceCounter = 0;
|
||||
|
||||
@@ -10,22 +10,22 @@
|
||||
|
||||
void* operator new(std::size_t size)
|
||||
{
|
||||
return NzMemoryManager::Allocate(size, false);
|
||||
return Nz::MemoryManager::Allocate(size, false);
|
||||
}
|
||||
|
||||
void* operator new[](std::size_t size)
|
||||
{
|
||||
return NzMemoryManager::Allocate(size, true);
|
||||
return Nz::MemoryManager::Allocate(size, true);
|
||||
}
|
||||
|
||||
void operator delete(void* pointer) noexcept
|
||||
{
|
||||
NzMemoryManager::Free(pointer, false);
|
||||
Nz::MemoryManager::Free(pointer, false);
|
||||
}
|
||||
|
||||
void operator delete[](void* pointer) noexcept
|
||||
{
|
||||
NzMemoryManager::Free(pointer, true);
|
||||
Nz::MemoryManager::Free(pointer, true);
|
||||
}
|
||||
|
||||
#endif // NAZARA_AUDIO_MANAGE_MEMORY
|
||||
|
||||
@@ -13,381 +13,387 @@
|
||||
#include <Nazara/Core/Endianness.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Core/InputStream.hpp>
|
||||
#include <Nazara/Core/MemoryStream.hpp>
|
||||
#include <Nazara/Core/MemoryView.hpp>
|
||||
#include <Nazara/Core/Stream.hpp>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <sndfile/sndfile.h>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace
|
||||
namespace Nz
|
||||
{
|
||||
sf_count_t GetSize(void* user_data)
|
||||
namespace Detail
|
||||
{
|
||||
NzInputStream* stream = static_cast<NzInputStream*>(user_data);
|
||||
return stream->GetSize();
|
||||
}
|
||||
sf_count_t GetSize(void* user_data)
|
||||
{
|
||||
Stream* stream = static_cast<Stream*>(user_data);
|
||||
return stream->GetSize();
|
||||
}
|
||||
|
||||
sf_count_t Read(void* ptr, sf_count_t count, void* user_data)
|
||||
{
|
||||
NzInputStream* stream = static_cast<NzInputStream*>(user_data);
|
||||
return static_cast<sf_count_t>(stream->Read(ptr, static_cast<std::size_t>(count)));
|
||||
}
|
||||
sf_count_t Read(void* ptr, sf_count_t count, void* user_data)
|
||||
{
|
||||
Stream* stream = static_cast<Stream*>(user_data);
|
||||
return static_cast<sf_count_t>(stream->Read(ptr, static_cast<std::size_t>(count)));
|
||||
}
|
||||
|
||||
sf_count_t Seek(sf_count_t offset, int whence, void* user_data)
|
||||
{
|
||||
NzInputStream* stream = static_cast<NzInputStream*>(user_data);
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_CUR:
|
||||
stream->Read(nullptr, static_cast<std::size_t>(offset));
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
stream->SetCursorPos(stream->GetSize() + offset); // L'offset est négatif ici
|
||||
break;
|
||||
|
||||
case SEEK_SET:
|
||||
stream->SetCursorPos(offset);
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Seek mode not handled");
|
||||
}
|
||||
|
||||
return stream->GetCursorPos();
|
||||
}
|
||||
|
||||
sf_count_t Tell(void* user_data)
|
||||
{
|
||||
NzInputStream* stream = static_cast<NzInputStream*>(user_data);
|
||||
return stream->GetCursorPos();
|
||||
}
|
||||
|
||||
static SF_VIRTUAL_IO callbacks = {GetSize, Seek, Read, nullptr, Tell};
|
||||
|
||||
class sndfileStream : public NzSoundStream
|
||||
{
|
||||
public:
|
||||
sndfileStream() :
|
||||
m_handle(nullptr)
|
||||
sf_count_t Seek(sf_count_t offset, int whence, void* user_data)
|
||||
{
|
||||
Stream* stream = static_cast<Stream*>(user_data);
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_CUR:
|
||||
stream->Read(nullptr, static_cast<std::size_t>(offset));
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
stream->SetCursorPos(stream->GetSize() + offset); // L'offset est négatif ici
|
||||
break;
|
||||
|
||||
case SEEK_SET:
|
||||
stream->SetCursorPos(offset);
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Seek mode not handled");
|
||||
}
|
||||
|
||||
~sndfileStream()
|
||||
{
|
||||
if (m_handle)
|
||||
sf_close(m_handle);
|
||||
}
|
||||
return stream->GetCursorPos();
|
||||
}
|
||||
|
||||
nzUInt32 GetDuration() const override
|
||||
{
|
||||
return m_duration;
|
||||
}
|
||||
sf_count_t Tell(void* user_data)
|
||||
{
|
||||
Stream* stream = static_cast<Stream*>(user_data);
|
||||
return stream->GetCursorPos();
|
||||
}
|
||||
|
||||
nzAudioFormat GetFormat() const override
|
||||
{
|
||||
// Nous avons besoin du nombre de canaux d'origine pour convertir en mono, nous trichons donc un peu...
|
||||
if (m_mixToMono)
|
||||
return nzAudioFormat_Mono;
|
||||
else
|
||||
return m_format;
|
||||
}
|
||||
static SF_VIRTUAL_IO callbacks = {GetSize, Seek, Read, nullptr, Tell};
|
||||
|
||||
nzUInt64 GetSampleCount() const override
|
||||
{
|
||||
return m_sampleCount;
|
||||
}
|
||||
|
||||
nzUInt32 GetSampleRate() const override
|
||||
{
|
||||
return m_sampleRate;
|
||||
}
|
||||
|
||||
bool Open(const NzString& filePath, bool forceMono)
|
||||
{
|
||||
// Nous devons gérer nous-même le flux car il doit rester ouvert après le passage du loader
|
||||
// (les flux automatiquement ouverts par le ResourceLoader étant fermés après celui-ci)
|
||||
std::unique_ptr<NzFile> file(new NzFile);
|
||||
if (!file->Open(filePath, nzOpenMode_ReadOnly))
|
||||
class sndfileStream : public SoundStream
|
||||
{
|
||||
public:
|
||||
sndfileStream() :
|
||||
m_handle(nullptr)
|
||||
{
|
||||
NazaraError("Failed to open stream from file: " + NzError::GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ownedStream = std::move(file);
|
||||
return Open(*m_ownedStream, forceMono);
|
||||
}
|
||||
|
||||
bool Open(const void* data, std::size_t size, bool forceMono)
|
||||
{
|
||||
m_ownedStream.reset(new NzMemoryStream(data, size));
|
||||
return Open(*m_ownedStream, forceMono);
|
||||
}
|
||||
|
||||
bool Open(NzInputStream& stream, bool forceMono)
|
||||
{
|
||||
SF_INFO infos;
|
||||
infos.format = 0; // Format inconnu
|
||||
|
||||
m_handle = sf_open_virtual(&callbacks, SFM_READ, &infos, &stream);
|
||||
if (!m_handle)
|
||||
~sndfileStream()
|
||||
{
|
||||
NazaraError("Failed to open sound: " + NzString(sf_strerror(m_handle)));
|
||||
return false;
|
||||
if (m_handle)
|
||||
sf_close(m_handle);
|
||||
}
|
||||
|
||||
// Un peu de RRID
|
||||
NzCallOnExit onExit([this]
|
||||
UInt32 GetDuration() const override
|
||||
{
|
||||
sf_close(m_handle);
|
||||
m_handle = nullptr;
|
||||
});
|
||||
|
||||
m_format = NzAudio::GetAudioFormat(infos.channels);
|
||||
if (m_format == nzAudioFormat_Unknown)
|
||||
{
|
||||
NazaraError("Channel count not handled");
|
||||
return false;
|
||||
return m_duration;
|
||||
}
|
||||
|
||||
m_sampleCount = infos.channels*infos.frames;
|
||||
m_sampleRate = infos.samplerate;
|
||||
|
||||
// Durée de la musique (s) = samples / channels*rate
|
||||
m_duration = static_cast<nzUInt32>(1000*m_sampleCount / (m_format*m_sampleRate));
|
||||
|
||||
// https://github.com/LaurentGomila/SFML/issues/271
|
||||
// http://www.mega-nerd.com/libsndfile/command.html#SFC_SET_SCALE_FLOAT_INT_READ
|
||||
///FIXME: Seulement le Vorbis ?
|
||||
if (infos.format & SF_FORMAT_VORBIS)
|
||||
sf_command(m_handle, SFC_SET_SCALE_FLOAT_INT_READ, nullptr, SF_TRUE);
|
||||
|
||||
// On mixera en mono lors de la lecture
|
||||
if (forceMono && m_format != nzAudioFormat_Mono)
|
||||
AudioFormat GetFormat() const override
|
||||
{
|
||||
m_mixToMono = true;
|
||||
m_sampleCount = infos.frames;
|
||||
// Nous avons besoin du nombre de canaux d'origine pour convertir en mono, nous trichons donc un peu...
|
||||
if (m_mixToMono)
|
||||
return AudioFormat_Mono;
|
||||
else
|
||||
return m_format;
|
||||
}
|
||||
else
|
||||
m_mixToMono = false;
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int Read(void* buffer, unsigned int sampleCount)
|
||||
{
|
||||
// Si la musique a été demandée en mono, nous devons la convertir à la volée lors de la lecture
|
||||
if (m_mixToMono)
|
||||
UInt32 GetSampleCount() const override
|
||||
{
|
||||
// On garde un buffer sur le côté pour éviter la réallocation
|
||||
m_mixBuffer.resize(m_format * sampleCount);
|
||||
sf_count_t readSampleCount = sf_read_short(m_handle, m_mixBuffer.data(), m_format * sampleCount);
|
||||
NzMixToMono(m_mixBuffer.data(), static_cast<nzInt16*>(buffer), m_format, sampleCount);
|
||||
|
||||
return static_cast<unsigned int>(readSampleCount / m_format);
|
||||
return m_sampleCount;
|
||||
}
|
||||
else
|
||||
return static_cast<unsigned int>(sf_read_short(m_handle, static_cast<nzInt16*>(buffer), sampleCount));
|
||||
}
|
||||
|
||||
void Seek(nzUInt32 offset) override
|
||||
{
|
||||
sf_seek(m_handle, offset*m_sampleRate / 1000, SEEK_SET);
|
||||
}
|
||||
UInt32 GetSampleRate() const override
|
||||
{
|
||||
return m_sampleRate;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<nzInt16> m_mixBuffer;
|
||||
std::unique_ptr<NzInputStream> m_ownedStream;
|
||||
nzAudioFormat m_format;
|
||||
SNDFILE* m_handle;
|
||||
bool m_mixToMono;
|
||||
nzUInt32 m_duration;
|
||||
nzUInt64 m_sampleCount;
|
||||
nzUInt32 m_sampleRate;
|
||||
};
|
||||
bool Open(const String& filePath, bool forceMono)
|
||||
{
|
||||
// Nous devons gérer nous-même le flux car il doit rester ouvert après le passage du loader
|
||||
// (les flux automatiquement ouverts par le ResourceLoader étant fermés après celui-ci)
|
||||
std::unique_ptr<File> file(new File);
|
||||
if (!file->Open(filePath, OpenMode_ReadOnly))
|
||||
{
|
||||
NazaraError("Failed to open stream from file: " + Error::GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsSupported(const NzString& extension)
|
||||
{
|
||||
static std::set<NzString> supportedExtensions = {
|
||||
"aiff", "au", "avr", "caf", "flac", "htk", "ircam", "mat4", "mat5", "mpc2k",
|
||||
"nist","ogg", "pvf", "raw", "rf64", "sd2", "sds", "svx", "voc", "w64", "wav", "wve"
|
||||
m_ownedStream = std::move(file);
|
||||
return Open(*m_ownedStream, forceMono);
|
||||
}
|
||||
|
||||
bool Open(const void* data, std::size_t size, bool forceMono)
|
||||
{
|
||||
m_ownedStream.reset(new MemoryView(data, size));
|
||||
return Open(*m_ownedStream, forceMono);
|
||||
}
|
||||
|
||||
bool Open(Stream& stream, bool forceMono)
|
||||
{
|
||||
SF_INFO infos;
|
||||
infos.format = 0; // Format inconnu
|
||||
|
||||
m_handle = sf_open_virtual(&callbacks, SFM_READ, &infos, &stream);
|
||||
if (!m_handle)
|
||||
{
|
||||
NazaraError("Failed to open sound: " + String(sf_strerror(m_handle)));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Un peu de RRID
|
||||
CallOnExit onExit([this]
|
||||
{
|
||||
sf_close(m_handle);
|
||||
m_handle = nullptr;
|
||||
});
|
||||
|
||||
m_format = Audio::GetAudioFormat(infos.channels);
|
||||
if (m_format == AudioFormat_Unknown)
|
||||
{
|
||||
NazaraError("Channel count not handled");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sampleCount = static_cast<UInt32>(infos.channels*infos.frames);
|
||||
m_sampleRate = infos.samplerate;
|
||||
|
||||
// Durée de la musique (s) = samples / channels*rate
|
||||
m_duration = static_cast<UInt32>(1000ULL*m_sampleCount / (m_format*m_sampleRate));
|
||||
|
||||
// https://github.com/LaurentGomila/SFML/issues/271
|
||||
// http://www.mega-nerd.com/libsndfile/command.html#SFC_SET_SCALE_FLOAT_INT_READ
|
||||
///FIXME: Seulement le Vorbis ?
|
||||
if (infos.format & SF_FORMAT_VORBIS)
|
||||
sf_command(m_handle, SFC_SET_SCALE_FLOAT_INT_READ, nullptr, SF_TRUE);
|
||||
|
||||
// On mixera en mono lors de la lecture
|
||||
if (forceMono && m_format != AudioFormat_Mono)
|
||||
{
|
||||
m_mixToMono = true;
|
||||
m_sampleCount = static_cast<UInt32>(infos.frames);
|
||||
}
|
||||
else
|
||||
m_mixToMono = false;
|
||||
|
||||
onExit.Reset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int Read(void* buffer, unsigned int sampleCount)
|
||||
{
|
||||
// Si la musique a été demandée en mono, nous devons la convertir à la volée lors de la lecture
|
||||
if (m_mixToMono)
|
||||
{
|
||||
// On garde un buffer sur le côté pour éviter la réallocation
|
||||
m_mixBuffer.resize(m_format * sampleCount);
|
||||
sf_count_t readSampleCount = sf_read_short(m_handle, m_mixBuffer.data(), m_format * sampleCount);
|
||||
MixToMono(m_mixBuffer.data(), static_cast<Int16*>(buffer), m_format, sampleCount);
|
||||
|
||||
return static_cast<unsigned int>(readSampleCount / m_format);
|
||||
}
|
||||
else
|
||||
return static_cast<unsigned int>(sf_read_short(m_handle, static_cast<Int16*>(buffer), sampleCount));
|
||||
}
|
||||
|
||||
void Seek(UInt32 offset) override
|
||||
{
|
||||
sf_seek(m_handle, offset*m_sampleRate / 1000, SEEK_SET);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Int16> m_mixBuffer;
|
||||
std::unique_ptr<Stream> m_ownedStream;
|
||||
AudioFormat m_format;
|
||||
SNDFILE* m_handle;
|
||||
bool m_mixToMono;
|
||||
UInt32 m_duration;
|
||||
unsigned int m_sampleCount;
|
||||
unsigned int m_sampleRate;
|
||||
};
|
||||
|
||||
return supportedExtensions.find(extension) != supportedExtensions.end();
|
||||
bool IsSupported(const String& extension)
|
||||
{
|
||||
static std::set<String> supportedExtensions = {
|
||||
"aiff", "au", "avr", "caf", "flac", "htk", "ircam", "mat4", "mat5", "mpc2k",
|
||||
"nist","ogg", "pvf", "raw", "rf64", "sd2", "sds", "svx", "voc", "w64", "wav", "wve"
|
||||
};
|
||||
|
||||
return supportedExtensions.find(extension) != supportedExtensions.end();
|
||||
}
|
||||
|
||||
Ternary CheckMusic(Stream& stream, const MusicParams& parameters)
|
||||
{
|
||||
NazaraUnused(parameters);
|
||||
|
||||
SF_INFO info;
|
||||
info.format = 0; // Format inconnu
|
||||
|
||||
// Si on peut ouvrir le flux, c'est qu'il est dans un format compatible
|
||||
SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream);
|
||||
if (file)
|
||||
{
|
||||
sf_close(file);
|
||||
return Ternary_True;
|
||||
}
|
||||
else
|
||||
return Ternary_False;
|
||||
}
|
||||
|
||||
bool LoadMusicFile(Music* music, const String& filePath, const MusicParams& parameters)
|
||||
{
|
||||
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
|
||||
if (!musicStream->Open(filePath, parameters.forceMono))
|
||||
{
|
||||
NazaraError("Failed to open music stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!music->Create(musicStream.get())) // Transfert de propriété
|
||||
{
|
||||
NazaraError("Failed to create music");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
|
||||
musicStream.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadMusicMemory(Music* music, const void* data, std::size_t size, const MusicParams& parameters)
|
||||
{
|
||||
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
|
||||
if (!musicStream->Open(data, size, parameters.forceMono))
|
||||
{
|
||||
NazaraError("Failed to open music stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!music->Create(musicStream.get())) // Transfert de propriété
|
||||
{
|
||||
NazaraError("Failed to create music");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
|
||||
musicStream.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadMusicStream(Music* music, Stream& stream, const MusicParams& parameters)
|
||||
{
|
||||
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
|
||||
if (!musicStream->Open(stream, parameters.forceMono))
|
||||
{
|
||||
NazaraError("Failed to open music stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!music->Create(musicStream.get())) // Transfert de propriété
|
||||
{
|
||||
NazaraError("Failed to create music");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
|
||||
musicStream.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Ternary CheckSoundBuffer(Stream& stream, const SoundBufferParams& parameters)
|
||||
{
|
||||
NazaraUnused(parameters);
|
||||
|
||||
SF_INFO info;
|
||||
info.format = 0;
|
||||
|
||||
SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream);
|
||||
if (file)
|
||||
{
|
||||
sf_close(file);
|
||||
return Ternary_True;
|
||||
}
|
||||
else
|
||||
return Ternary_False;
|
||||
}
|
||||
|
||||
bool LoadSoundBuffer(SoundBuffer* soundBuffer, Stream& stream, const SoundBufferParams& parameters)
|
||||
{
|
||||
SF_INFO info;
|
||||
info.format = 0;
|
||||
|
||||
SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream);
|
||||
if (!file)
|
||||
{
|
||||
NazaraError("Failed to load sound file: " + String(sf_strerror(file)));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lynix utilise RAII...
|
||||
// C'est très efficace !
|
||||
// MemoryLeak est confus...
|
||||
CallOnExit onExit([file]
|
||||
{
|
||||
sf_close(file);
|
||||
});
|
||||
|
||||
AudioFormat format = Audio::GetAudioFormat(info.channels);
|
||||
if (format == AudioFormat_Unknown)
|
||||
{
|
||||
NazaraError("Channel count not handled");
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://github.com/LaurentGomila/SFML/issues/271
|
||||
// http://www.mega-nerd.com/libsndfile/command.html#SFC_SET_SCALE_FLOAT_INT_READ
|
||||
///FIXME: Seulement le Vorbis ?
|
||||
if (info.format & SF_FORMAT_VORBIS)
|
||||
sf_command(file, SFC_SET_SCALE_FLOAT_INT_READ, nullptr, SF_TRUE);
|
||||
|
||||
unsigned int sampleCount = static_cast<unsigned int>(info.frames * info.channels);
|
||||
std::unique_ptr<Int16[]> samples(new Int16[sampleCount]);
|
||||
|
||||
if (sf_read_short(file, samples.get(), sampleCount) != sampleCount)
|
||||
{
|
||||
NazaraError("Failed to read samples");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Une conversion en mono est-elle nécessaire ?
|
||||
if (parameters.forceMono && format != AudioFormat_Mono)
|
||||
{
|
||||
// Nous effectuons la conversion en mono dans le même buffer (il va de toute façon être copié)
|
||||
MixToMono(samples.get(), samples.get(), static_cast<unsigned int>(info.channels), static_cast<unsigned int>(info.frames));
|
||||
|
||||
format = AudioFormat_Mono;
|
||||
sampleCount = static_cast<unsigned int>(info.frames);
|
||||
}
|
||||
|
||||
if (!soundBuffer->Create(format, sampleCount, info.samplerate, samples.get()))
|
||||
{
|
||||
NazaraError("Failed to create sound buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
nzTernary CheckMusic(NzInputStream& stream, const NzMusicParams& parameters)
|
||||
namespace Loaders
|
||||
{
|
||||
NazaraUnused(parameters);
|
||||
|
||||
SF_INFO info;
|
||||
info.format = 0; // Format inconnu
|
||||
|
||||
// Si on peut ouvrir le flux, c'est qu'il est dans un format compatible
|
||||
SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream);
|
||||
if (file)
|
||||
void Register_sndfile()
|
||||
{
|
||||
sf_close(file);
|
||||
return nzTernary_True;
|
||||
}
|
||||
else
|
||||
return nzTernary_False;
|
||||
}
|
||||
|
||||
bool LoadMusicFile(NzMusic* music, const NzString& filePath, const NzMusicParams& parameters)
|
||||
{
|
||||
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
|
||||
if (!musicStream->Open(filePath, parameters.forceMono))
|
||||
{
|
||||
NazaraError("Failed to open music stream");
|
||||
return false;
|
||||
MusicLoader::RegisterLoader(Detail::IsSupported, Detail::CheckMusic, Detail::LoadMusicStream, Detail::LoadMusicFile, Detail::LoadMusicMemory);
|
||||
SoundBufferLoader::RegisterLoader(Detail::IsSupported, Detail::CheckSoundBuffer, Detail::LoadSoundBuffer);
|
||||
}
|
||||
|
||||
if (!music->Create(musicStream.get())) // Transfert de propriété
|
||||
void Unregister_sndfile()
|
||||
{
|
||||
NazaraError("Failed to create music");
|
||||
return false;
|
||||
MusicLoader::UnregisterLoader(Detail::IsSupported, Detail::CheckMusic, Detail::LoadMusicStream, Detail::LoadMusicFile, Detail::LoadMusicMemory);
|
||||
SoundBufferLoader::UnregisterLoader(Detail::IsSupported, Detail::CheckSoundBuffer, Detail::LoadSoundBuffer);
|
||||
}
|
||||
|
||||
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
|
||||
musicStream.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadMusicMemory(NzMusic* music, const void* data, std::size_t size, const NzMusicParams& parameters)
|
||||
{
|
||||
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
|
||||
if (!musicStream->Open(data, size, parameters.forceMono))
|
||||
{
|
||||
NazaraError("Failed to open music stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!music->Create(musicStream.get())) // Transfert de propriété
|
||||
{
|
||||
NazaraError("Failed to create music");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
|
||||
musicStream.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadMusicStream(NzMusic* music, NzInputStream& stream, const NzMusicParams& parameters)
|
||||
{
|
||||
std::unique_ptr<sndfileStream> musicStream(new sndfileStream);
|
||||
if (!musicStream->Open(stream, parameters.forceMono))
|
||||
{
|
||||
NazaraError("Failed to open music stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!music->Create(musicStream.get())) // Transfert de propriété
|
||||
{
|
||||
NazaraError("Failed to create music");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Le pointeur a été transféré avec succès, nous pouvons laisser tomber la propriété
|
||||
musicStream.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
nzTernary CheckSoundBuffer(NzInputStream& stream, const NzSoundBufferParams& parameters)
|
||||
{
|
||||
NazaraUnused(parameters);
|
||||
|
||||
SF_INFO info;
|
||||
info.format = 0;
|
||||
|
||||
SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream);
|
||||
if (file)
|
||||
{
|
||||
sf_close(file);
|
||||
return nzTernary_True;
|
||||
}
|
||||
else
|
||||
return nzTernary_False;
|
||||
}
|
||||
|
||||
bool LoadSoundBuffer(NzSoundBuffer* soundBuffer, NzInputStream& stream, const NzSoundBufferParams& parameters)
|
||||
{
|
||||
SF_INFO info;
|
||||
info.format = 0;
|
||||
|
||||
SNDFILE* file = sf_open_virtual(&callbacks, SFM_READ, &info, &stream);
|
||||
if (!file)
|
||||
{
|
||||
NazaraError("Failed to load sound file: " + NzString(sf_strerror(file)));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Lynix utilise RAII...
|
||||
// C'est très efficace !
|
||||
// MemoryLeak est confus...
|
||||
NzCallOnExit onExit([file]
|
||||
{
|
||||
sf_close(file);
|
||||
});
|
||||
|
||||
nzAudioFormat format = NzAudio::GetAudioFormat(info.channels);
|
||||
if (format == nzAudioFormat_Unknown)
|
||||
{
|
||||
NazaraError("Channel count not handled");
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://github.com/LaurentGomila/SFML/issues/271
|
||||
// http://www.mega-nerd.com/libsndfile/command.html#SFC_SET_SCALE_FLOAT_INT_READ
|
||||
///FIXME: Seulement le Vorbis ?
|
||||
if (info.format & SF_FORMAT_VORBIS)
|
||||
sf_command(file, SFC_SET_SCALE_FLOAT_INT_READ, nullptr, SF_TRUE);
|
||||
|
||||
unsigned int sampleCount = static_cast<unsigned int>(info.frames * info.channels);
|
||||
std::unique_ptr<nzInt16[]> samples(new nzInt16[sampleCount]);
|
||||
|
||||
if (sf_read_short(file, samples.get(), sampleCount) != sampleCount)
|
||||
{
|
||||
NazaraError("Failed to read samples");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Une conversion en mono est-elle nécessaire ?
|
||||
if (parameters.forceMono && format != nzAudioFormat_Mono)
|
||||
{
|
||||
// Nous effectuons la conversion en mono dans le même buffer (il va de toute façon être copié)
|
||||
NzMixToMono(samples.get(), samples.get(), static_cast<unsigned int>(info.channels), static_cast<unsigned int>(info.frames));
|
||||
|
||||
format = nzAudioFormat_Mono;
|
||||
sampleCount = static_cast<unsigned int>(info.frames);
|
||||
}
|
||||
|
||||
if (!soundBuffer->Create(format, sampleCount, info.samplerate, samples.get()))
|
||||
{
|
||||
NazaraError("Failed to create sound buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void NzLoaders_sndfile_Register()
|
||||
{
|
||||
NzMusicLoader::RegisterLoader(IsSupported, CheckMusic, LoadMusicStream, LoadMusicFile, LoadMusicMemory);
|
||||
NzSoundBufferLoader::RegisterLoader(IsSupported, CheckSoundBuffer, LoadSoundBuffer);
|
||||
}
|
||||
|
||||
void NzLoaders_sndfile_Unregister()
|
||||
{
|
||||
NzMusicLoader::UnregisterLoader(IsSupported, CheckMusic, LoadMusicStream, LoadMusicFile, LoadMusicMemory);
|
||||
NzSoundBufferLoader::UnregisterLoader(IsSupported, CheckSoundBuffer, LoadSoundBuffer);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,13 @@
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
|
||||
void NzLoaders_sndfile_Register();
|
||||
void NzLoaders_sndfile_Unregister();
|
||||
namespace Nz
|
||||
{
|
||||
namespace Loaders
|
||||
{
|
||||
void Register_sndfile();
|
||||
void Unregister_sndfile();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NAZARA_LOADERS_SNDFILE_HPP
|
||||
|
||||
@@ -11,302 +11,331 @@
|
||||
#include <vector>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
bool NzMusicParams::IsValid() const
|
||||
namespace Nz
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NzMusicImpl
|
||||
{
|
||||
ALenum audioFormat;
|
||||
std::unique_ptr<NzSoundStream> stream;
|
||||
std::vector<nzInt16> chunkSamples;
|
||||
NzThread thread;
|
||||
bool loop = false;
|
||||
bool streaming = false;
|
||||
unsigned int sampleRate;
|
||||
};
|
||||
|
||||
NzMusic::~NzMusic()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzMusic::Create(NzSoundStream* soundStream)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!soundStream)
|
||||
bool MusicParams::IsValid() const
|
||||
{
|
||||
NazaraError("Sound stream must be valid");
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
nzAudioFormat format = soundStream->GetFormat();
|
||||
|
||||
m_impl = new NzMusicImpl;
|
||||
m_impl->sampleRate = soundStream->GetSampleRate();
|
||||
m_impl->audioFormat = NzOpenAL::AudioFormat[format];
|
||||
m_impl->chunkSamples.resize(format * m_impl->sampleRate); // Une seconde de samples
|
||||
m_impl->stream.reset(soundStream);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzMusic::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
struct MusicImpl
|
||||
{
|
||||
Stop();
|
||||
ALenum audioFormat;
|
||||
std::unique_ptr<SoundStream> stream;
|
||||
std::vector<Int16> chunkSamples;
|
||||
Thread thread;
|
||||
bool loop = false;
|
||||
bool streaming = false;
|
||||
unsigned int sampleRate;
|
||||
};
|
||||
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
Music::~Music()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void NzMusic::EnableLooping(bool loop)
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
bool Music::Create(SoundStream* soundStream)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!soundStream)
|
||||
{
|
||||
NazaraError("Sound stream must be valid");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
AudioFormat format = soundStream->GetFormat();
|
||||
|
||||
m_impl = new MusicImpl;
|
||||
m_impl->sampleRate = soundStream->GetSampleRate();
|
||||
m_impl->audioFormat = OpenAL::AudioFormat[format];
|
||||
m_impl->chunkSamples.resize(format * m_impl->sampleRate); // Une seconde de samples
|
||||
m_impl->stream.reset(soundStream);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->loop = loop;
|
||||
}
|
||||
|
||||
nzUInt32 NzMusic::GetDuration() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
void Music::Destroy()
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
if (m_impl)
|
||||
{
|
||||
Stop();
|
||||
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Music::EnableLooping(bool loop)
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->loop = loop;
|
||||
}
|
||||
|
||||
UInt32 Music::GetDuration() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->stream->GetDuration();
|
||||
}
|
||||
|
||||
AudioFormat Music::GetFormat() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return AudioFormat_Unknown;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->stream->GetFormat();
|
||||
}
|
||||
|
||||
UInt32 Music::GetPlayingOffset() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
///TODO
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->stream->GetDuration();
|
||||
}
|
||||
|
||||
nzAudioFormat NzMusic::GetFormat() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
UInt32 Music::GetSampleCount() const
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return nzAudioFormat_Unknown;
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->stream->GetSampleCount();
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->stream->GetFormat();
|
||||
}
|
||||
|
||||
nzUInt32 NzMusic::GetPlayingOffset() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
UInt32 Music::GetSampleRate() const
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return 0;
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->stream->GetSampleRate();
|
||||
}
|
||||
#endif
|
||||
|
||||
///TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
nzSoundStatus NzMusic::GetStatus() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
SoundStatus Music::GetStatus() const
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return nzSoundStatus_Stopped;
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return SoundStatus_Stopped;
|
||||
}
|
||||
#endif
|
||||
|
||||
SoundStatus status = GetInternalStatus();
|
||||
|
||||
// Pour compenser les éventuels retards (ou le laps de temps entre Play() et la mise en route du thread)
|
||||
if (m_impl->streaming && status == SoundStatus_Stopped)
|
||||
status = SoundStatus_Playing;
|
||||
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
nzSoundStatus status = GetInternalStatus();
|
||||
|
||||
// Pour compenser les éventuels retards (ou le laps de temps entre Play() et la mise en route du thread)
|
||||
if (m_impl->streaming && status == nzSoundStatus_Stopped)
|
||||
status = nzSoundStatus_Playing;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool NzMusic::IsLooping() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
bool Music::IsLooping() const
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return false;
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->loop;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->loop;
|
||||
}
|
||||
|
||||
bool NzMusic::OpenFromFile(const NzString& filePath, const NzMusicParams& params)
|
||||
{
|
||||
return NzMusicLoader::LoadFromFile(this, filePath, params);
|
||||
}
|
||||
|
||||
bool NzMusic::OpenFromMemory(const void* data, std::size_t size, const NzMusicParams& params)
|
||||
{
|
||||
return NzMusicLoader::LoadFromMemory(this, data, size, params);
|
||||
}
|
||||
|
||||
bool NzMusic::OpenFromStream(NzInputStream& stream, const NzMusicParams& params)
|
||||
{
|
||||
return NzMusicLoader::LoadFromStream(this, stream, params);
|
||||
}
|
||||
|
||||
void NzMusic::Pause()
|
||||
{
|
||||
alSourcePause(m_source);
|
||||
}
|
||||
|
||||
void NzMusic::Play()
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
bool Music::OpenFromFile(const String& filePath, const MusicParams& params)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
return MusicLoader::LoadFromFile(this, filePath, params);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Nous sommes déjà en train de jouer
|
||||
if (m_impl->streaming)
|
||||
bool Music::OpenFromMemory(const void* data, std::size_t size, const MusicParams& params)
|
||||
{
|
||||
// Peut-être sommes-nous en pause
|
||||
if (GetStatus() != nzSoundStatus_Playing)
|
||||
alSourcePlay(m_source);
|
||||
return MusicLoader::LoadFromMemory(this, data, size, params);
|
||||
}
|
||||
|
||||
bool Music::OpenFromStream(Stream& stream, const MusicParams& params)
|
||||
{
|
||||
return MusicLoader::LoadFromStream(this, stream, params);
|
||||
}
|
||||
|
||||
void Music::Pause()
|
||||
{
|
||||
alSourcePause(m_source);
|
||||
}
|
||||
|
||||
void Music::Play()
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Nous sommes déjà en train de jouer
|
||||
if (m_impl->streaming)
|
||||
{
|
||||
// Peut-être sommes-nous en pause
|
||||
if (GetStatus() != SoundStatus_Playing)
|
||||
alSourcePlay(m_source);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Lancement du thread de streaming
|
||||
m_impl->stream->Seek(0);
|
||||
m_impl->streaming = true;
|
||||
m_impl->thread = Thread(&Music::MusicThread, this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Lancement du thread de streaming
|
||||
m_impl->stream->Seek(0);
|
||||
m_impl->streaming = true;
|
||||
m_impl->thread = NzThread(&NzMusic::MusicThread, this);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void NzMusic::SetPlayingOffset(nzUInt32 offset)
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
void Music::SetPlayingOffset(UInt32 offset)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
///TODO
|
||||
}
|
||||
|
||||
void NzMusic::Stop()
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_impl->streaming)
|
||||
{
|
||||
m_impl->streaming = false;
|
||||
m_impl->thread.Join();
|
||||
}
|
||||
}
|
||||
|
||||
bool NzMusic::FillAndQueueBuffer(unsigned int buffer)
|
||||
{
|
||||
unsigned int sampleCount = m_impl->chunkSamples.size();
|
||||
unsigned int sampleRead = 0;
|
||||
|
||||
// Lecture depuis le stream pour remplir le buffer
|
||||
for (;;)
|
||||
{
|
||||
sampleRead += m_impl->stream->Read(&m_impl->chunkSamples[sampleRead], sampleCount - sampleRead);
|
||||
if (sampleRead < sampleCount && !m_impl->loop)
|
||||
break; // Fin du stream (On ne boucle pas)
|
||||
|
||||
m_impl->stream->Seek(0); // On boucle au début du stream et on remplit à nouveau
|
||||
///TODO
|
||||
}
|
||||
|
||||
// Mise à jour du buffer (envoi à OpenAL) et placement dans la file d'attente
|
||||
if (sampleRead > 0)
|
||||
void Music::Stop()
|
||||
{
|
||||
alBufferData(buffer, m_impl->audioFormat, &m_impl->chunkSamples[0], sampleRead*sizeof(nzInt16), m_impl->sampleRate);
|
||||
alSourceQueueBuffers(m_source, 1, &buffer);
|
||||
}
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Music not created");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
return sampleRead != sampleCount; // Fin du stream (N'arrive pas en cas de loop)
|
||||
}
|
||||
|
||||
void NzMusic::MusicThread()
|
||||
{
|
||||
// Allocation des buffers de streaming
|
||||
ALuint buffers[NAZARA_AUDIO_STREAMED_BUFFER_COUNT];
|
||||
alGenBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers);
|
||||
|
||||
for (unsigned int i = 0; i < NAZARA_AUDIO_STREAMED_BUFFER_COUNT; ++i)
|
||||
{
|
||||
if (FillAndQueueBuffer(buffers[i]))
|
||||
break; // Nous avons atteint la fin du stream, inutile de rajouter des buffers
|
||||
}
|
||||
|
||||
alSourcePlay(m_source);
|
||||
|
||||
// Boucle de lecture (remplissage de nouveaux buffers au fur et à mesure)
|
||||
while (m_impl->streaming)
|
||||
{
|
||||
// La lecture s'est arrêtée, nous avons atteint la fin du stream
|
||||
nzSoundStatus status = GetInternalStatus();
|
||||
if (status == nzSoundStatus_Stopped)
|
||||
if (m_impl->streaming)
|
||||
{
|
||||
m_impl->streaming = false;
|
||||
break;
|
||||
m_impl->thread.Join();
|
||||
}
|
||||
|
||||
// On traite les buffers lus
|
||||
ALint processedCount = 0;
|
||||
alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &processedCount);
|
||||
|
||||
ALuint buffer;
|
||||
while (processedCount--)
|
||||
{
|
||||
alSourceUnqueueBuffers(m_source, 1, &buffer);
|
||||
if (FillAndQueueBuffer(buffer))
|
||||
break;
|
||||
}
|
||||
|
||||
// On retourne dormir un peu
|
||||
NzThread::Sleep(50);
|
||||
}
|
||||
|
||||
// Arrêt de la lecture du son (dans le cas où ça ne serait pas déjà fait)
|
||||
alSourceStop(m_source);
|
||||
bool Music::FillAndQueueBuffer(unsigned int buffer)
|
||||
{
|
||||
unsigned int sampleCount = m_impl->chunkSamples.size();
|
||||
unsigned int sampleRead = 0;
|
||||
|
||||
// On supprime les buffers du stream
|
||||
ALint queuedBufferCount;
|
||||
alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queuedBufferCount);
|
||||
// Lecture depuis le stream pour remplir le buffer
|
||||
for (;;)
|
||||
{
|
||||
sampleRead += m_impl->stream->Read(&m_impl->chunkSamples[sampleRead], sampleCount - sampleRead);
|
||||
if (sampleRead < sampleCount && !m_impl->loop)
|
||||
break; // Fin du stream (On ne boucle pas)
|
||||
|
||||
ALuint buffer;
|
||||
for (ALint i = 0; i < queuedBufferCount; ++i)
|
||||
alSourceUnqueueBuffers(m_source, 1, &buffer);
|
||||
m_impl->stream->Seek(0); // On boucle au début du stream et on remplit à nouveau
|
||||
}
|
||||
|
||||
alDeleteBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers);
|
||||
// Mise à jour du buffer (envoi à OpenAL) et placement dans la file d'attente
|
||||
if (sampleRead > 0)
|
||||
{
|
||||
alBufferData(buffer, m_impl->audioFormat, &m_impl->chunkSamples[0], sampleRead*sizeof(Int16), m_impl->sampleRate);
|
||||
alSourceQueueBuffers(m_source, 1, &buffer);
|
||||
}
|
||||
|
||||
return sampleRead != sampleCount; // Fin du stream (N'arrive pas en cas de loop)
|
||||
}
|
||||
|
||||
void Music::MusicThread()
|
||||
{
|
||||
// Allocation des buffers de streaming
|
||||
ALuint buffers[NAZARA_AUDIO_STREAMED_BUFFER_COUNT];
|
||||
alGenBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers);
|
||||
|
||||
for (unsigned int i = 0; i < NAZARA_AUDIO_STREAMED_BUFFER_COUNT; ++i)
|
||||
{
|
||||
if (FillAndQueueBuffer(buffers[i]))
|
||||
break; // Nous avons atteint la fin du stream, inutile de rajouter des buffers
|
||||
}
|
||||
|
||||
alSourcePlay(m_source);
|
||||
|
||||
// Boucle de lecture (remplissage de nouveaux buffers au fur et à mesure)
|
||||
while (m_impl->streaming)
|
||||
{
|
||||
// La lecture s'est arrêtée, nous avons atteint la fin du stream
|
||||
SoundStatus status = GetInternalStatus();
|
||||
if (status == SoundStatus_Stopped)
|
||||
{
|
||||
m_impl->streaming = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// On traite les buffers lus
|
||||
ALint processedCount = 0;
|
||||
alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &processedCount);
|
||||
|
||||
ALuint buffer;
|
||||
while (processedCount--)
|
||||
{
|
||||
alSourceUnqueueBuffers(m_source, 1, &buffer);
|
||||
if (FillAndQueueBuffer(buffer))
|
||||
break;
|
||||
}
|
||||
|
||||
// On retourne dormir un peu
|
||||
Thread::Sleep(50);
|
||||
}
|
||||
|
||||
// Arrêt de la lecture du son (dans le cas où ça ne serait pas déjà fait)
|
||||
alSourceStop(m_source);
|
||||
|
||||
// On supprime les buffers du stream
|
||||
ALint queuedBufferCount;
|
||||
alGetSourcei(m_source, AL_BUFFERS_QUEUED, &queuedBufferCount);
|
||||
|
||||
ALuint buffer;
|
||||
for (ALint i = 0; i < queuedBufferCount; ++i)
|
||||
alSourceUnqueueBuffers(m_source, 1, &buffer);
|
||||
|
||||
alDeleteBuffers(NAZARA_AUDIO_STREAMED_BUFFER_COUNT, buffers);
|
||||
}
|
||||
|
||||
MusicLoader::LoaderList Music::s_loaders;
|
||||
}
|
||||
|
||||
NzMusicLoader::LoaderList NzMusic::s_loaders;
|
||||
|
||||
@@ -11,459 +11,462 @@
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
namespace
|
||||
namespace Nz
|
||||
{
|
||||
NzDynLib s_library;
|
||||
NzString s_deviceName;
|
||||
NzString s_rendererName;
|
||||
NzString s_vendorName;
|
||||
ALCdevice* s_device = nullptr;
|
||||
ALCcontext* s_context = nullptr;
|
||||
unsigned int s_version;
|
||||
|
||||
unsigned int ParseDevices(const char* deviceString, std::vector<NzString>& devices)
|
||||
namespace
|
||||
{
|
||||
DynLib s_library;
|
||||
String s_deviceName;
|
||||
String s_rendererName;
|
||||
String s_vendorName;
|
||||
ALCdevice* s_device = nullptr;
|
||||
ALCcontext* s_context = nullptr;
|
||||
unsigned int s_version;
|
||||
|
||||
unsigned int ParseDevices(const char* deviceString, std::vector<String>& devices)
|
||||
{
|
||||
if (!deviceString)
|
||||
return 0;
|
||||
|
||||
unsigned int startSize = devices.size();
|
||||
|
||||
unsigned int length;
|
||||
while ((length = std::strlen(deviceString)) > 0)
|
||||
{
|
||||
devices.push_back(String(deviceString, length));
|
||||
deviceString += length + 1;
|
||||
}
|
||||
|
||||
return devices.size() - startSize;
|
||||
}
|
||||
}
|
||||
|
||||
OpenALFunc OpenAL::GetEntry(const String& entryPoint)
|
||||
{
|
||||
return LoadEntry(entryPoint.GetConstBuffer(), false);
|
||||
}
|
||||
|
||||
String OpenAL::GetRendererName()
|
||||
{
|
||||
return s_rendererName;
|
||||
}
|
||||
|
||||
String OpenAL::GetVendorName()
|
||||
{
|
||||
return s_vendorName;
|
||||
}
|
||||
|
||||
unsigned int OpenAL::GetVersion()
|
||||
{
|
||||
return s_version;
|
||||
}
|
||||
|
||||
bool OpenAL::Initialize(bool openDevice)
|
||||
{
|
||||
if (s_library.IsLoaded())
|
||||
return true;
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
///FIXME: Est-ce qu'OpenAL Soft est une meilleure implémentation que Creative ?
|
||||
/// Si on pouvait se résigner à utiliser OpenAL Soft tout le temps, cela nous permettrait d'utiliser les extensions sonores
|
||||
/// et de donner plus de possibilités techniques au niveau de l'audio.
|
||||
const char* libs[] = {
|
||||
"soft_oal.dll",
|
||||
"wrap_oal.dll",
|
||||
"openal32.dll"
|
||||
};
|
||||
#elif defined(NAZARA_PLATFORM_LINUX)
|
||||
const char* libs[] = {
|
||||
"libopenal.so.1",
|
||||
"libopenal.so.0",
|
||||
"libopenal.so"
|
||||
};
|
||||
//#elif defined(NAZARA_PLATFORM_MACOSX)
|
||||
#else
|
||||
NazaraError("Unknown OS");
|
||||
return false;
|
||||
#endif
|
||||
|
||||
bool succeeded = false;
|
||||
for (const char* path : libs)
|
||||
{
|
||||
String libPath(path);
|
||||
if (!s_library.Load(libPath))
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
// al
|
||||
alBuffer3f = reinterpret_cast<OpenALDetail::LPALBUFFER3F>(LoadEntry("alBuffer3f"));
|
||||
alBuffer3i = reinterpret_cast<OpenALDetail::LPALBUFFER3I>(LoadEntry("alBuffer3i"));
|
||||
alBufferData = reinterpret_cast<OpenALDetail::LPALBUFFERDATA>(LoadEntry("alBufferData"));
|
||||
alBufferf = reinterpret_cast<OpenALDetail::LPALBUFFERF>(LoadEntry("alBufferf"));
|
||||
alBufferfv = reinterpret_cast<OpenALDetail::LPALBUFFERFV>(LoadEntry("alBufferfv"));
|
||||
alBufferi = reinterpret_cast<OpenALDetail::LPALBUFFERI>(LoadEntry("alBufferi"));
|
||||
alBufferiv = reinterpret_cast<OpenALDetail::LPALBUFFERIV>(LoadEntry("alBufferiv"));
|
||||
alDeleteBuffers = reinterpret_cast<OpenALDetail::LPALDELETEBUFFERS>(LoadEntry("alDeleteBuffers"));
|
||||
alDeleteSources = reinterpret_cast<OpenALDetail::LPALDELETESOURCES>(LoadEntry("alDeleteSources"));
|
||||
alDisable = reinterpret_cast<OpenALDetail::LPALDISABLE>(LoadEntry("alDisable"));
|
||||
alDistanceModel = reinterpret_cast<OpenALDetail::LPALDISTANCEMODEL>(LoadEntry("alDistanceModel"));
|
||||
alDopplerFactor = reinterpret_cast<OpenALDetail::LPALDOPPLERFACTOR>(LoadEntry("alDopplerFactor"));
|
||||
alDopplerVelocity = reinterpret_cast<OpenALDetail::LPALDOPPLERVELOCITY>(LoadEntry("alDopplerVelocity"));
|
||||
alEnable = reinterpret_cast<OpenALDetail::LPALENABLE>(LoadEntry("alEnable"));
|
||||
alGenBuffers = reinterpret_cast<OpenALDetail::LPALGENBUFFERS>(LoadEntry("alGenBuffers"));
|
||||
alGenSources = reinterpret_cast<OpenALDetail::LPALGENSOURCES>(LoadEntry("alGenSources"));
|
||||
alGetBoolean = reinterpret_cast<OpenALDetail::LPALGETBOOLEAN>(LoadEntry("alGetBoolean"));
|
||||
alGetBooleanv = reinterpret_cast<OpenALDetail::LPALGETBOOLEANV>(LoadEntry("alGetBooleanv"));
|
||||
alGetBuffer3f = reinterpret_cast<OpenALDetail::LPALGETBUFFER3F>(LoadEntry("alGetBuffer3f"));
|
||||
alGetBuffer3i = reinterpret_cast<OpenALDetail::LPALGETBUFFER3I>(LoadEntry("alGetBuffer3i"));
|
||||
alGetBufferf = reinterpret_cast<OpenALDetail::LPALGETBUFFERF>(LoadEntry("alGetBufferf"));
|
||||
alGetBufferfv = reinterpret_cast<OpenALDetail::LPALGETBUFFERFV>(LoadEntry("alGetBufferfv"));
|
||||
alGetBufferi = reinterpret_cast<OpenALDetail::LPALGETBUFFERI>(LoadEntry("alGetBufferi"));
|
||||
alGetBufferiv = reinterpret_cast<OpenALDetail::LPALGETBUFFERIV>(LoadEntry("alGetBufferiv"));
|
||||
alGetDouble = reinterpret_cast<OpenALDetail::LPALGETDOUBLE>(LoadEntry("alGetDouble"));
|
||||
alGetDoublev = reinterpret_cast<OpenALDetail::LPALGETDOUBLEV>(LoadEntry("alGetDoublev"));
|
||||
alGetEnumValue = reinterpret_cast<OpenALDetail::LPALGETENUMVALUE>(LoadEntry("alGetEnumValue"));
|
||||
alGetError = reinterpret_cast<OpenALDetail::LPALGETERROR>(LoadEntry("alGetError"));
|
||||
alGetFloat = reinterpret_cast<OpenALDetail::LPALGETFLOAT>(LoadEntry("alGetFloat"));
|
||||
alGetFloatv = reinterpret_cast<OpenALDetail::LPALGETFLOATV>(LoadEntry("alGetFloatv"));
|
||||
alGetInteger = reinterpret_cast<OpenALDetail::LPALGETINTEGER>(LoadEntry("alGetInteger"));
|
||||
alGetIntegerv = reinterpret_cast<OpenALDetail::LPALGETINTEGERV>(LoadEntry("alGetIntegerv"));
|
||||
alGetListener3f = reinterpret_cast<OpenALDetail::LPALGETLISTENER3F>(LoadEntry("alGetListener3f"));
|
||||
alGetListener3i = reinterpret_cast<OpenALDetail::LPALGETLISTENER3I>(LoadEntry("alGetListener3i"));
|
||||
alGetListenerf = reinterpret_cast<OpenALDetail::LPALGETLISTENERF>(LoadEntry("alGetListenerf"));
|
||||
alGetListenerfv = reinterpret_cast<OpenALDetail::LPALGETLISTENERFV>(LoadEntry("alGetListenerfv"));
|
||||
alGetListeneri = reinterpret_cast<OpenALDetail::LPALGETLISTENERI>(LoadEntry("alGetListeneri"));
|
||||
alGetListeneriv = reinterpret_cast<OpenALDetail::LPALGETLISTENERIV>(LoadEntry("alGetListeneriv"));
|
||||
alGetProcAddress = reinterpret_cast<OpenALDetail::LPALGETPROCADDRESS>(LoadEntry("alGetProcAddress"));
|
||||
alGetSource3f = reinterpret_cast<OpenALDetail::LPALGETSOURCE3F>(LoadEntry("alGetSource3f"));
|
||||
alGetSource3i = reinterpret_cast<OpenALDetail::LPALGETSOURCE3I>(LoadEntry("alGetSource3i"));
|
||||
alGetSourcef = reinterpret_cast<OpenALDetail::LPALGETSOURCEF>(LoadEntry("alGetSourcef"));
|
||||
alGetSourcefv = reinterpret_cast<OpenALDetail::LPALGETSOURCEFV>(LoadEntry("alGetSourcefv"));
|
||||
alGetSourcei = reinterpret_cast<OpenALDetail::LPALGETSOURCEI>(LoadEntry("alGetSourcei"));
|
||||
alGetSourceiv = reinterpret_cast<OpenALDetail::LPALGETSOURCEIV>(LoadEntry("alGetSourceiv"));
|
||||
alGetString = reinterpret_cast<OpenALDetail::LPALGETSTRING>(LoadEntry("alGetString"));
|
||||
alIsBuffer = reinterpret_cast<OpenALDetail::LPALISBUFFER>(LoadEntry("alIsBuffer"));
|
||||
alIsEnabled = reinterpret_cast<OpenALDetail::LPALISENABLED>(LoadEntry("alIsEnabled"));
|
||||
alIsExtensionPresent = reinterpret_cast<OpenALDetail::LPALISEXTENSIONPRESENT>(LoadEntry("alIsExtensionPresent"));
|
||||
alIsSource = reinterpret_cast<OpenALDetail::LPALISSOURCE>(LoadEntry("alIsSource"));
|
||||
alListener3f = reinterpret_cast<OpenALDetail::LPALLISTENER3F>(LoadEntry("alListener3f"));
|
||||
alListener3i = reinterpret_cast<OpenALDetail::LPALLISTENER3I>(LoadEntry("alListener3i"));
|
||||
alListenerf = reinterpret_cast<OpenALDetail::LPALLISTENERF>(LoadEntry("alListenerf"));
|
||||
alListenerfv = reinterpret_cast<OpenALDetail::LPALLISTENERFV>(LoadEntry("alListenerfv"));
|
||||
alListeneri = reinterpret_cast<OpenALDetail::LPALLISTENERI>(LoadEntry("alListeneri"));
|
||||
alListeneriv = reinterpret_cast<OpenALDetail::LPALLISTENERIV>(LoadEntry("alListeneriv"));
|
||||
alSource3f = reinterpret_cast<OpenALDetail::LPALSOURCE3F>(LoadEntry("alSource3f"));
|
||||
alSource3i = reinterpret_cast<OpenALDetail::LPALSOURCE3I>(LoadEntry("alSource3i"));
|
||||
alSourcef = reinterpret_cast<OpenALDetail::LPALSOURCEF>(LoadEntry("alSourcef"));
|
||||
alSourcefv = reinterpret_cast<OpenALDetail::LPALSOURCEFV>(LoadEntry("alSourcefv"));
|
||||
alSourcei = reinterpret_cast<OpenALDetail::LPALSOURCEI>(LoadEntry("alSourcei"));
|
||||
alSourceiv = reinterpret_cast<OpenALDetail::LPALSOURCEIV>(LoadEntry("alSourceiv"));
|
||||
alSourcePause = reinterpret_cast<OpenALDetail::LPALSOURCEPAUSE>(LoadEntry("alSourcePause"));
|
||||
alSourcePausev = reinterpret_cast<OpenALDetail::LPALSOURCEPAUSEV>(LoadEntry("alSourcePausev"));
|
||||
alSourcePlay = reinterpret_cast<OpenALDetail::LPALSOURCEPLAY>(LoadEntry("alSourcePlay"));
|
||||
alSourcePlayv = reinterpret_cast<OpenALDetail::LPALSOURCEPLAYV>(LoadEntry("alSourcePlayv"));
|
||||
alSourceQueueBuffers = reinterpret_cast<OpenALDetail::LPALSOURCEQUEUEBUFFERS>(LoadEntry("alSourceQueueBuffers"));
|
||||
alSourceRewind = reinterpret_cast<OpenALDetail::LPALSOURCEREWIND>(LoadEntry("alSourceRewind"));
|
||||
alSourceRewindv = reinterpret_cast<OpenALDetail::LPALSOURCEREWINDV>(LoadEntry("alSourceRewindv"));
|
||||
alSourceStop = reinterpret_cast<OpenALDetail::LPALSOURCESTOP>(LoadEntry("alSourceStop"));
|
||||
alSourceStopv = reinterpret_cast<OpenALDetail::LPALSOURCESTOPV>(LoadEntry("alSourceStopv"));
|
||||
alSourceUnqueueBuffers = reinterpret_cast<OpenALDetail::LPALSOURCEUNQUEUEBUFFERS>(LoadEntry("alSourceUnqueueBuffers"));
|
||||
alSpeedOfSound = reinterpret_cast<OpenALDetail::LPALSPEEDOFSOUND>(LoadEntry("alSpeedOfSound"));
|
||||
|
||||
// alc
|
||||
alcCaptureCloseDevice = reinterpret_cast<OpenALDetail::LPALCCAPTURECLOSEDEVICE>(LoadEntry("alcCaptureCloseDevice"));
|
||||
alcCaptureOpenDevice = reinterpret_cast<OpenALDetail::LPALCCAPTUREOPENDEVICE>(LoadEntry("alcCaptureOpenDevice"));
|
||||
alcCaptureSamples = reinterpret_cast<OpenALDetail::LPALCCAPTURESAMPLES>(LoadEntry("alcCaptureSamples"));
|
||||
alcCaptureStart = reinterpret_cast<OpenALDetail::LPALCCAPTURESTART>(LoadEntry("alcCaptureStart"));
|
||||
alcCaptureStop = reinterpret_cast<OpenALDetail::LPALCCAPTURESTOP>(LoadEntry("alcCaptureStop"));
|
||||
alcCloseDevice = reinterpret_cast<OpenALDetail::LPALCCLOSEDEVICE>(LoadEntry("alcCloseDevice"));
|
||||
alcCreateContext = reinterpret_cast<OpenALDetail::LPALCCREATECONTEXT>(LoadEntry("alcCreateContext"));
|
||||
alcDestroyContext = reinterpret_cast<OpenALDetail::LPALCDESTROYCONTEXT>(LoadEntry("alcDestroyContext"));
|
||||
alcGetContextsDevice = reinterpret_cast<OpenALDetail::LPALCGETCONTEXTSDEVICE>(LoadEntry("alcGetContextsDevice"));
|
||||
alcGetCurrentContext = reinterpret_cast<OpenALDetail::LPALCGETCURRENTCONTEXT>(LoadEntry("alcGetCurrentContext"));
|
||||
alcGetEnumValue = reinterpret_cast<OpenALDetail::LPALCGETENUMVALUE>(LoadEntry("alcGetEnumValue"));
|
||||
alcGetError = reinterpret_cast<OpenALDetail::LPALCGETERROR>(LoadEntry("alcGetError"));
|
||||
alcGetIntegerv = reinterpret_cast<OpenALDetail::LPALCGETINTEGERV>(LoadEntry("alcGetIntegerv"));
|
||||
alcGetProcAddress = reinterpret_cast<OpenALDetail::LPALCGETPROCADDRESS>(LoadEntry("alcGetProcAddress"));
|
||||
alcGetString = reinterpret_cast<OpenALDetail::LPALCGETSTRING>(LoadEntry("alcGetString"));
|
||||
alcIsExtensionPresent = reinterpret_cast<OpenALDetail::LPALCISEXTENSIONPRESENT>(LoadEntry("alcIsExtensionPresent"));
|
||||
alcMakeContextCurrent = reinterpret_cast<OpenALDetail::LPALCMAKECONTEXTCURRENT>(LoadEntry("alcMakeContextCurrent"));
|
||||
alcOpenDevice = reinterpret_cast<OpenALDetail::LPALCOPENDEVICE>(LoadEntry("alcOpenDevice"));
|
||||
alcProcessContext = reinterpret_cast<OpenALDetail::LPALCPROCESSCONTEXT>(LoadEntry("alcProcessContext"));
|
||||
alcSuspendContext = reinterpret_cast<OpenALDetail::LPALCSUSPENDCONTEXT>(LoadEntry("alcSuspendContext"));
|
||||
|
||||
succeeded = true;
|
||||
break;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
NazaraWarning(libPath + " loading failed: " + String(e.what()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!succeeded)
|
||||
{
|
||||
NazaraError("Failed to load OpenAL");
|
||||
Uninitialize();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (openDevice)
|
||||
OpenDevice();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenAL::IsInitialized()
|
||||
{
|
||||
return s_library.IsLoaded();
|
||||
}
|
||||
|
||||
unsigned int OpenAL::QueryInputDevices(std::vector<String>& devices)
|
||||
{
|
||||
const char* deviceString = reinterpret_cast<const char*>(alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER));
|
||||
if (!deviceString)
|
||||
return 0;
|
||||
|
||||
unsigned int startSize = devices.size();
|
||||
|
||||
unsigned int length;
|
||||
while ((length = std::strlen(deviceString)) > 0)
|
||||
{
|
||||
devices.push_back(NzString(deviceString, length));
|
||||
deviceString += length + 1;
|
||||
}
|
||||
|
||||
return devices.size() - startSize;
|
||||
return ParseDevices(deviceString, devices);
|
||||
}
|
||||
}
|
||||
|
||||
NzOpenALFunc NzOpenAL::GetEntry(const NzString& entryPoint)
|
||||
{
|
||||
return LoadEntry(entryPoint.GetConstBuffer(), false);
|
||||
}
|
||||
|
||||
NzString NzOpenAL::GetRendererName()
|
||||
{
|
||||
return s_rendererName;
|
||||
}
|
||||
|
||||
NzString NzOpenAL::GetVendorName()
|
||||
{
|
||||
return s_vendorName;
|
||||
}
|
||||
|
||||
unsigned int NzOpenAL::GetVersion()
|
||||
{
|
||||
return s_version;
|
||||
}
|
||||
|
||||
bool NzOpenAL::Initialize(bool openDevice)
|
||||
{
|
||||
if (s_library.IsLoaded())
|
||||
return true;
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
///FIXME: Est-ce qu'OpenAL Soft est une meilleure implémentation que Creative ?
|
||||
/// Si on pouvait se résigner à utiliser OpenAL Soft tout le temps, cela nous permettrait d'utiliser les extensions sonores
|
||||
/// et de donner plus de possibilités techniques au niveau de l'audio.
|
||||
const char* libs[] = {
|
||||
"soft_oal.dll",
|
||||
"wrap_oal.dll",
|
||||
"openal32.dll"
|
||||
};
|
||||
#elif defined(NAZARA_PLATFORM_LINUX)
|
||||
const char* libs[] = {
|
||||
"libopenal.so.1",
|
||||
"libopenal.so.0",
|
||||
"libopenal.so"
|
||||
};
|
||||
//#elif defined(NAZARA_PLATFORM_MACOSX)
|
||||
#else
|
||||
NazaraError("Unknown OS");
|
||||
return false;
|
||||
#endif
|
||||
|
||||
bool succeeded = false;
|
||||
for (const char* path : libs)
|
||||
unsigned int OpenAL::QueryOutputDevices(std::vector<String>& devices)
|
||||
{
|
||||
NzString libPath(path);
|
||||
if (!s_library.Load(libPath))
|
||||
continue;
|
||||
const char* deviceString = reinterpret_cast<const char*>(alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER));
|
||||
if (!deviceString)
|
||||
return 0;
|
||||
|
||||
try
|
||||
{
|
||||
// al
|
||||
alBuffer3f = reinterpret_cast<NzOpenALDetail::LPALBUFFER3F>(LoadEntry("alBuffer3f"));
|
||||
alBuffer3i = reinterpret_cast<NzOpenALDetail::LPALBUFFER3I>(LoadEntry("alBuffer3i"));
|
||||
alBufferData = reinterpret_cast<NzOpenALDetail::LPALBUFFERDATA>(LoadEntry("alBufferData"));
|
||||
alBufferf = reinterpret_cast<NzOpenALDetail::LPALBUFFERF>(LoadEntry("alBufferf"));
|
||||
alBufferfv = reinterpret_cast<NzOpenALDetail::LPALBUFFERFV>(LoadEntry("alBufferfv"));
|
||||
alBufferi = reinterpret_cast<NzOpenALDetail::LPALBUFFERI>(LoadEntry("alBufferi"));
|
||||
alBufferiv = reinterpret_cast<NzOpenALDetail::LPALBUFFERIV>(LoadEntry("alBufferiv"));
|
||||
alDeleteBuffers = reinterpret_cast<NzOpenALDetail::LPALDELETEBUFFERS>(LoadEntry("alDeleteBuffers"));
|
||||
alDeleteSources = reinterpret_cast<NzOpenALDetail::LPALDELETESOURCES>(LoadEntry("alDeleteSources"));
|
||||
alDisable = reinterpret_cast<NzOpenALDetail::LPALDISABLE>(LoadEntry("alDisable"));
|
||||
alDistanceModel = reinterpret_cast<NzOpenALDetail::LPALDISTANCEMODEL>(LoadEntry("alDistanceModel"));
|
||||
alDopplerFactor = reinterpret_cast<NzOpenALDetail::LPALDOPPLERFACTOR>(LoadEntry("alDopplerFactor"));
|
||||
alDopplerVelocity = reinterpret_cast<NzOpenALDetail::LPALDOPPLERVELOCITY>(LoadEntry("alDopplerVelocity"));
|
||||
alEnable = reinterpret_cast<NzOpenALDetail::LPALENABLE>(LoadEntry("alEnable"));
|
||||
alGenBuffers = reinterpret_cast<NzOpenALDetail::LPALGENBUFFERS>(LoadEntry("alGenBuffers"));
|
||||
alGenSources = reinterpret_cast<NzOpenALDetail::LPALGENSOURCES>(LoadEntry("alGenSources"));
|
||||
alGetBoolean = reinterpret_cast<NzOpenALDetail::LPALGETBOOLEAN>(LoadEntry("alGetBoolean"));
|
||||
alGetBooleanv = reinterpret_cast<NzOpenALDetail::LPALGETBOOLEANV>(LoadEntry("alGetBooleanv"));
|
||||
alGetBuffer3f = reinterpret_cast<NzOpenALDetail::LPALGETBUFFER3F>(LoadEntry("alGetBuffer3f"));
|
||||
alGetBuffer3i = reinterpret_cast<NzOpenALDetail::LPALGETBUFFER3I>(LoadEntry("alGetBuffer3i"));
|
||||
alGetBufferf = reinterpret_cast<NzOpenALDetail::LPALGETBUFFERF>(LoadEntry("alGetBufferf"));
|
||||
alGetBufferfv = reinterpret_cast<NzOpenALDetail::LPALGETBUFFERFV>(LoadEntry("alGetBufferfv"));
|
||||
alGetBufferi = reinterpret_cast<NzOpenALDetail::LPALGETBUFFERI>(LoadEntry("alGetBufferi"));
|
||||
alGetBufferiv = reinterpret_cast<NzOpenALDetail::LPALGETBUFFERIV>(LoadEntry("alGetBufferiv"));
|
||||
alGetDouble = reinterpret_cast<NzOpenALDetail::LPALGETDOUBLE>(LoadEntry("alGetDouble"));
|
||||
alGetDoublev = reinterpret_cast<NzOpenALDetail::LPALGETDOUBLEV>(LoadEntry("alGetDoublev"));
|
||||
alGetEnumValue = reinterpret_cast<NzOpenALDetail::LPALGETENUMVALUE>(LoadEntry("alGetEnumValue"));
|
||||
alGetError = reinterpret_cast<NzOpenALDetail::LPALGETERROR>(LoadEntry("alGetError"));
|
||||
alGetFloat = reinterpret_cast<NzOpenALDetail::LPALGETFLOAT>(LoadEntry("alGetFloat"));
|
||||
alGetFloatv = reinterpret_cast<NzOpenALDetail::LPALGETFLOATV>(LoadEntry("alGetFloatv"));
|
||||
alGetInteger = reinterpret_cast<NzOpenALDetail::LPALGETINTEGER>(LoadEntry("alGetInteger"));
|
||||
alGetIntegerv = reinterpret_cast<NzOpenALDetail::LPALGETINTEGERV>(LoadEntry("alGetIntegerv"));
|
||||
alGetListener3f = reinterpret_cast<NzOpenALDetail::LPALGETLISTENER3F>(LoadEntry("alGetListener3f"));
|
||||
alGetListener3i = reinterpret_cast<NzOpenALDetail::LPALGETLISTENER3I>(LoadEntry("alGetListener3i"));
|
||||
alGetListenerf = reinterpret_cast<NzOpenALDetail::LPALGETLISTENERF>(LoadEntry("alGetListenerf"));
|
||||
alGetListenerfv = reinterpret_cast<NzOpenALDetail::LPALGETLISTENERFV>(LoadEntry("alGetListenerfv"));
|
||||
alGetListeneri = reinterpret_cast<NzOpenALDetail::LPALGETLISTENERI>(LoadEntry("alGetListeneri"));
|
||||
alGetListeneriv = reinterpret_cast<NzOpenALDetail::LPALGETLISTENERIV>(LoadEntry("alGetListeneriv"));
|
||||
alGetProcAddress = reinterpret_cast<NzOpenALDetail::LPALGETPROCADDRESS>(LoadEntry("alGetProcAddress"));
|
||||
alGetSource3f = reinterpret_cast<NzOpenALDetail::LPALGETSOURCE3F>(LoadEntry("alGetSource3f"));
|
||||
alGetSource3i = reinterpret_cast<NzOpenALDetail::LPALGETSOURCE3I>(LoadEntry("alGetSource3i"));
|
||||
alGetSourcef = reinterpret_cast<NzOpenALDetail::LPALGETSOURCEF>(LoadEntry("alGetSourcef"));
|
||||
alGetSourcefv = reinterpret_cast<NzOpenALDetail::LPALGETSOURCEFV>(LoadEntry("alGetSourcefv"));
|
||||
alGetSourcei = reinterpret_cast<NzOpenALDetail::LPALGETSOURCEI>(LoadEntry("alGetSourcei"));
|
||||
alGetSourceiv = reinterpret_cast<NzOpenALDetail::LPALGETSOURCEIV>(LoadEntry("alGetSourceiv"));
|
||||
alGetString = reinterpret_cast<NzOpenALDetail::LPALGETSTRING>(LoadEntry("alGetString"));
|
||||
alIsBuffer = reinterpret_cast<NzOpenALDetail::LPALISBUFFER>(LoadEntry("alIsBuffer"));
|
||||
alIsEnabled = reinterpret_cast<NzOpenALDetail::LPALISENABLED>(LoadEntry("alIsEnabled"));
|
||||
alIsExtensionPresent = reinterpret_cast<NzOpenALDetail::LPALISEXTENSIONPRESENT>(LoadEntry("alIsExtensionPresent"));
|
||||
alIsSource = reinterpret_cast<NzOpenALDetail::LPALISSOURCE>(LoadEntry("alIsSource"));
|
||||
alListener3f = reinterpret_cast<NzOpenALDetail::LPALLISTENER3F>(LoadEntry("alListener3f"));
|
||||
alListener3i = reinterpret_cast<NzOpenALDetail::LPALLISTENER3I>(LoadEntry("alListener3i"));
|
||||
alListenerf = reinterpret_cast<NzOpenALDetail::LPALLISTENERF>(LoadEntry("alListenerf"));
|
||||
alListenerfv = reinterpret_cast<NzOpenALDetail::LPALLISTENERFV>(LoadEntry("alListenerfv"));
|
||||
alListeneri = reinterpret_cast<NzOpenALDetail::LPALLISTENERI>(LoadEntry("alListeneri"));
|
||||
alListeneriv = reinterpret_cast<NzOpenALDetail::LPALLISTENERIV>(LoadEntry("alListeneriv"));
|
||||
alSource3f = reinterpret_cast<NzOpenALDetail::LPALSOURCE3F>(LoadEntry("alSource3f"));
|
||||
alSource3i = reinterpret_cast<NzOpenALDetail::LPALSOURCE3I>(LoadEntry("alSource3i"));
|
||||
alSourcef = reinterpret_cast<NzOpenALDetail::LPALSOURCEF>(LoadEntry("alSourcef"));
|
||||
alSourcefv = reinterpret_cast<NzOpenALDetail::LPALSOURCEFV>(LoadEntry("alSourcefv"));
|
||||
alSourcei = reinterpret_cast<NzOpenALDetail::LPALSOURCEI>(LoadEntry("alSourcei"));
|
||||
alSourceiv = reinterpret_cast<NzOpenALDetail::LPALSOURCEIV>(LoadEntry("alSourceiv"));
|
||||
alSourcePause = reinterpret_cast<NzOpenALDetail::LPALSOURCEPAUSE>(LoadEntry("alSourcePause"));
|
||||
alSourcePausev = reinterpret_cast<NzOpenALDetail::LPALSOURCEPAUSEV>(LoadEntry("alSourcePausev"));
|
||||
alSourcePlay = reinterpret_cast<NzOpenALDetail::LPALSOURCEPLAY>(LoadEntry("alSourcePlay"));
|
||||
alSourcePlayv = reinterpret_cast<NzOpenALDetail::LPALSOURCEPLAYV>(LoadEntry("alSourcePlayv"));
|
||||
alSourceQueueBuffers = reinterpret_cast<NzOpenALDetail::LPALSOURCEQUEUEBUFFERS>(LoadEntry("alSourceQueueBuffers"));
|
||||
alSourceRewind = reinterpret_cast<NzOpenALDetail::LPALSOURCEREWIND>(LoadEntry("alSourceRewind"));
|
||||
alSourceRewindv = reinterpret_cast<NzOpenALDetail::LPALSOURCEREWINDV>(LoadEntry("alSourceRewindv"));
|
||||
alSourceStop = reinterpret_cast<NzOpenALDetail::LPALSOURCESTOP>(LoadEntry("alSourceStop"));
|
||||
alSourceStopv = reinterpret_cast<NzOpenALDetail::LPALSOURCESTOPV>(LoadEntry("alSourceStopv"));
|
||||
alSourceUnqueueBuffers = reinterpret_cast<NzOpenALDetail::LPALSOURCEUNQUEUEBUFFERS>(LoadEntry("alSourceUnqueueBuffers"));
|
||||
alSpeedOfSound = reinterpret_cast<NzOpenALDetail::LPALSPEEDOFSOUND>(LoadEntry("alSpeedOfSound"));
|
||||
|
||||
// alc
|
||||
alcCaptureCloseDevice = reinterpret_cast<NzOpenALDetail::LPALCCAPTURECLOSEDEVICE>(LoadEntry("alcCaptureCloseDevice"));
|
||||
alcCaptureOpenDevice = reinterpret_cast<NzOpenALDetail::LPALCCAPTUREOPENDEVICE>(LoadEntry("alcCaptureOpenDevice"));
|
||||
alcCaptureSamples = reinterpret_cast<NzOpenALDetail::LPALCCAPTURESAMPLES>(LoadEntry("alcCaptureSamples"));
|
||||
alcCaptureStart = reinterpret_cast<NzOpenALDetail::LPALCCAPTURESTART>(LoadEntry("alcCaptureStart"));
|
||||
alcCaptureStop = reinterpret_cast<NzOpenALDetail::LPALCCAPTURESTOP>(LoadEntry("alcCaptureStop"));
|
||||
alcCloseDevice = reinterpret_cast<NzOpenALDetail::LPALCCLOSEDEVICE>(LoadEntry("alcCloseDevice"));
|
||||
alcCreateContext = reinterpret_cast<NzOpenALDetail::LPALCCREATECONTEXT>(LoadEntry("alcCreateContext"));
|
||||
alcDestroyContext = reinterpret_cast<NzOpenALDetail::LPALCDESTROYCONTEXT>(LoadEntry("alcDestroyContext"));
|
||||
alcGetContextsDevice = reinterpret_cast<NzOpenALDetail::LPALCGETCONTEXTSDEVICE>(LoadEntry("alcGetContextsDevice"));
|
||||
alcGetCurrentContext = reinterpret_cast<NzOpenALDetail::LPALCGETCURRENTCONTEXT>(LoadEntry("alcGetCurrentContext"));
|
||||
alcGetEnumValue = reinterpret_cast<NzOpenALDetail::LPALCGETENUMVALUE>(LoadEntry("alcGetEnumValue"));
|
||||
alcGetError = reinterpret_cast<NzOpenALDetail::LPALCGETERROR>(LoadEntry("alcGetError"));
|
||||
alcGetIntegerv = reinterpret_cast<NzOpenALDetail::LPALCGETINTEGERV>(LoadEntry("alcGetIntegerv"));
|
||||
alcGetProcAddress = reinterpret_cast<NzOpenALDetail::LPALCGETPROCADDRESS>(LoadEntry("alcGetProcAddress"));
|
||||
alcGetString = reinterpret_cast<NzOpenALDetail::LPALCGETSTRING>(LoadEntry("alcGetString"));
|
||||
alcIsExtensionPresent = reinterpret_cast<NzOpenALDetail::LPALCISEXTENSIONPRESENT>(LoadEntry("alcIsExtensionPresent"));
|
||||
alcMakeContextCurrent = reinterpret_cast<NzOpenALDetail::LPALCMAKECONTEXTCURRENT>(LoadEntry("alcMakeContextCurrent"));
|
||||
alcOpenDevice = reinterpret_cast<NzOpenALDetail::LPALCOPENDEVICE>(LoadEntry("alcOpenDevice"));
|
||||
alcProcessContext = reinterpret_cast<NzOpenALDetail::LPALCPROCESSCONTEXT>(LoadEntry("alcProcessContext"));
|
||||
alcSuspendContext = reinterpret_cast<NzOpenALDetail::LPALCSUSPENDCONTEXT>(LoadEntry("alcSuspendContext"));
|
||||
|
||||
succeeded = true;
|
||||
break;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
NazaraWarning(libPath + " loading failed: " + NzString(e.what()));
|
||||
continue;
|
||||
}
|
||||
return ParseDevices(deviceString, devices);
|
||||
}
|
||||
|
||||
if (!succeeded)
|
||||
bool OpenAL::SetDevice(const String& deviceName)
|
||||
{
|
||||
NazaraError("Failed to load OpenAL");
|
||||
Uninitialize();
|
||||
s_deviceName = deviceName;
|
||||
if (IsInitialized())
|
||||
{
|
||||
CloseDevice();
|
||||
|
||||
return false;
|
||||
return OpenDevice();
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
if (openDevice)
|
||||
OpenDevice();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzOpenAL::IsInitialized()
|
||||
{
|
||||
return s_library.IsLoaded();
|
||||
}
|
||||
|
||||
unsigned int NzOpenAL::QueryInputDevices(std::vector<NzString>& devices)
|
||||
{
|
||||
const char* deviceString = reinterpret_cast<const char*>(alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER));
|
||||
if (!deviceString)
|
||||
return 0;
|
||||
|
||||
return ParseDevices(deviceString, devices);
|
||||
}
|
||||
|
||||
unsigned int NzOpenAL::QueryOutputDevices(std::vector<NzString>& devices)
|
||||
{
|
||||
const char* deviceString = reinterpret_cast<const char*>(alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER));
|
||||
if (!deviceString)
|
||||
return 0;
|
||||
|
||||
return ParseDevices(deviceString, devices);
|
||||
}
|
||||
|
||||
bool NzOpenAL::SetDevice(const NzString& deviceName)
|
||||
{
|
||||
s_deviceName = deviceName;
|
||||
if (IsInitialized())
|
||||
void OpenAL::Uninitialize()
|
||||
{
|
||||
CloseDevice();
|
||||
|
||||
return OpenDevice();
|
||||
s_rendererName.Clear(false);
|
||||
s_vendorName.Clear(false);
|
||||
s_library.Unload();
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzOpenAL::Uninitialize()
|
||||
{
|
||||
CloseDevice();
|
||||
///ATTENTION: La valeur entière est le nombre de canaux possédés par ce format
|
||||
ALenum OpenAL::AudioFormat[AudioFormat_Max+1] = {0}; // Valeur ajoutées au chargement d'OpenAL
|
||||
|
||||
s_rendererName.Clear(false);
|
||||
s_vendorName.Clear(false);
|
||||
s_library.Unload();
|
||||
}
|
||||
|
||||
///ATTENTION: La valeur entière est le nombre de canaux possédés par ce format
|
||||
ALenum NzOpenAL::AudioFormat[nzAudioFormat_Max+1] = {0}; // Valeur ajoutées au chargement d'OpenAL
|
||||
|
||||
void NzOpenAL::CloseDevice()
|
||||
{
|
||||
if (s_device)
|
||||
void OpenAL::CloseDevice()
|
||||
{
|
||||
if (s_context)
|
||||
if (s_device)
|
||||
{
|
||||
alcMakeContextCurrent(nullptr);
|
||||
alcDestroyContext(s_context);
|
||||
s_context = nullptr;
|
||||
}
|
||||
|
||||
if (!alcCloseDevice(s_device))
|
||||
// Nous n'avons pas pu fermer le device, ce qui signifie qu'il est en cours d'utilisation
|
||||
NazaraWarning("Failed to close device");
|
||||
|
||||
s_device = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool NzOpenAL::OpenDevice()
|
||||
{
|
||||
// Initialisation du module
|
||||
s_device = alcOpenDevice(s_deviceName.IsEmpty() ? nullptr : s_deviceName.GetConstBuffer()); // On choisit le device par défaut
|
||||
if (!s_device)
|
||||
{
|
||||
NazaraError("Failed to open default device");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Un seul contexte nous suffira
|
||||
s_context = alcCreateContext(s_device, nullptr);
|
||||
if (!s_context)
|
||||
{
|
||||
NazaraError("Failed to create context");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!alcMakeContextCurrent(s_context))
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_rendererName = reinterpret_cast<const char*>(alGetString(AL_RENDERER));
|
||||
s_vendorName = reinterpret_cast<const char*>(alGetString(AL_VENDOR));
|
||||
|
||||
const ALchar* version = alGetString(AL_VERSION);
|
||||
if (version)
|
||||
{
|
||||
unsigned int major = version[0] - '0';
|
||||
unsigned int minor = version[2] - '0';
|
||||
|
||||
if (major != 0 && major <= 9)
|
||||
{
|
||||
if (minor > 9)
|
||||
if (s_context)
|
||||
{
|
||||
NazaraWarning("Unable to retrieve OpenAL minor version (using 0)");
|
||||
minor = 0;
|
||||
alcMakeContextCurrent(nullptr);
|
||||
alcDestroyContext(s_context);
|
||||
s_context = nullptr;
|
||||
}
|
||||
|
||||
s_version = major*100 + minor*10;
|
||||
if (!alcCloseDevice(s_device))
|
||||
// Nous n'avons pas pu fermer le device, ce qui signifie qu'il est en cours d'utilisation
|
||||
NazaraWarning("Failed to close device");
|
||||
|
||||
NazaraDebug("OpenAL version: " + NzString::Number(major) + '.' + NzString::Number(minor));
|
||||
s_device = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenAL::OpenDevice()
|
||||
{
|
||||
// Initialisation du module
|
||||
s_device = alcOpenDevice(s_deviceName.IsEmpty() ? nullptr : s_deviceName.GetConstBuffer()); // On choisit le device par défaut
|
||||
if (!s_device)
|
||||
{
|
||||
NazaraError("Failed to open default device");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Un seul contexte nous suffira
|
||||
s_context = alcCreateContext(s_device, nullptr);
|
||||
if (!s_context)
|
||||
{
|
||||
NazaraError("Failed to create context");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!alcMakeContextCurrent(s_context))
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_rendererName = reinterpret_cast<const char*>(alGetString(AL_RENDERER));
|
||||
s_vendorName = reinterpret_cast<const char*>(alGetString(AL_VENDOR));
|
||||
|
||||
const ALchar* version = alGetString(AL_VERSION);
|
||||
if (version)
|
||||
{
|
||||
unsigned int major = version[0] - '0';
|
||||
unsigned int minor = version[2] - '0';
|
||||
|
||||
if (major != 0 && major <= 9)
|
||||
{
|
||||
if (minor > 9)
|
||||
{
|
||||
NazaraWarning("Unable to retrieve OpenAL minor version (using 0)");
|
||||
minor = 0;
|
||||
}
|
||||
|
||||
s_version = major*100 + minor*10;
|
||||
|
||||
NazaraDebug("OpenAL version: " + String::Number(major) + '.' + String::Number(minor));
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraDebug("Unable to retrieve OpenAL major version");
|
||||
s_version = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraDebug("Unable to retrieve OpenAL major version");
|
||||
NazaraDebug("Unable to retrieve OpenAL version");
|
||||
s_version = 0;
|
||||
}
|
||||
|
||||
// On complète le tableau de formats
|
||||
AudioFormat[AudioFormat_Mono] = AL_FORMAT_MONO16;
|
||||
AudioFormat[AudioFormat_Stereo] = AL_FORMAT_STEREO16;
|
||||
|
||||
// "The presence of an enum value does not guarantee the applicability of an extension to the current context."
|
||||
if (alIsExtensionPresent("AL_EXT_MCFORMATS"))
|
||||
{
|
||||
AudioFormat[AudioFormat_Quad] = alGetEnumValue("AL_FORMAT_QUAD16");
|
||||
AudioFormat[AudioFormat_5_1] = alGetEnumValue("AL_FORMAT_51CHN16");
|
||||
AudioFormat[AudioFormat_6_1] = alGetEnumValue("AL_FORMAT_61CHN16");
|
||||
AudioFormat[AudioFormat_7_1] = alGetEnumValue("AL_FORMAT_71CHN16");
|
||||
}
|
||||
else if (alIsExtensionPresent("AL_LOKI_quadriphonic"))
|
||||
AudioFormat[AudioFormat_Quad] = alGetEnumValue("AL_FORMAT_QUAD16_LOKI");
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
||||
OpenALFunc OpenAL::LoadEntry(const char* name, bool throwException)
|
||||
{
|
||||
NazaraDebug("Unable to retrieve OpenAL version");
|
||||
s_version = 0;
|
||||
OpenALFunc entry = reinterpret_cast<OpenALFunc>(s_library.GetSymbol(name));
|
||||
if (!entry && throwException)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "failed to load \"" << name << '"';
|
||||
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
// On complète le tableau de formats
|
||||
AudioFormat[nzAudioFormat_Mono] = AL_FORMAT_MONO16;
|
||||
AudioFormat[nzAudioFormat_Stereo] = AL_FORMAT_STEREO16;
|
||||
|
||||
// "The presence of an enum value does not guarantee the applicability of an extension to the current context."
|
||||
if (alIsExtensionPresent("AL_EXT_MCFORMATS"))
|
||||
{
|
||||
AudioFormat[nzAudioFormat_Quad] = alGetEnumValue("AL_FORMAT_QUAD16");
|
||||
AudioFormat[nzAudioFormat_5_1] = alGetEnumValue("AL_FORMAT_51CHN16");
|
||||
AudioFormat[nzAudioFormat_6_1] = alGetEnumValue("AL_FORMAT_61CHN16");
|
||||
AudioFormat[nzAudioFormat_7_1] = alGetEnumValue("AL_FORMAT_71CHN16");
|
||||
}
|
||||
else if (alIsExtensionPresent("AL_LOKI_quadriphonic"))
|
||||
AudioFormat[nzAudioFormat_Quad] = alGetEnumValue("AL_FORMAT_QUAD16_LOKI");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NzOpenALFunc NzOpenAL::LoadEntry(const char* name, bool throwException)
|
||||
{
|
||||
NzOpenALFunc entry = reinterpret_cast<NzOpenALFunc>(s_library.GetSymbol(name));
|
||||
if (!entry && throwException)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << "failed to load \"" << name << '"';
|
||||
|
||||
throw std::runtime_error(oss.str());
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
// al
|
||||
NzOpenALDetail::LPALBUFFER3F alBuffer3f = nullptr;
|
||||
NzOpenALDetail::LPALBUFFER3I alBuffer3i = nullptr;
|
||||
NzOpenALDetail::LPALBUFFERDATA alBufferData = nullptr;
|
||||
NzOpenALDetail::LPALBUFFERF alBufferf = nullptr;
|
||||
NzOpenALDetail::LPALBUFFERFV alBufferfv = nullptr;
|
||||
NzOpenALDetail::LPALBUFFERI alBufferi = nullptr;
|
||||
NzOpenALDetail::LPALBUFFERIV alBufferiv = nullptr;
|
||||
NzOpenALDetail::LPALDELETEBUFFERS alDeleteBuffers = nullptr;
|
||||
NzOpenALDetail::LPALDELETESOURCES alDeleteSources = nullptr;
|
||||
NzOpenALDetail::LPALDISABLE alDisable = nullptr;
|
||||
NzOpenALDetail::LPALDISTANCEMODEL alDistanceModel = nullptr;
|
||||
NzOpenALDetail::LPALDOPPLERFACTOR alDopplerFactor = nullptr;
|
||||
NzOpenALDetail::LPALDOPPLERVELOCITY alDopplerVelocity = nullptr;
|
||||
NzOpenALDetail::LPALENABLE alEnable = nullptr;
|
||||
NzOpenALDetail::LPALGENBUFFERS alGenBuffers = nullptr;
|
||||
NzOpenALDetail::LPALGENSOURCES alGenSources = nullptr;
|
||||
NzOpenALDetail::LPALGETBOOLEAN alGetBoolean = nullptr;
|
||||
NzOpenALDetail::LPALGETBOOLEANV alGetBooleanv = nullptr;
|
||||
NzOpenALDetail::LPALGETBUFFER3F alGetBuffer3f = nullptr;
|
||||
NzOpenALDetail::LPALGETBUFFER3I alGetBuffer3i = nullptr;
|
||||
NzOpenALDetail::LPALGETBUFFERF alGetBufferf = nullptr;
|
||||
NzOpenALDetail::LPALGETBUFFERFV alGetBufferfv = nullptr;
|
||||
NzOpenALDetail::LPALGETBUFFERI alGetBufferi = nullptr;
|
||||
NzOpenALDetail::LPALGETBUFFERIV alGetBufferiv = nullptr;
|
||||
NzOpenALDetail::LPALGETDOUBLE alGetDouble = nullptr;
|
||||
NzOpenALDetail::LPALGETDOUBLEV alGetDoublev = nullptr;
|
||||
NzOpenALDetail::LPALGETENUMVALUE alGetEnumValue = nullptr;
|
||||
NzOpenALDetail::LPALGETERROR alGetError = nullptr;
|
||||
NzOpenALDetail::LPALGETFLOAT alGetFloat = nullptr;
|
||||
NzOpenALDetail::LPALGETFLOATV alGetFloatv = nullptr;
|
||||
NzOpenALDetail::LPALGETINTEGER alGetInteger = nullptr;
|
||||
NzOpenALDetail::LPALGETINTEGERV alGetIntegerv = nullptr;
|
||||
NzOpenALDetail::LPALGETLISTENER3F alGetListener3f = nullptr;
|
||||
NzOpenALDetail::LPALGETLISTENER3I alGetListener3i = nullptr;
|
||||
NzOpenALDetail::LPALGETLISTENERF alGetListenerf = nullptr;
|
||||
NzOpenALDetail::LPALGETLISTENERFV alGetListenerfv = nullptr;
|
||||
NzOpenALDetail::LPALGETLISTENERI alGetListeneri = nullptr;
|
||||
NzOpenALDetail::LPALGETLISTENERIV alGetListeneriv = nullptr;
|
||||
NzOpenALDetail::LPALGETPROCADDRESS alGetProcAddress = nullptr;
|
||||
NzOpenALDetail::LPALGETSOURCE3F alGetSource3f = nullptr;
|
||||
NzOpenALDetail::LPALGETSOURCE3I alGetSource3i = nullptr;
|
||||
NzOpenALDetail::LPALGETSOURCEF alGetSourcef = nullptr;
|
||||
NzOpenALDetail::LPALGETSOURCEFV alGetSourcefv = nullptr;
|
||||
NzOpenALDetail::LPALGETSOURCEI alGetSourcei = nullptr;
|
||||
NzOpenALDetail::LPALGETSOURCEIV alGetSourceiv = nullptr;
|
||||
NzOpenALDetail::LPALGETSTRING alGetString = nullptr;
|
||||
NzOpenALDetail::LPALISBUFFER alIsBuffer = nullptr;
|
||||
NzOpenALDetail::LPALISENABLED alIsEnabled = nullptr;
|
||||
NzOpenALDetail::LPALISEXTENSIONPRESENT alIsExtensionPresent = nullptr;
|
||||
NzOpenALDetail::LPALISSOURCE alIsSource = nullptr;
|
||||
NzOpenALDetail::LPALLISTENER3F alListener3f = nullptr;
|
||||
NzOpenALDetail::LPALLISTENER3I alListener3i = nullptr;
|
||||
NzOpenALDetail::LPALLISTENERF alListenerf = nullptr;
|
||||
NzOpenALDetail::LPALLISTENERFV alListenerfv = nullptr;
|
||||
NzOpenALDetail::LPALLISTENERI alListeneri = nullptr;
|
||||
NzOpenALDetail::LPALLISTENERIV alListeneriv = nullptr;
|
||||
NzOpenALDetail::LPALSOURCE3F alSource3f = nullptr;
|
||||
NzOpenALDetail::LPALSOURCE3I alSource3i = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEF alSourcef = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEFV alSourcefv = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEI alSourcei = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEIV alSourceiv = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEPAUSE alSourcePause = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEPAUSEV alSourcePausev = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEPLAY alSourcePlay = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEPLAYV alSourcePlayv = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEREWIND alSourceRewind = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEREWINDV alSourceRewindv = nullptr;
|
||||
NzOpenALDetail::LPALSOURCESTOP alSourceStop = nullptr;
|
||||
NzOpenALDetail::LPALSOURCESTOPV alSourceStopv = nullptr;
|
||||
NzOpenALDetail::LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers = nullptr;
|
||||
NzOpenALDetail::LPALSPEEDOFSOUND alSpeedOfSound = nullptr;
|
||||
OpenALDetail::LPALBUFFER3F alBuffer3f = nullptr;
|
||||
OpenALDetail::LPALBUFFER3I alBuffer3i = nullptr;
|
||||
OpenALDetail::LPALBUFFERDATA alBufferData = nullptr;
|
||||
OpenALDetail::LPALBUFFERF alBufferf = nullptr;
|
||||
OpenALDetail::LPALBUFFERFV alBufferfv = nullptr;
|
||||
OpenALDetail::LPALBUFFERI alBufferi = nullptr;
|
||||
OpenALDetail::LPALBUFFERIV alBufferiv = nullptr;
|
||||
OpenALDetail::LPALDELETEBUFFERS alDeleteBuffers = nullptr;
|
||||
OpenALDetail::LPALDELETESOURCES alDeleteSources = nullptr;
|
||||
OpenALDetail::LPALDISABLE alDisable = nullptr;
|
||||
OpenALDetail::LPALDISTANCEMODEL alDistanceModel = nullptr;
|
||||
OpenALDetail::LPALDOPPLERFACTOR alDopplerFactor = nullptr;
|
||||
OpenALDetail::LPALDOPPLERVELOCITY alDopplerVelocity = nullptr;
|
||||
OpenALDetail::LPALENABLE alEnable = nullptr;
|
||||
OpenALDetail::LPALGENBUFFERS alGenBuffers = nullptr;
|
||||
OpenALDetail::LPALGENSOURCES alGenSources = nullptr;
|
||||
OpenALDetail::LPALGETBOOLEAN alGetBoolean = nullptr;
|
||||
OpenALDetail::LPALGETBOOLEANV alGetBooleanv = nullptr;
|
||||
OpenALDetail::LPALGETBUFFER3F alGetBuffer3f = nullptr;
|
||||
OpenALDetail::LPALGETBUFFER3I alGetBuffer3i = nullptr;
|
||||
OpenALDetail::LPALGETBUFFERF alGetBufferf = nullptr;
|
||||
OpenALDetail::LPALGETBUFFERFV alGetBufferfv = nullptr;
|
||||
OpenALDetail::LPALGETBUFFERI alGetBufferi = nullptr;
|
||||
OpenALDetail::LPALGETBUFFERIV alGetBufferiv = nullptr;
|
||||
OpenALDetail::LPALGETDOUBLE alGetDouble = nullptr;
|
||||
OpenALDetail::LPALGETDOUBLEV alGetDoublev = nullptr;
|
||||
OpenALDetail::LPALGETENUMVALUE alGetEnumValue = nullptr;
|
||||
OpenALDetail::LPALGETERROR alGetError = nullptr;
|
||||
OpenALDetail::LPALGETFLOAT alGetFloat = nullptr;
|
||||
OpenALDetail::LPALGETFLOATV alGetFloatv = nullptr;
|
||||
OpenALDetail::LPALGETINTEGER alGetInteger = nullptr;
|
||||
OpenALDetail::LPALGETINTEGERV alGetIntegerv = nullptr;
|
||||
OpenALDetail::LPALGETLISTENER3F alGetListener3f = nullptr;
|
||||
OpenALDetail::LPALGETLISTENER3I alGetListener3i = nullptr;
|
||||
OpenALDetail::LPALGETLISTENERF alGetListenerf = nullptr;
|
||||
OpenALDetail::LPALGETLISTENERFV alGetListenerfv = nullptr;
|
||||
OpenALDetail::LPALGETLISTENERI alGetListeneri = nullptr;
|
||||
OpenALDetail::LPALGETLISTENERIV alGetListeneriv = nullptr;
|
||||
OpenALDetail::LPALGETPROCADDRESS alGetProcAddress = nullptr;
|
||||
OpenALDetail::LPALGETSOURCE3F alGetSource3f = nullptr;
|
||||
OpenALDetail::LPALGETSOURCE3I alGetSource3i = nullptr;
|
||||
OpenALDetail::LPALGETSOURCEF alGetSourcef = nullptr;
|
||||
OpenALDetail::LPALGETSOURCEFV alGetSourcefv = nullptr;
|
||||
OpenALDetail::LPALGETSOURCEI alGetSourcei = nullptr;
|
||||
OpenALDetail::LPALGETSOURCEIV alGetSourceiv = nullptr;
|
||||
OpenALDetail::LPALGETSTRING alGetString = nullptr;
|
||||
OpenALDetail::LPALISBUFFER alIsBuffer = nullptr;
|
||||
OpenALDetail::LPALISENABLED alIsEnabled = nullptr;
|
||||
OpenALDetail::LPALISEXTENSIONPRESENT alIsExtensionPresent = nullptr;
|
||||
OpenALDetail::LPALISSOURCE alIsSource = nullptr;
|
||||
OpenALDetail::LPALLISTENER3F alListener3f = nullptr;
|
||||
OpenALDetail::LPALLISTENER3I alListener3i = nullptr;
|
||||
OpenALDetail::LPALLISTENERF alListenerf = nullptr;
|
||||
OpenALDetail::LPALLISTENERFV alListenerfv = nullptr;
|
||||
OpenALDetail::LPALLISTENERI alListeneri = nullptr;
|
||||
OpenALDetail::LPALLISTENERIV alListeneriv = nullptr;
|
||||
OpenALDetail::LPALSOURCE3F alSource3f = nullptr;
|
||||
OpenALDetail::LPALSOURCE3I alSource3i = nullptr;
|
||||
OpenALDetail::LPALSOURCEF alSourcef = nullptr;
|
||||
OpenALDetail::LPALSOURCEFV alSourcefv = nullptr;
|
||||
OpenALDetail::LPALSOURCEI alSourcei = nullptr;
|
||||
OpenALDetail::LPALSOURCEIV alSourceiv = nullptr;
|
||||
OpenALDetail::LPALSOURCEPAUSE alSourcePause = nullptr;
|
||||
OpenALDetail::LPALSOURCEPAUSEV alSourcePausev = nullptr;
|
||||
OpenALDetail::LPALSOURCEPLAY alSourcePlay = nullptr;
|
||||
OpenALDetail::LPALSOURCEPLAYV alSourcePlayv = nullptr;
|
||||
OpenALDetail::LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers = nullptr;
|
||||
OpenALDetail::LPALSOURCEREWIND alSourceRewind = nullptr;
|
||||
OpenALDetail::LPALSOURCEREWINDV alSourceRewindv = nullptr;
|
||||
OpenALDetail::LPALSOURCESTOP alSourceStop = nullptr;
|
||||
OpenALDetail::LPALSOURCESTOPV alSourceStopv = nullptr;
|
||||
OpenALDetail::LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers = nullptr;
|
||||
OpenALDetail::LPALSPEEDOFSOUND alSpeedOfSound = nullptr;
|
||||
|
||||
// alc
|
||||
NzOpenALDetail::LPALCCAPTURECLOSEDEVICE alcCaptureCloseDevice = nullptr;
|
||||
NzOpenALDetail::LPALCCAPTUREOPENDEVICE alcCaptureOpenDevice = nullptr;
|
||||
NzOpenALDetail::LPALCCAPTURESAMPLES alcCaptureSamples = nullptr;
|
||||
NzOpenALDetail::LPALCCAPTURESTART alcCaptureStart = nullptr;
|
||||
NzOpenALDetail::LPALCCAPTURESTOP alcCaptureStop = nullptr;
|
||||
NzOpenALDetail::LPALCCLOSEDEVICE alcCloseDevice = nullptr;
|
||||
NzOpenALDetail::LPALCCREATECONTEXT alcCreateContext = nullptr;
|
||||
NzOpenALDetail::LPALCDESTROYCONTEXT alcDestroyContext = nullptr;
|
||||
NzOpenALDetail::LPALCGETCONTEXTSDEVICE alcGetContextsDevice = nullptr;
|
||||
NzOpenALDetail::LPALCGETCURRENTCONTEXT alcGetCurrentContext = nullptr;
|
||||
NzOpenALDetail::LPALCGETENUMVALUE alcGetEnumValue = nullptr;
|
||||
NzOpenALDetail::LPALCGETERROR alcGetError = nullptr;
|
||||
NzOpenALDetail::LPALCGETINTEGERV alcGetIntegerv = nullptr;
|
||||
NzOpenALDetail::LPALCGETPROCADDRESS alcGetProcAddress = nullptr;
|
||||
NzOpenALDetail::LPALCGETSTRING alcGetString = nullptr;
|
||||
NzOpenALDetail::LPALCISEXTENSIONPRESENT alcIsExtensionPresent = nullptr;
|
||||
NzOpenALDetail::LPALCMAKECONTEXTCURRENT alcMakeContextCurrent = nullptr;
|
||||
NzOpenALDetail::LPALCOPENDEVICE alcOpenDevice = nullptr;
|
||||
NzOpenALDetail::LPALCPROCESSCONTEXT alcProcessContext = nullptr;
|
||||
NzOpenALDetail::LPALCSUSPENDCONTEXT alcSuspendContext = nullptr;
|
||||
OpenALDetail::LPALCCAPTURECLOSEDEVICE alcCaptureCloseDevice = nullptr;
|
||||
OpenALDetail::LPALCCAPTUREOPENDEVICE alcCaptureOpenDevice = nullptr;
|
||||
OpenALDetail::LPALCCAPTURESAMPLES alcCaptureSamples = nullptr;
|
||||
OpenALDetail::LPALCCAPTURESTART alcCaptureStart = nullptr;
|
||||
OpenALDetail::LPALCCAPTURESTOP alcCaptureStop = nullptr;
|
||||
OpenALDetail::LPALCCLOSEDEVICE alcCloseDevice = nullptr;
|
||||
OpenALDetail::LPALCCREATECONTEXT alcCreateContext = nullptr;
|
||||
OpenALDetail::LPALCDESTROYCONTEXT alcDestroyContext = nullptr;
|
||||
OpenALDetail::LPALCGETCONTEXTSDEVICE alcGetContextsDevice = nullptr;
|
||||
OpenALDetail::LPALCGETCURRENTCONTEXT alcGetCurrentContext = nullptr;
|
||||
OpenALDetail::LPALCGETENUMVALUE alcGetEnumValue = nullptr;
|
||||
OpenALDetail::LPALCGETERROR alcGetError = nullptr;
|
||||
OpenALDetail::LPALCGETINTEGERV alcGetIntegerv = nullptr;
|
||||
OpenALDetail::LPALCGETPROCADDRESS alcGetProcAddress = nullptr;
|
||||
OpenALDetail::LPALCGETSTRING alcGetString = nullptr;
|
||||
OpenALDetail::LPALCISEXTENSIONPRESENT alcIsExtensionPresent = nullptr;
|
||||
OpenALDetail::LPALCMAKECONTEXTCURRENT alcMakeContextCurrent = nullptr;
|
||||
OpenALDetail::LPALCOPENDEVICE alcOpenDevice = nullptr;
|
||||
OpenALDetail::LPALCPROCESSCONTEXT alcProcessContext = nullptr;
|
||||
OpenALDetail::LPALCSUSPENDCONTEXT alcSuspendContext = nullptr;
|
||||
|
||||
@@ -12,162 +12,165 @@
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
NzSound::NzSound(const NzSoundBuffer* soundBuffer)
|
||||
namespace Nz
|
||||
{
|
||||
SetBuffer(soundBuffer);
|
||||
}
|
||||
|
||||
NzSound::NzSound(const NzSound& sound) :
|
||||
NzSoundEmitter(sound)
|
||||
{
|
||||
SetBuffer(sound.m_buffer);
|
||||
}
|
||||
|
||||
NzSound::~NzSound()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
void NzSound::EnableLooping(bool loop)
|
||||
{
|
||||
alSourcei(m_source, AL_LOOPING, loop);
|
||||
}
|
||||
|
||||
const NzSoundBuffer* NzSound::GetBuffer() const
|
||||
{
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
nzUInt32 NzSound::GetDuration() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_buffer)
|
||||
Sound::Sound(const SoundBuffer* soundBuffer)
|
||||
{
|
||||
NazaraError("Invalid sound buffer");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_buffer->GetDuration();
|
||||
}
|
||||
|
||||
nzUInt32 NzSound::GetPlayingOffset() const
|
||||
{
|
||||
ALfloat seconds = -1.f;
|
||||
alGetSourcef(m_source, AL_SEC_OFFSET, &seconds);
|
||||
|
||||
return static_cast<nzUInt32>(seconds*1000);
|
||||
}
|
||||
|
||||
nzSoundStatus NzSound::GetStatus() const
|
||||
{
|
||||
return GetInternalStatus();
|
||||
}
|
||||
|
||||
bool NzSound::IsLooping() const
|
||||
{
|
||||
ALint loop;
|
||||
alGetSourcei(m_source, AL_LOOPING, &loop);
|
||||
|
||||
return loop != AL_FALSE;
|
||||
}
|
||||
|
||||
bool NzSound::IsPlayable() const
|
||||
{
|
||||
return m_buffer != nullptr;
|
||||
}
|
||||
|
||||
bool NzSound::IsPlaying() const
|
||||
{
|
||||
return GetStatus() == nzSoundStatus_Playing;
|
||||
}
|
||||
|
||||
bool NzSound::LoadFromFile(const NzString& filePath, const NzSoundBufferParams& params)
|
||||
{
|
||||
NzSoundBufferRef buffer = NzSoundBuffer::New();
|
||||
if (!buffer->LoadFromFile(filePath, params))
|
||||
{
|
||||
NazaraError("Failed to load buffer from file (" + filePath + ')');
|
||||
return false;
|
||||
SetBuffer(soundBuffer);
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzSound::LoadFromMemory(const void* data, std::size_t size, const NzSoundBufferParams& params)
|
||||
{
|
||||
NzSoundBufferRef buffer = NzSoundBuffer::New();
|
||||
if (!buffer->LoadFromMemory(data, size, params))
|
||||
Sound::Sound(const Sound& sound) :
|
||||
SoundEmitter(sound)
|
||||
{
|
||||
NazaraError("Failed to load buffer from memory (" + NzString::Pointer(data) + ')');
|
||||
return false;
|
||||
SetBuffer(sound.m_buffer);
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzSound::LoadFromStream(NzInputStream& stream, const NzSoundBufferParams& params)
|
||||
{
|
||||
NzSoundBufferRef buffer = NzSoundBuffer::New();
|
||||
if (!buffer->LoadFromStream(stream, params))
|
||||
Sound::~Sound()
|
||||
{
|
||||
NazaraError("Failed to load buffer from stream");
|
||||
return false;
|
||||
Stop();
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzSound::Pause()
|
||||
{
|
||||
alSourcePause(m_source);
|
||||
}
|
||||
|
||||
void NzSound::Play()
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_buffer)
|
||||
void Sound::EnableLooping(bool loop)
|
||||
{
|
||||
NazaraError("Invalid sound buffer");
|
||||
return;
|
||||
alSourcei(m_source, AL_LOOPING, loop);
|
||||
}
|
||||
#endif
|
||||
|
||||
alSourcePlay(m_source);
|
||||
}
|
||||
|
||||
void NzSound::SetBuffer(const NzSoundBuffer* buffer)
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (buffer && !buffer->IsValid())
|
||||
const SoundBuffer* Sound::GetBuffer() const
|
||||
{
|
||||
NazaraError("Invalid sound buffer");
|
||||
return;
|
||||
return m_buffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_buffer == buffer)
|
||||
return;
|
||||
UInt32 Sound::GetDuration() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_buffer)
|
||||
{
|
||||
NazaraError("Invalid sound buffer");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
Stop();
|
||||
return m_buffer->GetDuration();
|
||||
}
|
||||
|
||||
m_buffer = buffer;
|
||||
UInt32 Sound::GetPlayingOffset() const
|
||||
{
|
||||
ALfloat seconds = -1.f;
|
||||
alGetSourcef(m_source, AL_SEC_OFFSET, &seconds);
|
||||
|
||||
if (m_buffer)
|
||||
alSourcei(m_source, AL_BUFFER, m_buffer->GetOpenALBuffer());
|
||||
else
|
||||
alSourcei(m_source, AL_BUFFER, AL_NONE);
|
||||
}
|
||||
|
||||
void NzSound::SetPlayingOffset(nzUInt32 offset)
|
||||
{
|
||||
alSourcef(m_source, AL_SEC_OFFSET, offset/1000.f);
|
||||
}
|
||||
|
||||
void NzSound::Stop()
|
||||
{
|
||||
alSourceStop(m_source);
|
||||
return static_cast<UInt32>(seconds*1000);
|
||||
}
|
||||
|
||||
SoundStatus Sound::GetStatus() const
|
||||
{
|
||||
return GetInternalStatus();
|
||||
}
|
||||
|
||||
bool Sound::IsLooping() const
|
||||
{
|
||||
ALint loop;
|
||||
alGetSourcei(m_source, AL_LOOPING, &loop);
|
||||
|
||||
return loop != AL_FALSE;
|
||||
}
|
||||
|
||||
bool Sound::IsPlayable() const
|
||||
{
|
||||
return m_buffer != nullptr;
|
||||
}
|
||||
|
||||
bool Sound::IsPlaying() const
|
||||
{
|
||||
return GetStatus() == SoundStatus_Playing;
|
||||
}
|
||||
|
||||
bool Sound::LoadFromFile(const String& filePath, const SoundBufferParams& params)
|
||||
{
|
||||
SoundBufferRef buffer = SoundBuffer::New();
|
||||
if (!buffer->LoadFromFile(filePath, params))
|
||||
{
|
||||
NazaraError("Failed to load buffer from file (" + filePath + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sound::LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params)
|
||||
{
|
||||
SoundBufferRef buffer = SoundBuffer::New();
|
||||
if (!buffer->LoadFromMemory(data, size, params))
|
||||
{
|
||||
NazaraError("Failed to load buffer from memory (" + String::Pointer(data) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sound::LoadFromStream(Stream& stream, const SoundBufferParams& params)
|
||||
{
|
||||
SoundBufferRef buffer = SoundBuffer::New();
|
||||
if (!buffer->LoadFromStream(stream, params))
|
||||
{
|
||||
NazaraError("Failed to load buffer from stream");
|
||||
return false;
|
||||
}
|
||||
|
||||
SetBuffer(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sound::Pause()
|
||||
{
|
||||
alSourcePause(m_source);
|
||||
}
|
||||
|
||||
void Sound::Play()
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_buffer)
|
||||
{
|
||||
NazaraError("Invalid sound buffer");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
alSourcePlay(m_source);
|
||||
}
|
||||
|
||||
void Sound::SetBuffer(const SoundBuffer* buffer)
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (buffer && !buffer->IsValid())
|
||||
{
|
||||
NazaraError("Invalid sound buffer");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_buffer == buffer)
|
||||
return;
|
||||
|
||||
Stop();
|
||||
|
||||
m_buffer = buffer;
|
||||
|
||||
if (m_buffer)
|
||||
alSourcei(m_source, AL_BUFFER, m_buffer->GetOpenALBuffer());
|
||||
else
|
||||
alSourcei(m_source, AL_BUFFER, AL_NONE);
|
||||
}
|
||||
|
||||
void Sound::SetPlayingOffset(UInt32 offset)
|
||||
{
|
||||
alSourcef(m_source, AL_SEC_OFFSET, offset/1000.f);
|
||||
}
|
||||
|
||||
void Sound::Stop()
|
||||
{
|
||||
alSourceStop(m_source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,243 +14,246 @@
|
||||
|
||||
///FIXME: Adapter la création
|
||||
|
||||
bool NzSoundBufferParams::IsValid() const
|
||||
namespace Nz
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NzSoundBufferImpl
|
||||
{
|
||||
ALuint buffer;
|
||||
nzAudioFormat format;
|
||||
nzUInt32 duration;
|
||||
std::unique_ptr<nzInt16[]> samples;
|
||||
unsigned int sampleCount;
|
||||
unsigned int sampleRate;
|
||||
};
|
||||
|
||||
NzSoundBuffer::NzSoundBuffer(nzAudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const nzInt16* samples)
|
||||
{
|
||||
Create(format, sampleCount, sampleRate, samples);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
bool SoundBufferParams::IsValid() const
|
||||
{
|
||||
NazaraError("Failed to create sound buffer");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NzSoundBuffer::~NzSoundBuffer()
|
||||
{
|
||||
OnSoundBufferRelease(this);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::Create(nzAudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const nzInt16* samples)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!IsFormatSupported(format))
|
||||
{
|
||||
NazaraError("Audio format is not supported");
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sampleCount == 0)
|
||||
struct SoundBufferImpl
|
||||
{
|
||||
NazaraError("Sample rate must be different from zero");
|
||||
return false;
|
||||
ALuint buffer;
|
||||
AudioFormat format;
|
||||
UInt32 duration;
|
||||
std::unique_ptr<Int16[]> samples;
|
||||
UInt32 sampleCount;
|
||||
UInt32 sampleRate;
|
||||
};
|
||||
|
||||
SoundBuffer::SoundBuffer(AudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const Int16* samples)
|
||||
{
|
||||
Create(format, sampleCount, sampleRate, samples);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Failed to create sound buffer");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (sampleRate == 0)
|
||||
SoundBuffer::~SoundBuffer()
|
||||
{
|
||||
NazaraError("Sample rate must be different from zero");
|
||||
return false;
|
||||
OnSoundBufferRelease(this);
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
if (!samples)
|
||||
bool SoundBuffer::Create(AudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const Int16* samples)
|
||||
{
|
||||
NazaraError("Invalid sample source");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
Destroy();
|
||||
|
||||
// On vide le stack d'erreurs
|
||||
while (alGetError() != AL_NO_ERROR);
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!IsFormatSupported(format))
|
||||
{
|
||||
NazaraError("Audio format is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
ALuint buffer;
|
||||
alGenBuffers(1, &buffer);
|
||||
if (sampleCount == 0)
|
||||
{
|
||||
NazaraError("Sample rate must be different from zero");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
NazaraError("Failed to create OpenAL buffer");
|
||||
return false;
|
||||
if (sampleRate == 0)
|
||||
{
|
||||
NazaraError("Sample rate must be different from zero");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!samples)
|
||||
{
|
||||
NazaraError("Invalid sample source");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// On vide le stack d'erreurs
|
||||
while (alGetError() != AL_NO_ERROR);
|
||||
|
||||
ALuint buffer;
|
||||
alGenBuffers(1, &buffer);
|
||||
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
NazaraError("Failed to create OpenAL buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
alBufferData(buffer, OpenAL::AudioFormat[format], samples, sampleCount*sizeof(Int16), sampleRate);
|
||||
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
alDeleteBuffers(1, &buffer);
|
||||
|
||||
NazaraError("Failed to set OpenAL buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = new SoundBufferImpl;
|
||||
m_impl->buffer = buffer;
|
||||
m_impl->duration = (1000*sampleCount / (format * sampleRate));
|
||||
m_impl->format = format;
|
||||
m_impl->sampleCount = sampleCount;
|
||||
m_impl->sampleRate = sampleRate;
|
||||
m_impl->samples.reset(new Int16[sampleCount]);
|
||||
std::memcpy(&m_impl->samples[0], samples, sampleCount*sizeof(Int16));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
alBufferData(buffer, NzOpenAL::AudioFormat[format], samples, sampleCount*sizeof(nzInt16), sampleRate);
|
||||
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
void SoundBuffer::Destroy()
|
||||
{
|
||||
alDeleteBuffers(1, &buffer);
|
||||
if (m_impl)
|
||||
{
|
||||
OnSoundBufferDestroy(this);
|
||||
|
||||
NazaraError("Failed to set OpenAL buffer");
|
||||
return false;
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
m_impl = new NzSoundBufferImpl;
|
||||
m_impl->buffer = buffer;
|
||||
m_impl->duration = (1000*sampleCount / (format * sampleRate));
|
||||
m_impl->format = format;
|
||||
m_impl->sampleCount = sampleCount;
|
||||
m_impl->sampleRate = sampleRate;
|
||||
m_impl->samples.reset(new nzInt16[sampleCount]);
|
||||
std::memcpy(&m_impl->samples[0], samples, sampleCount*sizeof(nzInt16));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzSoundBuffer::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
UInt32 SoundBuffer::GetDuration() const
|
||||
{
|
||||
OnSoundBufferDestroy(this);
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nzUInt32 NzSoundBuffer::GetDuration() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->duration;
|
||||
}
|
||||
|
||||
nzAudioFormat NzSoundBuffer::GetFormat() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return nzAudioFormat_Unknown;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->format;
|
||||
}
|
||||
|
||||
const nzInt16* NzSoundBuffer::GetSamples() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->samples.get();
|
||||
}
|
||||
|
||||
unsigned int NzSoundBuffer::GetSampleCount() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->sampleCount;
|
||||
}
|
||||
|
||||
unsigned int NzSoundBuffer::GetSampleRate() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->sampleRate;
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::IsValid() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::LoadFromFile(const NzString& filePath, const NzSoundBufferParams& params)
|
||||
{
|
||||
return NzSoundBufferLoader::LoadFromFile(this, filePath, params);
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::LoadFromMemory(const void* data, std::size_t size, const NzSoundBufferParams& params)
|
||||
{
|
||||
return NzSoundBufferLoader::LoadFromMemory(this, data, size, params);
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::LoadFromStream(NzInputStream& stream, const NzSoundBufferParams& params)
|
||||
{
|
||||
return NzSoundBufferLoader::LoadFromStream(this, stream, params);
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::IsFormatSupported(nzAudioFormat format)
|
||||
{
|
||||
return NzAudio::IsFormatSupported(format);
|
||||
}
|
||||
|
||||
unsigned int NzSoundBuffer::GetOpenALBuffer() const
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraInternalError("Sound buffer not created");
|
||||
return AL_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->buffer;
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::Initialize()
|
||||
{
|
||||
if (!NzSoundBufferLibrary::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise library");
|
||||
return false;
|
||||
return m_impl->duration;
|
||||
}
|
||||
|
||||
if (!NzSoundBufferManager::Initialize())
|
||||
AudioFormat SoundBuffer::GetFormat() const
|
||||
{
|
||||
NazaraError("Failed to initialise manager");
|
||||
return false;
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return AudioFormat_Unknown;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->format;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
const Int16* SoundBuffer::GetSamples() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void NzSoundBuffer::Uninitialize()
|
||||
{
|
||||
NzSoundBufferManager::Uninitialize();
|
||||
NzSoundBufferLibrary::Uninitialize();
|
||||
}
|
||||
return m_impl->samples.get();
|
||||
}
|
||||
|
||||
NzSoundBufferLibrary::LibraryMap NzSoundBuffer::s_library;
|
||||
NzSoundBufferLoader::LoaderList NzSoundBuffer::s_loaders;
|
||||
NzSoundBufferManager::ManagerMap NzSoundBuffer::s_managerMap;
|
||||
NzSoundBufferManager::ManagerParams NzSoundBuffer::s_managerParameters;
|
||||
unsigned int SoundBuffer::GetSampleCount() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->sampleCount;
|
||||
}
|
||||
|
||||
unsigned int SoundBuffer::GetSampleRate() const
|
||||
{
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Sound buffer not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->sampleRate;
|
||||
}
|
||||
|
||||
bool SoundBuffer::IsValid() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
bool SoundBuffer::LoadFromFile(const String& filePath, const SoundBufferParams& params)
|
||||
{
|
||||
return SoundBufferLoader::LoadFromFile(this, filePath, params);
|
||||
}
|
||||
|
||||
bool SoundBuffer::LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params)
|
||||
{
|
||||
return SoundBufferLoader::LoadFromMemory(this, data, size, params);
|
||||
}
|
||||
|
||||
bool SoundBuffer::LoadFromStream(Stream& stream, const SoundBufferParams& params)
|
||||
{
|
||||
return SoundBufferLoader::LoadFromStream(this, stream, params);
|
||||
}
|
||||
|
||||
bool SoundBuffer::IsFormatSupported(AudioFormat format)
|
||||
{
|
||||
return Audio::IsFormatSupported(format);
|
||||
}
|
||||
|
||||
unsigned int SoundBuffer::GetOpenALBuffer() const
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraInternalError("Sound buffer not created");
|
||||
return AL_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->buffer;
|
||||
}
|
||||
|
||||
bool SoundBuffer::Initialize()
|
||||
{
|
||||
if (!SoundBufferLibrary::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise library");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SoundBufferManager::Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialise manager");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SoundBuffer::Uninitialize()
|
||||
{
|
||||
SoundBufferManager::Uninitialize();
|
||||
SoundBufferLibrary::Uninitialize();
|
||||
}
|
||||
|
||||
SoundBufferLibrary::LibraryMap SoundBuffer::s_library;
|
||||
SoundBufferLoader::LoaderList SoundBuffer::s_loaders;
|
||||
SoundBufferManager::ManagerMap SoundBuffer::s_managerMap;
|
||||
SoundBufferManager::ManagerParams SoundBuffer::s_managerParameters;
|
||||
}
|
||||
|
||||
@@ -9,148 +9,151 @@
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
NzSoundEmitter::NzSoundEmitter()
|
||||
namespace Nz
|
||||
{
|
||||
alGenSources(1, &m_source);
|
||||
}
|
||||
|
||||
NzSoundEmitter::NzSoundEmitter(const NzSoundEmitter& emitter)
|
||||
{
|
||||
alGenSources(1, &m_source);
|
||||
|
||||
SetAttenuation(emitter.GetAttenuation());
|
||||
SetMinDistance(emitter.GetMinDistance());
|
||||
SetPitch(emitter.GetPitch());
|
||||
// Pas de copie de position ou de vitesse
|
||||
SetVolume(emitter.GetVolume());
|
||||
}
|
||||
|
||||
NzSoundEmitter::~NzSoundEmitter()
|
||||
{
|
||||
alDeleteSources(1, &m_source);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::EnableSpatialization(bool spatialization)
|
||||
{
|
||||
alSourcei(m_source, AL_SOURCE_RELATIVE, !spatialization);
|
||||
}
|
||||
|
||||
float NzSoundEmitter::GetAttenuation() const
|
||||
{
|
||||
ALfloat attenuation;
|
||||
alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &attenuation);
|
||||
|
||||
return attenuation;
|
||||
}
|
||||
|
||||
float NzSoundEmitter::GetMinDistance() const
|
||||
{
|
||||
ALfloat distance;
|
||||
alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &distance);
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
float NzSoundEmitter::GetPitch() const
|
||||
{
|
||||
ALfloat pitch;
|
||||
alGetSourcef(m_source, AL_PITCH, &pitch);
|
||||
|
||||
return pitch;
|
||||
}
|
||||
|
||||
NzVector3f NzSoundEmitter::GetPosition() const
|
||||
{
|
||||
NzVector3f position;
|
||||
alGetSourcefv(m_source, AL_POSITION, position);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
NzVector3f NzSoundEmitter::GetVelocity() const
|
||||
{
|
||||
NzVector3f velocity;
|
||||
alGetSourcefv(m_source, AL_VELOCITY, velocity);
|
||||
|
||||
return velocity;
|
||||
}
|
||||
|
||||
float NzSoundEmitter::GetVolume() const
|
||||
{
|
||||
ALfloat gain;
|
||||
alGetSourcef(m_source, AL_GAIN, &gain);
|
||||
|
||||
return gain * 100.f;
|
||||
}
|
||||
|
||||
bool NzSoundEmitter::IsSpatialized() const
|
||||
{
|
||||
ALint relative;
|
||||
alGetSourcei(m_source, AL_SOURCE_RELATIVE, &relative);
|
||||
|
||||
return relative == AL_FALSE;
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetAttenuation(float attenuation)
|
||||
{
|
||||
alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetMinDistance(float minDistance)
|
||||
{
|
||||
alSourcef(m_source, AL_REFERENCE_DISTANCE, minDistance);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetPitch(float pitch)
|
||||
{
|
||||
alSourcef(m_source, AL_PITCH, pitch);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetPosition(const NzVector3f& position)
|
||||
{
|
||||
alSourcefv(m_source, AL_POSITION, position);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetPosition(float x, float y, float z)
|
||||
{
|
||||
alSource3f(m_source, AL_POSITION, x, y, z);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetVelocity(const NzVector3f& velocity)
|
||||
{
|
||||
alSourcefv(m_source, AL_VELOCITY, velocity);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetVelocity(float velX, float velY, float velZ)
|
||||
{
|
||||
alSource3f(m_source, AL_VELOCITY, velX, velY, velZ);
|
||||
}
|
||||
|
||||
void NzSoundEmitter::SetVolume(float volume)
|
||||
{
|
||||
alSourcef(m_source, AL_GAIN, volume*0.01f);
|
||||
}
|
||||
|
||||
nzSoundStatus NzSoundEmitter::GetInternalStatus() const
|
||||
{
|
||||
ALint state;
|
||||
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
|
||||
|
||||
switch (state)
|
||||
SoundEmitter::SoundEmitter()
|
||||
{
|
||||
case AL_INITIAL:
|
||||
case AL_STOPPED:
|
||||
return nzSoundStatus_Stopped;
|
||||
|
||||
case AL_PAUSED:
|
||||
return nzSoundStatus_Paused;
|
||||
|
||||
case AL_PLAYING:
|
||||
return nzSoundStatus_Playing;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Source state unrecognized");
|
||||
alGenSources(1, &m_source);
|
||||
}
|
||||
|
||||
return nzSoundStatus_Stopped;
|
||||
SoundEmitter::SoundEmitter(const SoundEmitter& emitter)
|
||||
{
|
||||
alGenSources(1, &m_source);
|
||||
|
||||
SetAttenuation(emitter.GetAttenuation());
|
||||
SetMinDistance(emitter.GetMinDistance());
|
||||
SetPitch(emitter.GetPitch());
|
||||
// Pas de copie de position ou de vitesse
|
||||
SetVolume(emitter.GetVolume());
|
||||
}
|
||||
|
||||
SoundEmitter::~SoundEmitter()
|
||||
{
|
||||
alDeleteSources(1, &m_source);
|
||||
}
|
||||
|
||||
void SoundEmitter::EnableSpatialization(bool spatialization)
|
||||
{
|
||||
alSourcei(m_source, AL_SOURCE_RELATIVE, !spatialization);
|
||||
}
|
||||
|
||||
float SoundEmitter::GetAttenuation() const
|
||||
{
|
||||
ALfloat attenuation;
|
||||
alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &attenuation);
|
||||
|
||||
return attenuation;
|
||||
}
|
||||
|
||||
float SoundEmitter::GetMinDistance() const
|
||||
{
|
||||
ALfloat distance;
|
||||
alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &distance);
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
float SoundEmitter::GetPitch() const
|
||||
{
|
||||
ALfloat pitch;
|
||||
alGetSourcef(m_source, AL_PITCH, &pitch);
|
||||
|
||||
return pitch;
|
||||
}
|
||||
|
||||
Vector3f SoundEmitter::GetPosition() const
|
||||
{
|
||||
Vector3f position;
|
||||
alGetSourcefv(m_source, AL_POSITION, position);
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
Vector3f SoundEmitter::GetVelocity() const
|
||||
{
|
||||
Vector3f velocity;
|
||||
alGetSourcefv(m_source, AL_VELOCITY, velocity);
|
||||
|
||||
return velocity;
|
||||
}
|
||||
|
||||
float SoundEmitter::GetVolume() const
|
||||
{
|
||||
ALfloat gain;
|
||||
alGetSourcef(m_source, AL_GAIN, &gain);
|
||||
|
||||
return gain * 100.f;
|
||||
}
|
||||
|
||||
bool SoundEmitter::IsSpatialized() const
|
||||
{
|
||||
ALint relative;
|
||||
alGetSourcei(m_source, AL_SOURCE_RELATIVE, &relative);
|
||||
|
||||
return relative == AL_FALSE;
|
||||
}
|
||||
|
||||
void SoundEmitter::SetAttenuation(float attenuation)
|
||||
{
|
||||
alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation);
|
||||
}
|
||||
|
||||
void SoundEmitter::SetMinDistance(float minDistance)
|
||||
{
|
||||
alSourcef(m_source, AL_REFERENCE_DISTANCE, minDistance);
|
||||
}
|
||||
|
||||
void SoundEmitter::SetPitch(float pitch)
|
||||
{
|
||||
alSourcef(m_source, AL_PITCH, pitch);
|
||||
}
|
||||
|
||||
void SoundEmitter::SetPosition(const Vector3f& position)
|
||||
{
|
||||
alSourcefv(m_source, AL_POSITION, position);
|
||||
}
|
||||
|
||||
void SoundEmitter::SetPosition(float x, float y, float z)
|
||||
{
|
||||
alSource3f(m_source, AL_POSITION, x, y, z);
|
||||
}
|
||||
|
||||
void SoundEmitter::SetVelocity(const Vector3f& velocity)
|
||||
{
|
||||
alSourcefv(m_source, AL_VELOCITY, velocity);
|
||||
}
|
||||
|
||||
void SoundEmitter::SetVelocity(float velX, float velY, float velZ)
|
||||
{
|
||||
alSource3f(m_source, AL_VELOCITY, velX, velY, velZ);
|
||||
}
|
||||
|
||||
void SoundEmitter::SetVolume(float volume)
|
||||
{
|
||||
alSourcef(m_source, AL_GAIN, volume*0.01f);
|
||||
}
|
||||
|
||||
SoundStatus SoundEmitter::GetInternalStatus() const
|
||||
{
|
||||
ALint state;
|
||||
alGetSourcei(m_source, AL_SOURCE_STATE, &state);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case AL_INITIAL:
|
||||
case AL_STOPPED:
|
||||
return SoundStatus_Stopped;
|
||||
|
||||
case AL_PAUSED:
|
||||
return SoundStatus_Paused;
|
||||
|
||||
case AL_PLAYING:
|
||||
return SoundStatus_Playing;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Source state unrecognized");
|
||||
}
|
||||
|
||||
return SoundStatus_Stopped;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,7 @@
|
||||
|
||||
#include <Nazara/Audio/SoundStream.hpp>
|
||||
|
||||
NzSoundStream::~NzSoundStream() = default;
|
||||
namespace Nz
|
||||
{
|
||||
SoundStream::~SoundStream() = default;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,57 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Core/AbstractHash.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Hash/CRC32.hpp>
|
||||
#include <Nazara/Core/Hash/Fletcher16.hpp>
|
||||
#include <Nazara/Core/Hash/MD5.hpp>
|
||||
#include <Nazara/Core/Hash/SHA1.hpp>
|
||||
#include <Nazara/Core/Hash/SHA224.hpp>
|
||||
#include <Nazara/Core/Hash/SHA256.hpp>
|
||||
#include <Nazara/Core/Hash/SHA384.hpp>
|
||||
#include <Nazara/Core/Hash/SHA512.hpp>
|
||||
#include <Nazara/Core/Hash/Whirlpool.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzAbstractHash::~NzAbstractHash() = default;
|
||||
namespace Nz
|
||||
{
|
||||
AbstractHash::~AbstractHash() = default;
|
||||
|
||||
std::unique_ptr<AbstractHash> AbstractHash::Get(HashType type)
|
||||
{
|
||||
NazaraAssert(type <= HashType_Max, "Hash type value out of enum");
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case HashType_Fletcher16:
|
||||
return std::unique_ptr<AbstractHash>(new HashFletcher16);
|
||||
|
||||
case HashType_CRC32:
|
||||
return std::unique_ptr<AbstractHash>(new HashCRC32);
|
||||
|
||||
case HashType_MD5:
|
||||
return std::unique_ptr<AbstractHash>(new HashMD5);
|
||||
|
||||
case HashType_SHA1:
|
||||
return std::unique_ptr<AbstractHash>(new HashSHA1);
|
||||
|
||||
case HashType_SHA224:
|
||||
return std::unique_ptr<AbstractHash>(new HashSHA224);
|
||||
|
||||
case HashType_SHA256:
|
||||
return std::unique_ptr<AbstractHash>(new HashSHA256);
|
||||
|
||||
case HashType_SHA384:
|
||||
return std::unique_ptr<AbstractHash>(new HashSHA384);
|
||||
|
||||
case HashType_SHA512:
|
||||
return std::unique_ptr<AbstractHash>(new HashSHA512);
|
||||
|
||||
case HashType_Whirlpool:
|
||||
return std::unique_ptr<AbstractHash>(new HashWhirlpool);
|
||||
}
|
||||
|
||||
NazaraInternalError("Hash type not handled (0x" + String::Number(type, 16) + ')');
|
||||
return std::unique_ptr<AbstractHash>();
|
||||
}
|
||||
}
|
||||
|
||||
33
src/Nazara/Core/AbstractLogger.cpp
Normal file
33
src/Nazara/Core/AbstractLogger.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// 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/AbstractLogger.hpp>
|
||||
#include <Nazara/Core/StringStream.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const char* errorType[] = {
|
||||
"Assert failed: ", // ErrorType_AssertFailed
|
||||
"Internal error: ", // ErrorType_Internal
|
||||
"Error: ", // ErrorType_Normal
|
||||
"Warning: " // ErrorType_Warning
|
||||
};
|
||||
|
||||
static_assert(sizeof(errorType) / sizeof(const char*) == ErrorType_Max + 1, "Error type array is incomplete");
|
||||
}
|
||||
|
||||
AbstractLogger::~AbstractLogger() = default;
|
||||
|
||||
void AbstractLogger::WriteError(ErrorType type, const String& error, unsigned int line, const char* file, const char* function)
|
||||
{
|
||||
StringStream stream;
|
||||
stream << errorType[type] << error;
|
||||
|
||||
if (line != 0 && file && function)
|
||||
stream << " (" << file << ':' << line << ": " << function << ')';
|
||||
}
|
||||
}
|
||||
@@ -7,15 +7,11 @@
|
||||
#include <ostream>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const NzByteArray& byteArray)
|
||||
namespace Nz
|
||||
{
|
||||
out << byteArray.ToString();
|
||||
return out;
|
||||
}
|
||||
|
||||
bool NzByteArray::FillHash(NzAbstractHash* hash) const
|
||||
{
|
||||
hash->Append(GetConstBuffer(), GetSize());
|
||||
|
||||
return true;
|
||||
std::ostream& operator<<(std::ostream& out, const Nz::ByteArray& byteArray)
|
||||
{
|
||||
out << byteArray.ToHex();
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,93 +21,155 @@
|
||||
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace
|
||||
namespace Nz
|
||||
{
|
||||
nzUInt64 NzGetMicrosecondsLowPrecision()
|
||||
namespace Detail
|
||||
{
|
||||
return NzClockImplGetMilliseconds()*1000ULL;
|
||||
UInt64 GetMicrosecondsLowPrecision()
|
||||
{
|
||||
return ClockImplGetElapsedMilliseconds()*1000ULL;
|
||||
}
|
||||
|
||||
UInt64 GetElapsedMicrosecondsFirstRun()
|
||||
{
|
||||
if (ClockImplInitializeHighPrecision())
|
||||
GetElapsedMicroseconds = ClockImplGetElapsedMicroseconds;
|
||||
else
|
||||
GetElapsedMicroseconds = GetMicrosecondsLowPrecision;
|
||||
|
||||
return GetElapsedMicroseconds();
|
||||
}
|
||||
}
|
||||
|
||||
nzUInt64 NzGetMicrosecondsFirstRun()
|
||||
{
|
||||
if (NzClockImplInitializeHighPrecision())
|
||||
NzGetMicroseconds = NzClockImplGetMicroseconds;
|
||||
else
|
||||
NzGetMicroseconds = NzGetMicrosecondsLowPrecision;
|
||||
/*!
|
||||
* \class Nz::Clock
|
||||
* \brief Utility class that measure the elapsed time
|
||||
*/
|
||||
|
||||
return NzGetMicroseconds();
|
||||
/*!
|
||||
* \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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
NzClock::NzClock(nzUInt64 startingValue, bool paused) :
|
||||
m_elapsedTime(startingValue),
|
||||
m_refTime(NzGetMicroseconds()),
|
||||
m_paused(paused)
|
||||
{
|
||||
}
|
||||
/*!
|
||||
* Returns the elapsed time in seconds
|
||||
* \return Seconds elapsed
|
||||
*
|
||||
* \see GetMicroseconds, GetMilliseconds
|
||||
*/
|
||||
|
||||
float NzClock::GetSeconds() const
|
||||
{
|
||||
return GetMicroseconds()/1000000.f;
|
||||
}
|
||||
|
||||
nzUInt64 NzClock::GetMicroseconds() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
nzUInt64 elapsedMicroseconds = m_elapsedTime;
|
||||
if (!m_paused)
|
||||
elapsedMicroseconds += (NzGetMicroseconds() - m_refTime);
|
||||
|
||||
return elapsedMicroseconds;
|
||||
}
|
||||
|
||||
nzUInt64 NzClock::GetMilliseconds() const
|
||||
{
|
||||
return GetMicroseconds()/1000;
|
||||
}
|
||||
|
||||
bool NzClock::IsPaused() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
return m_paused;
|
||||
}
|
||||
|
||||
void NzClock::Pause()
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
if (!m_paused)
|
||||
float Clock::GetSeconds() const
|
||||
{
|
||||
m_elapsedTime += NzGetMicroseconds()-m_refTime;
|
||||
m_paused = true;
|
||||
return GetMicroseconds()/1000000.f;
|
||||
}
|
||||
else
|
||||
NazaraWarning("Clock is already paused, ignoring...");
|
||||
}
|
||||
|
||||
void NzClock::Restart()
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
/*!
|
||||
* Returns the elapsed time in microseconds
|
||||
* \return Microseconds elapsed
|
||||
*
|
||||
* \see GetMilliseconds, GetSeconds
|
||||
*/
|
||||
|
||||
m_elapsedTime = 0;
|
||||
m_refTime = NzGetMicroseconds();
|
||||
m_paused = false;
|
||||
}
|
||||
|
||||
void NzClock::Unpause()
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
if (m_paused)
|
||||
UInt64 Clock::GetMicroseconds() const
|
||||
{
|
||||
m_refTime = NzGetMicroseconds();
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
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
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
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()
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
if (!m_paused)
|
||||
{
|
||||
m_elapsedTime += GetElapsedMicroseconds() - m_refTime;
|
||||
m_paused = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Restart the clock
|
||||
* Restarts the clock, putting it's time counter back to zero (as if the clock got constructed).
|
||||
*/
|
||||
|
||||
void Clock::Restart()
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
m_elapsedTime = 0;
|
||||
m_refTime = GetElapsedMicroseconds();
|
||||
m_paused = false;
|
||||
}
|
||||
else
|
||||
NazaraWarning("Clock is not paused, ignoring...");
|
||||
}
|
||||
|
||||
NzClockFunction NzGetMicroseconds = NzGetMicrosecondsFirstRun;
|
||||
NzClockFunction NzGetMilliseconds = NzClockImplGetMilliseconds;
|
||||
/*!
|
||||
* \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()
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
if (m_paused)
|
||||
{
|
||||
m_refTime = GetElapsedMicroseconds();
|
||||
m_paused = false;
|
||||
}
|
||||
}
|
||||
|
||||
ClockFunction GetElapsedMicroseconds = Detail::GetElapsedMicrosecondsFirstRun;
|
||||
ClockFunction GetElapsedMilliseconds = ClockImplGetElapsedMilliseconds;
|
||||
}
|
||||
|
||||
@@ -5,12 +5,15 @@
|
||||
#include <Nazara/Core/Color.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
const NzColor NzColor::Black(0, 0, 0);
|
||||
const NzColor NzColor::Blue(0, 0, 255);
|
||||
const NzColor NzColor::Cyan(0, 255, 255);
|
||||
const NzColor NzColor::Green(0, 255, 0);
|
||||
const NzColor NzColor::Magenta(255, 0, 255);
|
||||
const NzColor NzColor::Orange(255, 165, 0);
|
||||
const NzColor NzColor::Red(255, 0, 0);
|
||||
const NzColor NzColor::Yellow(255, 255, 0);
|
||||
const NzColor NzColor::White(255, 255, 255);
|
||||
namespace Nz
|
||||
{
|
||||
const Color Color::Black(0, 0, 0);
|
||||
const Color Color::Blue(0, 0, 255);
|
||||
const Color Color::Cyan(0, 255, 255);
|
||||
const Color Color::Green(0, 255, 0);
|
||||
const Color Color::Magenta(255, 0, 255);
|
||||
const Color Color::Orange(255, 165, 0);
|
||||
const Color Color::Red(255, 0, 0);
|
||||
const Color Color::Yellow(255, 255, 0);
|
||||
const Color Color::White(255, 255, 255);
|
||||
}
|
||||
|
||||
@@ -16,34 +16,37 @@
|
||||
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzConditionVariable::NzConditionVariable()
|
||||
namespace Nz
|
||||
{
|
||||
m_impl = new NzConditionVariableImpl;
|
||||
}
|
||||
ConditionVariable::ConditionVariable()
|
||||
{
|
||||
m_impl = new ConditionVariableImpl;
|
||||
}
|
||||
|
||||
NzConditionVariable::~NzConditionVariable()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
ConditionVariable::~ConditionVariable()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
void NzConditionVariable::Signal()
|
||||
{
|
||||
m_impl->Signal();
|
||||
}
|
||||
void ConditionVariable::Signal()
|
||||
{
|
||||
m_impl->Signal();
|
||||
}
|
||||
|
||||
void NzConditionVariable::SignalAll()
|
||||
{
|
||||
m_impl->SignalAll();
|
||||
}
|
||||
void ConditionVariable::SignalAll()
|
||||
{
|
||||
m_impl->SignalAll();
|
||||
}
|
||||
|
||||
void NzConditionVariable::Wait(NzMutex* mutex)
|
||||
{
|
||||
NazaraAssert(mutex != nullptr, "Mutex must be valid");
|
||||
m_impl->Wait(mutex->m_impl);
|
||||
}
|
||||
void ConditionVariable::Wait(Mutex* mutex)
|
||||
{
|
||||
NazaraAssert(mutex != nullptr, "Mutex must be valid");
|
||||
m_impl->Wait(mutex->m_impl);
|
||||
}
|
||||
|
||||
bool NzConditionVariable::Wait(NzMutex* mutex, nzUInt32 timeout)
|
||||
{
|
||||
NazaraAssert(mutex != nullptr, "Mutex must be valid");
|
||||
return m_impl->Wait(mutex->m_impl, timeout);
|
||||
bool ConditionVariable::Wait(Mutex* mutex, UInt32 timeout)
|
||||
{
|
||||
NazaraAssert(mutex != nullptr, "Mutex must be valid");
|
||||
return m_impl->Wait(mutex->m_impl, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,44 +11,50 @@
|
||||
#include <Nazara/Core/TaskScheduler.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
bool NzCore::Initialize()
|
||||
namespace Nz
|
||||
{
|
||||
if (s_moduleReferenceCounter > 0)
|
||||
bool Core::Initialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter > 0)
|
||||
{
|
||||
s_moduleReferenceCounter++;
|
||||
return true; // Déjà initialisé
|
||||
}
|
||||
|
||||
s_moduleReferenceCounter++;
|
||||
return true; // Déjà initialisé
|
||||
|
||||
Log::Initialize();
|
||||
|
||||
NazaraNotice("Initialized: Core");
|
||||
return true;
|
||||
}
|
||||
|
||||
s_moduleReferenceCounter++;
|
||||
|
||||
NazaraNotice("Initialized: Core");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzCore::IsInitialized()
|
||||
{
|
||||
return s_moduleReferenceCounter != 0;
|
||||
}
|
||||
|
||||
void NzCore::Uninitialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter != 1)
|
||||
bool Core::IsInitialized()
|
||||
{
|
||||
// Le module est soit encore utilisé, soit pas initialisé
|
||||
if (s_moduleReferenceCounter > 1)
|
||||
s_moduleReferenceCounter--;
|
||||
|
||||
return;
|
||||
return s_moduleReferenceCounter != 0;
|
||||
}
|
||||
|
||||
// Libération du module
|
||||
s_moduleReferenceCounter = 0;
|
||||
void Core::Uninitialize()
|
||||
{
|
||||
if (s_moduleReferenceCounter != 1)
|
||||
{
|
||||
// Le module est soit encore utilisé, soit pas initialisé
|
||||
if (s_moduleReferenceCounter > 1)
|
||||
s_moduleReferenceCounter--;
|
||||
|
||||
NzHardwareInfo::Uninitialize();
|
||||
NzPluginManager::Uninitialize();
|
||||
NzTaskScheduler::Uninitialize();
|
||||
return;
|
||||
}
|
||||
|
||||
NazaraNotice("Uninitialized: Core");
|
||||
// Libération du module
|
||||
s_moduleReferenceCounter = 0;
|
||||
|
||||
HardwareInfo::Uninitialize();
|
||||
Log::Uninitialize();
|
||||
PluginManager::Uninitialize();
|
||||
TaskScheduler::Uninitialize();
|
||||
|
||||
NazaraNotice("Uninitialized: Core");
|
||||
}
|
||||
|
||||
unsigned int Core::s_moduleReferenceCounter = 0;
|
||||
}
|
||||
|
||||
unsigned int NzCore::s_moduleReferenceCounter = 0;
|
||||
|
||||
@@ -10,22 +10,22 @@
|
||||
|
||||
void* operator new(std::size_t size)
|
||||
{
|
||||
return NzMemoryManager::Allocate(size, false);
|
||||
return Nz::MemoryManager::Allocate(size, false);
|
||||
}
|
||||
|
||||
void* operator new[](std::size_t size)
|
||||
{
|
||||
return NzMemoryManager::Allocate(size, true);
|
||||
return Nz::MemoryManager::Allocate(size, true);
|
||||
}
|
||||
|
||||
void operator delete(void* pointer) noexcept
|
||||
{
|
||||
NzMemoryManager::Free(pointer, false);
|
||||
Nz::MemoryManager::Free(pointer, false);
|
||||
}
|
||||
|
||||
void operator delete[](void* pointer) noexcept
|
||||
{
|
||||
NzMemoryManager::Free(pointer, true);
|
||||
Nz::MemoryManager::Free(pointer, true);
|
||||
}
|
||||
|
||||
#endif // NAZARA_CORE_MANAGE_MEMORY
|
||||
|
||||
@@ -13,24 +13,24 @@
|
||||
|
||||
void* operator new(std::size_t size, const char* file, unsigned int line)
|
||||
{
|
||||
return NzMemoryManager::Allocate(size, false, file, line);
|
||||
return Nz::MemoryManager::Allocate(size, false, file, line);
|
||||
}
|
||||
|
||||
void* operator new[](std::size_t size, const char* file, unsigned int line)
|
||||
{
|
||||
return NzMemoryManager::Allocate(size, true, file, line);
|
||||
return Nz::MemoryManager::Allocate(size, true, file, line);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr, const char* file, unsigned int line) noexcept
|
||||
{
|
||||
NzMemoryManager::NextFree(file, line);
|
||||
NzMemoryManager::Free(ptr, false);
|
||||
Nz::MemoryManager::NextFree(file, line);
|
||||
Nz::MemoryManager::Free(ptr, false);
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr, const char* file, unsigned int line) noexcept
|
||||
{
|
||||
NzMemoryManager::NextFree(file, line);
|
||||
NzMemoryManager::Free(ptr, true);
|
||||
Nz::MemoryManager::NextFree(file, line);
|
||||
Nz::MemoryManager::Free(ptr, true);
|
||||
}
|
||||
|
||||
#endif // NAZARA_CORE_MANAGE_MEMORY
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
#include <Nazara/Core/Config.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Core/Win32/DirectoryImpl.hpp>
|
||||
@@ -24,364 +26,355 @@
|
||||
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace
|
||||
namespace Nz
|
||||
{
|
||||
/*thread_local*/ NzString currentPath(NzDirectoryImpl::GetCurrent());
|
||||
}
|
||||
|
||||
NzDirectory::NzDirectory() :
|
||||
m_pattern('*'),
|
||||
m_impl(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
NzDirectory::NzDirectory(const NzString& dirPath) :
|
||||
m_dirPath(dirPath),
|
||||
m_pattern('*'),
|
||||
m_impl(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
NzDirectory::~NzDirectory()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void NzDirectory::Close()
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
if (m_impl)
|
||||
namespace
|
||||
{
|
||||
m_impl->Close();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool NzDirectory::Exists() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
if (IsOpen())
|
||||
return true; // Le fichier est ouvert, donc il existe
|
||||
else
|
||||
return Exists(m_dirPath);
|
||||
}
|
||||
|
||||
NzString NzDirectory::GetPath() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
return m_dirPath;
|
||||
}
|
||||
|
||||
NzString NzDirectory::GetPattern() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
return m_pattern;
|
||||
}
|
||||
|
||||
NzString NzDirectory::GetResultName() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Directory not opened");
|
||||
return NzString();
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetResultName();
|
||||
}
|
||||
|
||||
NzString NzDirectory::GetResultPath() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Directory not opened");
|
||||
return NzString();
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_dirPath + NAZARA_DIRECTORY_SEPARATOR + m_impl->GetResultName();
|
||||
}
|
||||
|
||||
nzUInt64 NzDirectory::GetResultSize() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Directory not opened");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetResultSize();
|
||||
}
|
||||
|
||||
bool NzDirectory::IsOpen() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
bool NzDirectory::IsResultDirectory() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Directory not opened");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->IsResultDirectory();
|
||||
}
|
||||
|
||||
bool NzDirectory::NextResult(bool skipDots)
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Directory not opened");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
NzString name;
|
||||
do
|
||||
{
|
||||
if (!m_impl->NextResult())
|
||||
return false;
|
||||
|
||||
name = m_impl->GetResultName();
|
||||
|
||||
if (skipDots && (name == '.' || name == ".."))
|
||||
continue;
|
||||
|
||||
if (name.Match(m_pattern))
|
||||
break;
|
||||
}
|
||||
while (true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzDirectory::Open()
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
Close();
|
||||
|
||||
if (!Exists(m_dirPath))
|
||||
return false;
|
||||
|
||||
m_impl = new NzDirectoryImpl(this);
|
||||
if (!m_impl->Open(m_dirPath))
|
||||
{
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
|
||||
return false;
|
||||
//FIXME: MinGW seems to dislike thread_local shared_ptr.. (using a std::string is a working hackfix)
|
||||
thread_local std::string currentPath(DirectoryImpl::GetCurrent());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzDirectory::SetPath(const NzString& dirPath)
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
Close();
|
||||
|
||||
m_dirPath = NzFile::AbsolutePath(dirPath);
|
||||
}
|
||||
|
||||
void NzDirectory::SetPattern(const NzString& pattern)
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
m_pattern = pattern;
|
||||
}
|
||||
|
||||
bool NzDirectory::Copy(const NzString& sourcePath, const NzString& destPath)
|
||||
{
|
||||
if (sourcePath.IsEmpty() || destPath.IsEmpty())
|
||||
return false;
|
||||
|
||||
NzString dirPath(sourcePath);
|
||||
NzString dest(NzFile::NormalizePath(destPath));
|
||||
|
||||
if (!Create(destPath, true))
|
||||
Directory::Directory() :
|
||||
m_pattern('*'),
|
||||
m_impl(nullptr)
|
||||
{
|
||||
NazaraError("Unable to create \"" + destPath + '"');
|
||||
return false;
|
||||
}
|
||||
|
||||
NzDirectory dir(dirPath);
|
||||
if (!dir.Open())
|
||||
Directory::Directory(const String& dirPath) :
|
||||
m_dirPath(dirPath),
|
||||
m_pattern('*'),
|
||||
m_impl(nullptr)
|
||||
{
|
||||
NazaraError("Unable to open \"" + destPath + '"');
|
||||
return false;
|
||||
}
|
||||
|
||||
while (dir.NextResult(true))
|
||||
Directory::~Directory()
|
||||
{
|
||||
if (dir.IsResultDirectory())
|
||||
Close();
|
||||
}
|
||||
|
||||
void Directory::Close()
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
if (m_impl)
|
||||
{
|
||||
if (!Copy(dir.GetResultPath(), dest + NAZARA_DIRECTORY_SEPARATOR + dir.GetResultName()))
|
||||
return false;
|
||||
}
|
||||
else if (!NzFile::Copy(dir.GetResultPath(), dest + NAZARA_DIRECTORY_SEPARATOR + dir.GetResultName()))
|
||||
{
|
||||
NazaraError("Failed to copy \"" + dir.GetResultPath() + "\" to \"" + dest + NAZARA_DIRECTORY_SEPARATOR + dir.GetResultName() + '"');
|
||||
return false;
|
||||
m_impl->Close();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
dir.Close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzDirectory::Create(const NzString& dirPath, bool recursive)
|
||||
{
|
||||
if (dirPath.IsEmpty())
|
||||
return false;
|
||||
|
||||
if (recursive)
|
||||
bool Directory::Exists() const
|
||||
{
|
||||
NzString path = NzFile::NormalizePath(dirPath);
|
||||
unsigned int foundPos = path.Find(NAZARA_DIRECTORY_SEPARATOR);
|
||||
if (foundPos == NzString::npos)
|
||||
return false;
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS
|
||||
// Contrairement au disque (Ex: "C:"), le chemin réseau n'est pas considéré comme un dossier (Ex: "\\Laptop")
|
||||
if (path.Match("\\\\*"))
|
||||
if (IsOpen())
|
||||
return true; // Le fichier est ouvert, donc il existe
|
||||
else
|
||||
return Exists(m_dirPath);
|
||||
}
|
||||
|
||||
String Directory::GetPath() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
return m_dirPath;
|
||||
}
|
||||
|
||||
String Directory::GetPattern() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
return m_pattern;
|
||||
}
|
||||
|
||||
String Directory::GetResultName() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
foundPos = path.Find('\\', 2);
|
||||
if (foundPos == NzString::npos)
|
||||
return false;
|
||||
|
||||
foundPos = path.Find('\\', foundPos+1);
|
||||
if (foundPos == NzString::npos)
|
||||
return false;
|
||||
NazaraError("Directory not opened");
|
||||
return String();
|
||||
}
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
NzString p = path.SubString(0, foundPos);
|
||||
if (p.EndsWith(NAZARA_DIRECTORY_SEPARATOR))
|
||||
p = p.SubString(0, -2);
|
||||
return m_impl->GetResultName();
|
||||
}
|
||||
|
||||
if (!NzDirectoryImpl::Exists(p) && !NzDirectoryImpl::Create(p))
|
||||
String Directory::GetResultPath() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Directory not opened");
|
||||
return String();
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_dirPath + NAZARA_DIRECTORY_SEPARATOR + m_impl->GetResultName();
|
||||
}
|
||||
|
||||
UInt64 Directory::GetResultSize() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Directory not opened");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetResultSize();
|
||||
}
|
||||
|
||||
bool Directory::IsOpen() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
bool Directory::IsResultDirectory() const
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Directory not opened");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->IsResultDirectory();
|
||||
}
|
||||
|
||||
bool Directory::NextResult(bool skipDots)
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Directory not opened");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
String name;
|
||||
for (;;)
|
||||
{
|
||||
if (!m_impl->NextResult())
|
||||
return false;
|
||||
|
||||
if (foundPos == NzString::npos)
|
||||
break;
|
||||
name = m_impl->GetResultName();
|
||||
|
||||
foundPos = path.Find(NAZARA_DIRECTORY_SEPARATOR, foundPos+1);
|
||||
if (skipDots && (name == '.' || name == ".."))
|
||||
continue;
|
||||
|
||||
if (name.Match(m_pattern))
|
||||
break;
|
||||
}
|
||||
while (true);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return NzDirectoryImpl::Create(NzFile::NormalizePath(dirPath));
|
||||
}
|
||||
|
||||
bool NzDirectory::Exists(const NzString& dirPath)
|
||||
{
|
||||
if (dirPath.IsEmpty())
|
||||
return false;
|
||||
|
||||
return NzDirectoryImpl::Exists(NzFile::NormalizePath(dirPath));
|
||||
}
|
||||
|
||||
NzString NzDirectory::GetCurrent()
|
||||
{
|
||||
return currentPath;
|
||||
}
|
||||
|
||||
const char* NzDirectory::GetCurrentFileRelativeToEngine(const char* currentFile)
|
||||
{
|
||||
///FIXME: Est-ce que cette méthode est au bon endroit ?
|
||||
static int offset = -1;
|
||||
|
||||
if (offset < 0)
|
||||
bool Directory::Open()
|
||||
{
|
||||
const char* directoryFile = __FILE__;
|
||||
const char* ptr = std::strstr(directoryFile, "NazaraEngine/src/Nazara/Core/Directory.cpp");
|
||||
if (ptr)
|
||||
offset = ptr - directoryFile;
|
||||
else
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
Close();
|
||||
|
||||
if (!Exists(m_dirPath))
|
||||
return false;
|
||||
|
||||
m_impl = new DirectoryImpl(this);
|
||||
if (!m_impl->Open(m_dirPath))
|
||||
{
|
||||
ptr = std::strstr(directoryFile, "NazaraEngine\\src\\Nazara\\Core\\Directory.cpp");
|
||||
if (ptr)
|
||||
offset = ptr - directoryFile;
|
||||
else
|
||||
offset = 0;
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return ¤tFile[offset];
|
||||
}
|
||||
|
||||
bool NzDirectory::Remove(const NzString& dirPath, bool emptyDirectory)
|
||||
{
|
||||
if (dirPath.IsEmpty())
|
||||
return false;
|
||||
|
||||
if (emptyDirectory)
|
||||
void Directory::SetPath(const String& dirPath)
|
||||
{
|
||||
NzDirectory dir(dirPath);
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
Close();
|
||||
|
||||
m_dirPath = File::AbsolutePath(dirPath);
|
||||
}
|
||||
|
||||
void Directory::SetPattern(const String& pattern)
|
||||
{
|
||||
NazaraLock(m_mutex);
|
||||
|
||||
m_pattern = pattern;
|
||||
}
|
||||
|
||||
bool Directory::Copy(const String& sourcePath, const String& destPath)
|
||||
{
|
||||
if (sourcePath.IsEmpty() || destPath.IsEmpty())
|
||||
return false;
|
||||
|
||||
String dirPath(sourcePath);
|
||||
String dest(File::NormalizePath(destPath));
|
||||
|
||||
if (!Create(destPath, true))
|
||||
{
|
||||
NazaraError("Unable to create \"" + destPath + '"');
|
||||
return false;
|
||||
}
|
||||
|
||||
Directory dir(dirPath);
|
||||
if (!dir.Open())
|
||||
return NzDirectoryImpl::Remove(dirPath); // Si on n'arrive pas à ouvrir le dossier, on tente de le supprimer
|
||||
{
|
||||
NazaraError("Unable to open \"" + destPath + '"');
|
||||
return false;
|
||||
}
|
||||
|
||||
while (dir.NextResult(true))
|
||||
{
|
||||
if (dir.IsResultDirectory())
|
||||
{
|
||||
if (!Remove(dir.GetResultPath(), true))
|
||||
if (!Copy(dir.GetResultPath(), dest + NAZARA_DIRECTORY_SEPARATOR + dir.GetResultName()))
|
||||
return false;
|
||||
}
|
||||
else if (!NzFile::Delete(dir.GetResultPath()))
|
||||
else if (!File::Copy(dir.GetResultPath(), dest + NAZARA_DIRECTORY_SEPARATOR + dir.GetResultName()))
|
||||
{
|
||||
NazaraError(dir.GetResultPath());
|
||||
NazaraError("Failed to copy \"" + dir.GetResultPath() + "\" to \"" + dest + NAZARA_DIRECTORY_SEPARATOR + dir.GetResultName() + '"');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
dir.Close();
|
||||
}
|
||||
|
||||
return NzDirectoryImpl::Remove(NzFile::NormalizePath(dirPath));
|
||||
}
|
||||
|
||||
bool NzDirectory::SetCurrent(const NzString& dirPath)
|
||||
{
|
||||
NzString path = NzFile::AbsolutePath(dirPath);
|
||||
if (NzDirectoryImpl::Exists(path))
|
||||
{
|
||||
currentPath = path;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
bool Directory::Create(const String& dirPath, bool recursive)
|
||||
{
|
||||
if (dirPath.IsEmpty())
|
||||
return false;
|
||||
|
||||
if (recursive)
|
||||
{
|
||||
String path = File::NormalizePath(dirPath);
|
||||
std::size_t foundPos = path.Find(NAZARA_DIRECTORY_SEPARATOR);
|
||||
if (foundPos == String::npos)
|
||||
return false;
|
||||
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS
|
||||
// Contrairement au disque (Ex: "C:"), le chemin réseau n'est pas considéré comme un dossier (Ex: "\\Laptop")
|
||||
if (path.Match("\\\\*"))
|
||||
{
|
||||
foundPos = path.Find('\\', 2);
|
||||
if (foundPos == String::npos)
|
||||
return false;
|
||||
|
||||
foundPos = path.Find('\\', foundPos + 1);
|
||||
if (foundPos == String::npos)
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;;)
|
||||
{
|
||||
String p = path.SubString(0, foundPos);
|
||||
if (p.EndsWith(NAZARA_DIRECTORY_SEPARATOR))
|
||||
p = p.SubString(0, -2);
|
||||
|
||||
if (!DirectoryImpl::Exists(p) && !DirectoryImpl::Create(p))
|
||||
return false;
|
||||
|
||||
if (foundPos == String::npos)
|
||||
break;
|
||||
|
||||
foundPos = path.Find(NAZARA_DIRECTORY_SEPARATOR, foundPos + 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return DirectoryImpl::Create(File::NormalizePath(dirPath));
|
||||
}
|
||||
|
||||
bool Directory::Exists(const String& dirPath)
|
||||
{
|
||||
if (dirPath.IsEmpty())
|
||||
return false;
|
||||
|
||||
return DirectoryImpl::Exists(File::NormalizePath(dirPath));
|
||||
}
|
||||
|
||||
String Directory::GetCurrent()
|
||||
{
|
||||
return currentPath;
|
||||
}
|
||||
|
||||
const char* Directory::GetCurrentFileRelativeToEngine(const char* currentFile)
|
||||
{
|
||||
///FIXME: Est-ce que cette méthode est au bon endroit ?
|
||||
const char* ptr = std::strstr(currentFile, "NazaraEngine/");
|
||||
if (!ptr)
|
||||
ptr = std::strstr(currentFile, "NazaraEngine\\");
|
||||
|
||||
if (!ptr)
|
||||
ptr = currentFile;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool Directory::Remove(const String& dirPath, bool emptyDirectory)
|
||||
{
|
||||
if (dirPath.IsEmpty())
|
||||
return false;
|
||||
|
||||
if (emptyDirectory)
|
||||
{
|
||||
Directory dir(dirPath);
|
||||
if (!dir.Open())
|
||||
return DirectoryImpl::Remove(dirPath); // Si on n'arrive pas à ouvrir le dossier, on tente de le supprimer
|
||||
|
||||
while (dir.NextResult(true))
|
||||
{
|
||||
if (dir.IsResultDirectory())
|
||||
{
|
||||
if (!Remove(dir.GetResultPath(), true))
|
||||
return false;
|
||||
}
|
||||
else if (!File::Delete(dir.GetResultPath()))
|
||||
{
|
||||
NazaraError(dir.GetResultPath());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
dir.Close();
|
||||
}
|
||||
|
||||
return DirectoryImpl::Remove(File::NormalizePath(dirPath));
|
||||
}
|
||||
|
||||
bool Directory::SetCurrent(const String& dirPath)
|
||||
{
|
||||
String path = File::AbsolutePath(dirPath);
|
||||
if (DirectoryImpl::Exists(path))
|
||||
{
|
||||
currentPath = path;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,88 +23,91 @@
|
||||
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzDynLib::NzDynLib() :
|
||||
m_impl(nullptr)
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
NzDynLib::NzDynLib(NzDynLib&& lib) :
|
||||
m_lastError(std::move(lib.m_lastError)),
|
||||
m_impl(lib.m_impl)
|
||||
{
|
||||
lib.m_impl = nullptr;
|
||||
}
|
||||
|
||||
NzDynLib::~NzDynLib()
|
||||
{
|
||||
Unload();
|
||||
}
|
||||
|
||||
NzString NzDynLib::GetLastError() const
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
return m_lastError;
|
||||
}
|
||||
|
||||
NzDynLibFunc NzDynLib::GetSymbol(const NzString& symbol) const
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!m_impl)
|
||||
DynLib::DynLib() :
|
||||
m_impl(nullptr)
|
||||
{
|
||||
NazaraError("Library not opened");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetSymbol(symbol, &m_lastError);
|
||||
}
|
||||
|
||||
bool NzDynLib::IsLoaded() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
bool NzDynLib::Load(const NzString& libraryPath)
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
Unload();
|
||||
|
||||
std::unique_ptr<NzDynLibImpl> impl(new NzDynLibImpl(this));
|
||||
if (!impl->Load(libraryPath, &m_lastError))
|
||||
{
|
||||
NazaraError("Failed to load library: " + m_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = impl.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzDynLib::Unload()
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
if (m_impl)
|
||||
DynLib::DynLib(DynLib&& lib) :
|
||||
m_lastError(std::move(lib.m_lastError)),
|
||||
m_impl(lib.m_impl)
|
||||
{
|
||||
m_impl->Unload();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
lib.m_impl = nullptr;
|
||||
}
|
||||
|
||||
DynLib::~DynLib()
|
||||
{
|
||||
Unload();
|
||||
}
|
||||
|
||||
String DynLib::GetLastError() const
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
return m_lastError;
|
||||
}
|
||||
|
||||
DynLibFunc DynLib::GetSymbol(const String& symbol) const
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Library not opened");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetSymbol(symbol, &m_lastError);
|
||||
}
|
||||
|
||||
bool DynLib::IsLoaded() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
bool DynLib::Load(const String& libraryPath)
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
Unload();
|
||||
|
||||
std::unique_ptr<DynLibImpl> impl(new DynLibImpl(this));
|
||||
if (!impl->Load(libraryPath, &m_lastError))
|
||||
{
|
||||
NazaraError("Failed to load library: " + m_lastError);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = impl.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DynLib::Unload()
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
if (m_impl)
|
||||
{
|
||||
m_impl->Unload();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
DynLib& DynLib::operator=(DynLib&& lib)
|
||||
{
|
||||
Unload();
|
||||
|
||||
m_impl = lib.m_impl;
|
||||
m_lastError = std::move(lib.m_lastError);
|
||||
|
||||
lib.m_impl = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
NzDynLib& NzDynLib::operator=(NzDynLib&& lib)
|
||||
{
|
||||
Unload();
|
||||
|
||||
m_impl = lib.m_impl;
|
||||
m_lastError = std::move(lib.m_lastError);
|
||||
|
||||
lib.m_impl = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -16,112 +16,115 @@
|
||||
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
void NzError::Error(nzErrorType type, const NzString& error)
|
||||
namespace Nz
|
||||
{
|
||||
if (type == nzErrorType_AssertFailed || (s_flags & nzErrorFlag_Silent) == 0 || (s_flags & nzErrorFlag_SilentDisabled) != 0)
|
||||
NazaraLog->WriteError(type, error);
|
||||
UInt32 Error::GetFlags()
|
||||
{
|
||||
return s_flags;
|
||||
}
|
||||
|
||||
s_lastError = error;
|
||||
s_lastErrorFile = "";
|
||||
s_lastErrorFunction = "";
|
||||
s_lastErrorLine = 0;
|
||||
String Error::GetLastError(const char** file, unsigned int* line, const char** function)
|
||||
{
|
||||
if (file)
|
||||
*file = s_lastErrorFile;
|
||||
|
||||
#if NAZARA_CORE_EXIT_ON_ASSERT_FAILURE
|
||||
if (type == nzErrorType_AssertFailed)
|
||||
std::abort();
|
||||
#endif
|
||||
if (line)
|
||||
*line = s_lastErrorLine;
|
||||
|
||||
if (type == nzErrorType_AssertFailed || (type != nzErrorType_Warning &&
|
||||
(s_flags & nzErrorFlag_ThrowException) != 0 && (s_flags & nzErrorFlag_ThrowExceptionDisabled) == 0))
|
||||
throw std::runtime_error(error);
|
||||
if (function)
|
||||
*function = s_lastErrorFunction;
|
||||
|
||||
return s_lastError;
|
||||
}
|
||||
|
||||
unsigned int Error::GetLastSystemErrorCode()
|
||||
{
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
return ::GetLastError();
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
return errno;
|
||||
#else
|
||||
#error GetLastSystemErrorCode is not implemented on this platform
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
String Error::GetLastSystemError(unsigned int code)
|
||||
{
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
wchar_t* buffer = nullptr;
|
||||
|
||||
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr,
|
||||
code,
|
||||
0,
|
||||
reinterpret_cast<LPWSTR>(&buffer),
|
||||
0,
|
||||
nullptr);
|
||||
|
||||
String error(String::Unicode(buffer));
|
||||
LocalFree(buffer);
|
||||
|
||||
error.Trim(); // Pour une raison inconnue, Windows met deux-trois retours à la ligne après le message
|
||||
|
||||
return error;
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
return std::strerror(code);
|
||||
#else
|
||||
#error GetLastSystemError is not implemented on this platform
|
||||
|
||||
return String("GetLastSystemError is not implemented on this platform");
|
||||
#endif
|
||||
}
|
||||
|
||||
void Error::SetFlags(UInt32 flags)
|
||||
{
|
||||
s_flags = flags;
|
||||
}
|
||||
|
||||
void Error::Trigger(ErrorType type, const String& error)
|
||||
{
|
||||
if (type == ErrorType_AssertFailed || (s_flags & ErrorFlag_Silent) == 0 || (s_flags & ErrorFlag_SilentDisabled) != 0)
|
||||
Log::WriteError(type, error);
|
||||
|
||||
s_lastError = error;
|
||||
s_lastErrorFile = "";
|
||||
s_lastErrorFunction = "";
|
||||
s_lastErrorLine = 0;
|
||||
|
||||
#if NAZARA_CORE_EXIT_ON_ASSERT_FAILURE
|
||||
if (type == ErrorType_AssertFailed)
|
||||
std::abort();
|
||||
#endif
|
||||
|
||||
if (type == ErrorType_AssertFailed || (type != ErrorType_Warning &&
|
||||
(s_flags & ErrorFlag_ThrowException) != 0 && (s_flags & ErrorFlag_ThrowExceptionDisabled) == 0))
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
|
||||
void Error::Trigger(ErrorType type, const String& error, unsigned int line, const char* file, const char* function)
|
||||
{
|
||||
if (type == ErrorType_AssertFailed || (s_flags & ErrorFlag_Silent) == 0 || (s_flags & ErrorFlag_SilentDisabled) != 0)
|
||||
Log::WriteError(type, error, line, file, function);
|
||||
|
||||
s_lastError = error;
|
||||
s_lastErrorFile = file;
|
||||
s_lastErrorFunction = function;
|
||||
s_lastErrorLine = line;
|
||||
|
||||
#if NAZARA_CORE_EXIT_ON_ASSERT_FAILURE
|
||||
if (type == ErrorType_AssertFailed)
|
||||
std::abort();
|
||||
#endif
|
||||
|
||||
if (type == ErrorType_AssertFailed || (type != ErrorType_Warning &&
|
||||
(s_flags & ErrorFlag_ThrowException) != 0 && (s_flags & ErrorFlag_ThrowExceptionDisabled) == 0))
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
|
||||
UInt32 Error::s_flags = ErrorFlag_None;
|
||||
String Error::s_lastError;
|
||||
const char* Error::s_lastErrorFunction = "";
|
||||
const char* Error::s_lastErrorFile = "";
|
||||
unsigned int Error::s_lastErrorLine = 0;
|
||||
}
|
||||
|
||||
void NzError::Error(nzErrorType type, const NzString& error, unsigned int line, const char* file, const char* function)
|
||||
{
|
||||
if (type == nzErrorType_AssertFailed || (s_flags & nzErrorFlag_Silent) == 0 || (s_flags & nzErrorFlag_SilentDisabled) != 0)
|
||||
NazaraLog->WriteError(type, error, line, file, function);
|
||||
|
||||
s_lastError = error;
|
||||
s_lastErrorFile = file;
|
||||
s_lastErrorFunction = function;
|
||||
s_lastErrorLine = line;
|
||||
|
||||
#if NAZARA_CORE_EXIT_ON_ASSERT_FAILURE
|
||||
if (type == nzErrorType_AssertFailed)
|
||||
std::abort();
|
||||
#endif
|
||||
|
||||
if (type == nzErrorType_AssertFailed || (type != nzErrorType_Warning &&
|
||||
(s_flags & nzErrorFlag_ThrowException) != 0 && (s_flags & nzErrorFlag_ThrowExceptionDisabled) == 0))
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
|
||||
nzUInt32 NzError::GetFlags()
|
||||
{
|
||||
return s_flags;
|
||||
}
|
||||
|
||||
NzString NzError::GetLastError(const char** file, unsigned int* line, const char** function)
|
||||
{
|
||||
if (file)
|
||||
*file = s_lastErrorFile;
|
||||
|
||||
if (line)
|
||||
*line = s_lastErrorLine;
|
||||
|
||||
if (function)
|
||||
*function = s_lastErrorFunction;
|
||||
|
||||
return s_lastError;
|
||||
}
|
||||
|
||||
unsigned int NzError::GetLastSystemErrorCode()
|
||||
{
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
return ::GetLastError();
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
return errno;
|
||||
#else
|
||||
#error GetLastSystemErrorCode is not implemented on this platform
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
NzString NzError::GetLastSystemError(unsigned int code)
|
||||
{
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
wchar_t* buffer = nullptr;
|
||||
|
||||
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr,
|
||||
code,
|
||||
0,
|
||||
reinterpret_cast<LPWSTR>(&buffer),
|
||||
0,
|
||||
nullptr);
|
||||
|
||||
NzString error(NzString::Unicode(buffer));
|
||||
LocalFree(buffer);
|
||||
|
||||
error.Trim(); // Pour une raison inconnue, Windows met deux-trois retours à la ligne après le message
|
||||
|
||||
return error;
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
return std::strerror(code);
|
||||
#else
|
||||
#error GetLastSystemError is not implemented on this platform
|
||||
|
||||
return NzString("GetLastSystemError is not implemented on this platform");
|
||||
#endif
|
||||
}
|
||||
|
||||
void NzError::SetFlags(nzUInt32 flags)
|
||||
{
|
||||
s_flags = flags;
|
||||
}
|
||||
|
||||
nzUInt32 NzError::s_flags = nzErrorFlag_None;
|
||||
NzString NzError::s_lastError;
|
||||
const char* NzError::s_lastErrorFunction = "";
|
||||
const char* NzError::s_lastErrorFile = "";
|
||||
unsigned int NzError::s_lastErrorLine = 0;
|
||||
|
||||
@@ -6,26 +6,29 @@
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzErrorFlags::NzErrorFlags(nzUInt32 flags, bool replace) :
|
||||
m_previousFlags(NzError::GetFlags())
|
||||
namespace Nz
|
||||
{
|
||||
SetFlags(flags, replace);
|
||||
}
|
||||
ErrorFlags::ErrorFlags(UInt32 flags, bool replace) :
|
||||
m_previousFlags(Error::GetFlags())
|
||||
{
|
||||
SetFlags(flags, replace);
|
||||
}
|
||||
|
||||
NzErrorFlags::~NzErrorFlags()
|
||||
{
|
||||
NzError::SetFlags(m_previousFlags);
|
||||
}
|
||||
ErrorFlags::~ErrorFlags()
|
||||
{
|
||||
Error::SetFlags(m_previousFlags);
|
||||
}
|
||||
|
||||
nzUInt32 NzErrorFlags::GetPreviousFlags() const
|
||||
{
|
||||
return m_previousFlags;
|
||||
}
|
||||
UInt32 ErrorFlags::GetPreviousFlags() const
|
||||
{
|
||||
return m_previousFlags;
|
||||
}
|
||||
|
||||
void NzErrorFlags::SetFlags(nzUInt32 flags, bool replace)
|
||||
{
|
||||
if (!replace)
|
||||
flags |= m_previousFlags;
|
||||
void ErrorFlags::SetFlags(UInt32 flags, bool replace)
|
||||
{
|
||||
if (!replace)
|
||||
flags |= m_previousFlags;
|
||||
|
||||
NzError::SetFlags(flags);
|
||||
Error::SetFlags(flags);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
101
src/Nazara/Core/FileLogger.cpp
Normal file
101
src/Nazara/Core/FileLogger.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// 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/FileLogger.hpp>
|
||||
#include <Nazara/Core/CallOnExit.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/StringStream.hpp>
|
||||
#include <array>
|
||||
#include <ctime>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
FileLogger::FileLogger(const String& logPath) :
|
||||
m_outputFile(logPath),
|
||||
m_forceStdOutput(false),
|
||||
m_stdReplicationEnabled(true),
|
||||
m_timeLoggingEnabled(true)
|
||||
{
|
||||
}
|
||||
|
||||
FileLogger::~FileLogger() = default;
|
||||
|
||||
void FileLogger::EnableTimeLogging(bool enable)
|
||||
{
|
||||
m_timeLoggingEnabled = enable;
|
||||
}
|
||||
|
||||
void FileLogger::EnableStdReplication(bool enable)
|
||||
{
|
||||
m_stdReplicationEnabled = enable;
|
||||
}
|
||||
|
||||
bool FileLogger::IsStdReplicationEnabled()
|
||||
{
|
||||
return m_stdReplicationEnabled;
|
||||
}
|
||||
|
||||
bool FileLogger::IsTimeLoggingEnabled()
|
||||
{
|
||||
return m_timeLoggingEnabled;
|
||||
}
|
||||
|
||||
void FileLogger::Write(const String& string)
|
||||
{
|
||||
if (m_forceStdOutput || m_stdReplicationEnabled)
|
||||
{
|
||||
m_stdLogger.Write(string);
|
||||
|
||||
if (m_forceStdOutput)
|
||||
return;
|
||||
}
|
||||
|
||||
// To prevent infinite loops
|
||||
m_forceStdOutput = true;
|
||||
CallOnExit resetOnExit([this] ()
|
||||
{
|
||||
m_forceStdOutput = false;
|
||||
});
|
||||
|
||||
if (!m_outputFile.IsOpen())
|
||||
{
|
||||
if (!m_outputFile.Open(OpenMode_Text | OpenMode_Truncate | OpenMode_WriteOnly))
|
||||
{
|
||||
NazaraError("Failed to open output file");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply some processing before writing
|
||||
StringStream stream;
|
||||
if (m_timeLoggingEnabled)
|
||||
{
|
||||
std::array<char, 24> buffer;
|
||||
|
||||
time_t currentTime = std::time(nullptr);
|
||||
std::strftime(buffer.data(), 24, "%d/%m/%Y - %H:%M:%S: ", std::localtime(¤tTime));
|
||||
|
||||
stream << buffer.data();
|
||||
}
|
||||
|
||||
stream << string << '\n';
|
||||
|
||||
m_outputFile.Write(stream);
|
||||
}
|
||||
|
||||
void FileLogger::WriteError(ErrorType type, const String& error, unsigned int line, const char* file, const char* function)
|
||||
{
|
||||
if (m_forceStdOutput || m_stdReplicationEnabled)
|
||||
{
|
||||
m_stdLogger.WriteError(type, error, line, file, function);
|
||||
|
||||
if (m_forceStdOutput)
|
||||
return;
|
||||
}
|
||||
|
||||
AbstractLogger::WriteError(type, error, line, file, function);
|
||||
m_outputFile.Flush();
|
||||
}
|
||||
}
|
||||
@@ -14,434 +14,437 @@
|
||||
#include <limits>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace
|
||||
namespace Nz
|
||||
{
|
||||
int ScoreBestAreaFit(int width, int height, const NzRectui& freeRectSize)
|
||||
namespace
|
||||
{
|
||||
return freeRectSize.width * freeRectSize.height - width * height;
|
||||
}
|
||||
|
||||
int ScoreBestLongSideFit(int width, int height, const NzRectui& freeRectSize)
|
||||
{
|
||||
int leftoverHoriz = std::abs(static_cast<int>(freeRectSize.width - width));
|
||||
int leftoverVert = std::abs(static_cast<int>(freeRectSize.height - height));
|
||||
int leftover = std::max(leftoverHoriz, leftoverVert);
|
||||
|
||||
return leftover;
|
||||
}
|
||||
|
||||
int ScoreBestShortSideFit(int width, int height, const NzRectui& freeRectSize)
|
||||
{
|
||||
int leftoverHoriz = std::abs(static_cast<int>(freeRectSize.width - width));
|
||||
int leftoverVert = std::abs(static_cast<int>(freeRectSize.height - height));
|
||||
int leftover = std::min(leftoverHoriz, leftoverVert);
|
||||
|
||||
return leftover;
|
||||
}
|
||||
|
||||
int ScoreWorstAreaFit(int width, int height, const NzRectui& freeRectSize)
|
||||
{
|
||||
return -ScoreBestAreaFit(width, height, freeRectSize);
|
||||
}
|
||||
|
||||
int ScoreWorstLongSideFit(int width, int height, const NzRectui& freeRectSize)
|
||||
{
|
||||
return -ScoreBestLongSideFit(width, height, freeRectSize);
|
||||
}
|
||||
|
||||
int ScoreWorstShortSideFit(int width, int height, const NzRectui& freeRectSize)
|
||||
{
|
||||
return -ScoreBestShortSideFit(width, height, freeRectSize);
|
||||
}
|
||||
}
|
||||
|
||||
NzGuillotineBinPack::NzGuillotineBinPack()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
NzGuillotineBinPack::NzGuillotineBinPack(unsigned int width, unsigned int height)
|
||||
{
|
||||
Reset(width, height);
|
||||
}
|
||||
|
||||
NzGuillotineBinPack::NzGuillotineBinPack(const NzVector2ui& size)
|
||||
{
|
||||
Reset(size);
|
||||
}
|
||||
|
||||
void NzGuillotineBinPack::Clear()
|
||||
{
|
||||
m_freeRectangles.clear();
|
||||
m_freeRectangles.push_back(NzRectui(0, 0, m_width, m_height));
|
||||
|
||||
m_usedArea = 0;
|
||||
}
|
||||
|
||||
void NzGuillotineBinPack::Expand(unsigned int newWidth, unsigned newHeight)
|
||||
{
|
||||
unsigned int oldWidth = m_width;
|
||||
unsigned int oldHeight = m_height;
|
||||
|
||||
m_width = std::max(newWidth, m_width);
|
||||
m_height = std::max(newHeight, m_height);
|
||||
|
||||
if (m_width > oldWidth)
|
||||
m_freeRectangles.push_back(NzRectui(oldWidth, 0, m_width - oldWidth, oldHeight));
|
||||
|
||||
if (m_height > oldHeight)
|
||||
m_freeRectangles.push_back(NzRectui(0, oldHeight, m_width, m_height - oldHeight));
|
||||
|
||||
// On va ensuite fusionner les rectangles tant que possible
|
||||
while (MergeFreeRectangles());
|
||||
}
|
||||
|
||||
void NzGuillotineBinPack::Expand(const NzVector2ui& newSize)
|
||||
{
|
||||
Expand(newSize.x, newSize.y);
|
||||
}
|
||||
|
||||
void NzGuillotineBinPack::FreeRectangle(const NzRectui& rect)
|
||||
{
|
||||
///DOC: Cette méthode ne devrait recevoir que des rectangles calculés par la méthode Insert et peut provoquer de la fragmentation
|
||||
m_freeRectangles.push_back(rect);
|
||||
|
||||
m_usedArea -= rect.width * rect.height;
|
||||
}
|
||||
|
||||
unsigned int NzGuillotineBinPack::GetHeight() const
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
float NzGuillotineBinPack::GetOccupancy() const
|
||||
{
|
||||
return static_cast<float>(m_usedArea)/(m_width*m_height);
|
||||
}
|
||||
|
||||
NzVector2ui NzGuillotineBinPack::GetSize() const
|
||||
{
|
||||
return NzVector2ui(m_width, m_height);
|
||||
}
|
||||
|
||||
unsigned int NzGuillotineBinPack::GetWidth() const
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
bool NzGuillotineBinPack::Insert(NzRectui* rects, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
|
||||
{
|
||||
return Insert(rects, nullptr, nullptr, count, merge, rectChoice, splitMethod);
|
||||
}
|
||||
|
||||
bool NzGuillotineBinPack::Insert(NzRectui* rects, bool* flipped, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
|
||||
{
|
||||
return Insert(rects, flipped, nullptr, count, merge, rectChoice, splitMethod);
|
||||
}
|
||||
|
||||
bool NzGuillotineBinPack::Insert(NzRectui* rects, bool* flipped, bool* inserted, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
|
||||
{
|
||||
std::vector<NzRectui*> remainingRects(count); // La position du rectangle
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
remainingRects[i] = &rects[i];
|
||||
|
||||
// Pack rectangles one at a time until we have cleared the rects array of all rectangles.
|
||||
while (!remainingRects.empty())
|
||||
{
|
||||
// Stores the penalty score of the best rectangle placement - bigger=worse, smaller=better.
|
||||
bool bestFlipped;
|
||||
int bestFreeRect;
|
||||
int bestRect;
|
||||
int bestScore = std::numeric_limits<int>::max();
|
||||
|
||||
for (std::size_t i = 0; i < m_freeRectangles.size(); ++i)
|
||||
int ScoreBestAreaFit(int width, int height, const Rectui& freeRectSize)
|
||||
{
|
||||
NzRectui& freeRect = m_freeRectangles[i];
|
||||
return freeRectSize.width * freeRectSize.height - width * height;
|
||||
}
|
||||
|
||||
for (std::size_t j = 0; j < remainingRects.size(); ++j)
|
||||
int ScoreBestLongSideFit(int width, int height, const Rectui& freeRectSize)
|
||||
{
|
||||
int leftoverHoriz = std::abs(static_cast<int>(freeRectSize.width - width));
|
||||
int leftoverVert = std::abs(static_cast<int>(freeRectSize.height - height));
|
||||
int leftover = std::max(leftoverHoriz, leftoverVert);
|
||||
|
||||
return leftover;
|
||||
}
|
||||
|
||||
int ScoreBestShortSideFit(int width, int height, const Rectui& freeRectSize)
|
||||
{
|
||||
int leftoverHoriz = std::abs(static_cast<int>(freeRectSize.width - width));
|
||||
int leftoverVert = std::abs(static_cast<int>(freeRectSize.height - height));
|
||||
int leftover = std::min(leftoverHoriz, leftoverVert);
|
||||
|
||||
return leftover;
|
||||
}
|
||||
|
||||
int ScoreWorstAreaFit(int width, int height, const Rectui& freeRectSize)
|
||||
{
|
||||
return -ScoreBestAreaFit(width, height, freeRectSize);
|
||||
}
|
||||
|
||||
int ScoreWorstLongSideFit(int width, int height, const Rectui& freeRectSize)
|
||||
{
|
||||
return -ScoreBestLongSideFit(width, height, freeRectSize);
|
||||
}
|
||||
|
||||
int ScoreWorstShortSideFit(int width, int height, const Rectui& freeRectSize)
|
||||
{
|
||||
return -ScoreBestShortSideFit(width, height, freeRectSize);
|
||||
}
|
||||
}
|
||||
|
||||
GuillotineBinPack::GuillotineBinPack()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
GuillotineBinPack::GuillotineBinPack(unsigned int width, unsigned int height)
|
||||
{
|
||||
Reset(width, height);
|
||||
}
|
||||
|
||||
GuillotineBinPack::GuillotineBinPack(const Vector2ui& size)
|
||||
{
|
||||
Reset(size);
|
||||
}
|
||||
|
||||
void GuillotineBinPack::Clear()
|
||||
{
|
||||
m_freeRectangles.clear();
|
||||
m_freeRectangles.push_back(Rectui(0, 0, m_width, m_height));
|
||||
|
||||
m_usedArea = 0;
|
||||
}
|
||||
|
||||
void GuillotineBinPack::Expand(unsigned int newWidth, unsigned newHeight)
|
||||
{
|
||||
unsigned int oldWidth = m_width;
|
||||
unsigned int oldHeight = m_height;
|
||||
|
||||
m_width = std::max(newWidth, m_width);
|
||||
m_height = std::max(newHeight, m_height);
|
||||
|
||||
if (m_width > oldWidth)
|
||||
m_freeRectangles.push_back(Rectui(oldWidth, 0, m_width - oldWidth, oldHeight));
|
||||
|
||||
if (m_height > oldHeight)
|
||||
m_freeRectangles.push_back(Rectui(0, oldHeight, m_width, m_height - oldHeight));
|
||||
|
||||
// On va ensuite fusionner les rectangles tant que possible
|
||||
while (MergeFreeRectangles());
|
||||
}
|
||||
|
||||
void GuillotineBinPack::Expand(const Vector2ui& newSize)
|
||||
{
|
||||
Expand(newSize.x, newSize.y);
|
||||
}
|
||||
|
||||
void GuillotineBinPack::FreeRectangle(const Rectui& rect)
|
||||
{
|
||||
///DOC: Cette méthode ne devrait recevoir que des rectangles calculés par la méthode Insert et peut provoquer de la fragmentation
|
||||
m_freeRectangles.push_back(rect);
|
||||
|
||||
m_usedArea -= rect.width * rect.height;
|
||||
}
|
||||
|
||||
unsigned int GuillotineBinPack::GetHeight() const
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
float GuillotineBinPack::GetOccupancy() const
|
||||
{
|
||||
return static_cast<float>(m_usedArea)/(m_width*m_height);
|
||||
}
|
||||
|
||||
Vector2ui GuillotineBinPack::GetSize() const
|
||||
{
|
||||
return Vector2ui(m_width, m_height);
|
||||
}
|
||||
|
||||
unsigned int GuillotineBinPack::GetWidth() const
|
||||
{
|
||||
return m_width;
|
||||
}
|
||||
|
||||
bool GuillotineBinPack::Insert(Rectui* rects, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
|
||||
{
|
||||
return Insert(rects, nullptr, nullptr, count, merge, rectChoice, splitMethod);
|
||||
}
|
||||
|
||||
bool GuillotineBinPack::Insert(Rectui* rects, bool* flipped, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
|
||||
{
|
||||
return Insert(rects, flipped, nullptr, count, merge, rectChoice, splitMethod);
|
||||
}
|
||||
|
||||
bool GuillotineBinPack::Insert(Rectui* rects, bool* flipped, bool* inserted, unsigned int count, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
|
||||
{
|
||||
std::vector<Rectui*> remainingRects(count); // La position du rectangle
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
remainingRects[i] = &rects[i];
|
||||
|
||||
// Pack rectangles one at a time until we have cleared the rects array of all rectangles.
|
||||
while (!remainingRects.empty())
|
||||
{
|
||||
// Stores the penalty score of the best rectangle placement - bigger=worse, smaller=better.
|
||||
bool bestFlipped;
|
||||
std::size_t bestFreeRect;
|
||||
std::size_t bestRect;
|
||||
int bestScore = std::numeric_limits<int>::max();
|
||||
|
||||
for (std::size_t i = 0; i < m_freeRectangles.size(); ++i)
|
||||
{
|
||||
NzRectui& rect = *remainingRects[j];
|
||||
Rectui& freeRect = m_freeRectangles[i];
|
||||
|
||||
// If this rectangle is a perfect match, we pick it instantly.
|
||||
if (rect.width == freeRect.width && rect.height == freeRect.height)
|
||||
for (std::size_t j = 0; j < remainingRects.size(); ++j)
|
||||
{
|
||||
bestFreeRect = i;
|
||||
bestRect = j;
|
||||
bestFlipped = false;
|
||||
bestScore = std::numeric_limits<int>::min();
|
||||
i = m_freeRectangles.size(); // Force a jump out of the outer loop as well - we got an instant fit.
|
||||
break;
|
||||
}
|
||||
// If flipping this rectangle is a perfect match, pick that then.
|
||||
else if (rect.height == freeRect.width && rect.width == freeRect.height)
|
||||
{
|
||||
bestFreeRect = i;
|
||||
bestRect = j;
|
||||
bestFlipped = true;
|
||||
bestScore = std::numeric_limits<int>::min();
|
||||
i = m_freeRectangles.size(); // Force a jump out of the outer loop as well - we got an instant fit.
|
||||
break;
|
||||
}
|
||||
// Try if we can fit the rectangle upright.
|
||||
else if (rect.width <= freeRect.width && rect.height <= freeRect.height)
|
||||
{
|
||||
int score = ScoreByHeuristic(rect.width, rect.height, freeRect, rectChoice);
|
||||
if (score < bestScore)
|
||||
Rectui& rect = *remainingRects[j];
|
||||
|
||||
// If this rectangle is a perfect match, we pick it instantly.
|
||||
if (rect.width == freeRect.width && rect.height == freeRect.height)
|
||||
{
|
||||
bestFreeRect = i;
|
||||
bestRect = j;
|
||||
bestFlipped = false;
|
||||
bestScore = score;
|
||||
bestScore = std::numeric_limits<int>::min();
|
||||
i = m_freeRectangles.size(); // Force a jump out of the outer loop as well - we got an instant fit.
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If not, then perhaps flipping sideways will make it fit?
|
||||
else if (rect.height <= freeRect.width && rect.width <= freeRect.height)
|
||||
{
|
||||
int score = ScoreByHeuristic(rect.height, rect.width, freeRect, rectChoice);
|
||||
if (score < bestScore)
|
||||
// If flipping this rectangle is a perfect match, pick that then.
|
||||
else if (rect.height == freeRect.width && rect.width == freeRect.height)
|
||||
{
|
||||
bestFreeRect = i;
|
||||
bestRect = j;
|
||||
bestFlipped = true;
|
||||
bestScore = score;
|
||||
bestScore = std::numeric_limits<int>::min();
|
||||
i = m_freeRectangles.size(); // Force a jump out of the outer loop as well - we got an instant fit.
|
||||
break;
|
||||
}
|
||||
// Try if we can fit the rectangle upright.
|
||||
else if (rect.width <= freeRect.width && rect.height <= freeRect.height)
|
||||
{
|
||||
int score = ScoreByHeuristic(rect.width, rect.height, freeRect, rectChoice);
|
||||
if (score < bestScore)
|
||||
{
|
||||
bestFreeRect = i;
|
||||
bestRect = j;
|
||||
bestFlipped = false;
|
||||
bestScore = score;
|
||||
}
|
||||
}
|
||||
// If not, then perhaps flipping sideways will make it fit?
|
||||
else if (rect.height <= freeRect.width && rect.width <= freeRect.height)
|
||||
{
|
||||
int score = ScoreByHeuristic(rect.height, rect.width, freeRect, rectChoice);
|
||||
if (score < bestScore)
|
||||
{
|
||||
bestFreeRect = i;
|
||||
bestRect = j;
|
||||
bestFlipped = true;
|
||||
bestScore = score;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't manage to find any rectangle to pack, abort.
|
||||
if (bestScore == std::numeric_limits<int>::max())
|
||||
{
|
||||
// Si nous le pouvons, on marque les rectangles n'ayant pas pu être insérés
|
||||
if (inserted)
|
||||
{
|
||||
for (Rectui* rect : remainingRects)
|
||||
{
|
||||
std::ptrdiff_t position = rect - rects;
|
||||
inserted[position] = false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, we're good to go and do the actual packing.
|
||||
std::ptrdiff_t position = remainingRects[bestRect] - rects;
|
||||
Rectui& rect = *remainingRects[bestRect];
|
||||
rect.x = m_freeRectangles[bestFreeRect].x;
|
||||
rect.y = m_freeRectangles[bestFreeRect].y;
|
||||
|
||||
if (bestFlipped)
|
||||
std::swap(rect.width, rect.height);
|
||||
|
||||
if (flipped)
|
||||
flipped[position] = bestFlipped;
|
||||
|
||||
if (inserted)
|
||||
inserted[position] = true;
|
||||
|
||||
// Remove the free space we lost in the bin.
|
||||
SplitFreeRectByHeuristic(m_freeRectangles[bestFreeRect], rect, splitMethod);
|
||||
m_freeRectangles.erase(m_freeRectangles.begin() + bestFreeRect);
|
||||
|
||||
// Remove the rectangle we just packed from the input list.
|
||||
remainingRects.erase(remainingRects.begin() + bestRect);
|
||||
|
||||
// Perform a Rectangle Merge step if desired.
|
||||
if (merge)
|
||||
MergeFreeRectangles();
|
||||
|
||||
m_usedArea += rect.width * rect.height;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuillotineBinPack::MergeFreeRectangles()
|
||||
{
|
||||
///DOC: Renvoie true s'il y a eu fusion (et donc si une fusion est encore possible)
|
||||
std::size_t oriSize = m_freeRectangles.size();
|
||||
|
||||
// Do a Theta(n^2) loop to see if any pair of free rectangles could me merged into one.
|
||||
// Note that we miss any opportunities to merge three rectangles into one. (should call this function again to detect that)
|
||||
for (std::size_t i = 0; i < m_freeRectangles.size(); ++i)
|
||||
{
|
||||
Rectui& firstRect = m_freeRectangles[i];
|
||||
|
||||
for (std::size_t j = i+1; j < m_freeRectangles.size(); ++j)
|
||||
{
|
||||
Rectui& secondRect = m_freeRectangles[j];
|
||||
|
||||
if (firstRect.width == secondRect.width && firstRect.x == secondRect.x)
|
||||
{
|
||||
if (firstRect.y == secondRect.y + secondRect.height)
|
||||
{
|
||||
firstRect.y -= secondRect.height;
|
||||
firstRect.height += secondRect.height;
|
||||
m_freeRectangles.erase(m_freeRectangles.begin() + j);
|
||||
--j;
|
||||
}
|
||||
else if (firstRect.y + firstRect.height == secondRect.y)
|
||||
{
|
||||
firstRect.height += secondRect.height;
|
||||
m_freeRectangles.erase(m_freeRectangles.begin() + j);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
else if (firstRect.height == secondRect.height && firstRect.y == secondRect.y)
|
||||
{
|
||||
if (firstRect.x == secondRect.x + secondRect.width)
|
||||
{
|
||||
firstRect.x -= secondRect.width;
|
||||
firstRect.width += secondRect.width;
|
||||
m_freeRectangles.erase(m_freeRectangles.begin() + j);
|
||||
--j;
|
||||
}
|
||||
else if (firstRect.x + firstRect.width == secondRect.x)
|
||||
{
|
||||
firstRect.width += secondRect.width;
|
||||
m_freeRectangles.erase(m_freeRectangles.begin() + j);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't manage to find any rectangle to pack, abort.
|
||||
if (bestScore == std::numeric_limits<int>::max())
|
||||
{
|
||||
// Si nous le pouvons, on marque les rectangles n'ayant pas pu être insérés
|
||||
if (inserted)
|
||||
{
|
||||
for (NzRectui* rect : remainingRects)
|
||||
{
|
||||
unsigned int position = rect - rects;
|
||||
inserted[position] = false;
|
||||
}
|
||||
}
|
||||
return m_freeRectangles.size() < oriSize;
|
||||
}
|
||||
|
||||
return false;
|
||||
void GuillotineBinPack::Reset()
|
||||
{
|
||||
m_height = 0;
|
||||
m_width = 0;
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
void GuillotineBinPack::Reset(unsigned int width, unsigned int height)
|
||||
{
|
||||
m_height = height;
|
||||
m_width = width;
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
void GuillotineBinPack::Reset(const Vector2ui& size)
|
||||
{
|
||||
Reset(size.x, size.y);
|
||||
}
|
||||
|
||||
void GuillotineBinPack::SplitFreeRectAlongAxis(const Rectui& freeRect, const Rectui& placedRect, bool splitHorizontal)
|
||||
{
|
||||
// Form the two new rectangles.
|
||||
Rectui bottom;
|
||||
bottom.x = freeRect.x;
|
||||
bottom.y = freeRect.y + placedRect.height;
|
||||
bottom.height = freeRect.height - placedRect.height;
|
||||
|
||||
Rectui right;
|
||||
right.x = freeRect.x + placedRect.width;
|
||||
right.y = freeRect.y;
|
||||
right.width = freeRect.width - placedRect.width;
|
||||
|
||||
if (splitHorizontal)
|
||||
{
|
||||
bottom.width = freeRect.width;
|
||||
right.height = placedRect.height;
|
||||
}
|
||||
else // Split vertically
|
||||
{
|
||||
bottom.width = placedRect.width;
|
||||
right.height = freeRect.height;
|
||||
}
|
||||
|
||||
// Otherwise, we're good to go and do the actual packing.
|
||||
unsigned int position = remainingRects[bestRect] - rects;
|
||||
NzRectui& rect = *remainingRects[bestRect];
|
||||
rect.x = m_freeRectangles[bestFreeRect].x;
|
||||
rect.y = m_freeRectangles[bestFreeRect].y;
|
||||
// Add the new rectangles into the free rectangle pool if they weren't degenerate.
|
||||
if (bottom.width > 0 && bottom.height > 0)
|
||||
m_freeRectangles.push_back(bottom);
|
||||
|
||||
if (bestFlipped)
|
||||
std::swap(rect.width, rect.height);
|
||||
|
||||
if (flipped)
|
||||
flipped[position] = bestFlipped;
|
||||
|
||||
if (inserted)
|
||||
inserted[position] = true;
|
||||
|
||||
// Remove the free space we lost in the bin.
|
||||
SplitFreeRectByHeuristic(m_freeRectangles[bestFreeRect], rect, splitMethod);
|
||||
m_freeRectangles.erase(m_freeRectangles.begin() + bestFreeRect);
|
||||
|
||||
// Remove the rectangle we just packed from the input list.
|
||||
remainingRects.erase(remainingRects.begin() + bestRect);
|
||||
|
||||
// Perform a Rectangle Merge step if desired.
|
||||
if (merge)
|
||||
MergeFreeRectangles();
|
||||
|
||||
m_usedArea += rect.width * rect.height;
|
||||
if (right.width > 0 && right.height > 0)
|
||||
m_freeRectangles.push_back(right);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzGuillotineBinPack::MergeFreeRectangles()
|
||||
{
|
||||
///DOC: Renvoie true s'il y a eu fusion (et donc si une fusion est encore possible)
|
||||
std::size_t oriSize = m_freeRectangles.size();
|
||||
|
||||
// Do a Theta(n^2) loop to see if any pair of free rectangles could me merged into one.
|
||||
// Note that we miss any opportunities to merge three rectangles into one. (should call this function again to detect that)
|
||||
for (std::size_t i = 0; i < m_freeRectangles.size(); ++i)
|
||||
void GuillotineBinPack::SplitFreeRectByHeuristic(const Rectui& freeRect, const Rectui& placedRect, GuillotineSplitHeuristic method)
|
||||
{
|
||||
NzRectui& firstRect = m_freeRectangles[i];
|
||||
// Compute the lengths of the leftover area.
|
||||
const int w = freeRect.width - placedRect.width;
|
||||
const int h = freeRect.height - placedRect.height;
|
||||
|
||||
for (std::size_t j = i+1; j < m_freeRectangles.size(); ++j)
|
||||
// Placing placedRect into freeRect results in an L-shaped free area, which must be split into
|
||||
// two disjoint rectangles. This can be achieved with by splitting the L-shape using a single line.
|
||||
// We have two choices: horizontal or vertical.
|
||||
|
||||
// Use the given heuristic to decide which choice to make.
|
||||
|
||||
bool splitHorizontal;
|
||||
switch (method)
|
||||
{
|
||||
NzRectui& secondRect = m_freeRectangles[j];
|
||||
case SplitLongerAxis:
|
||||
// Split along the longer total axis.
|
||||
splitHorizontal = (freeRect.width > freeRect.height);
|
||||
break;
|
||||
|
||||
if (firstRect.width == secondRect.width && firstRect.x == secondRect.x)
|
||||
{
|
||||
if (firstRect.y == secondRect.y + secondRect.height)
|
||||
{
|
||||
firstRect.y -= secondRect.height;
|
||||
firstRect.height += secondRect.height;
|
||||
m_freeRectangles.erase(m_freeRectangles.begin() + j);
|
||||
--j;
|
||||
}
|
||||
else if (firstRect.y + firstRect.height == secondRect.y)
|
||||
{
|
||||
firstRect.height += secondRect.height;
|
||||
m_freeRectangles.erase(m_freeRectangles.begin() + j);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
else if (firstRect.height == secondRect.height && firstRect.y == secondRect.y)
|
||||
{
|
||||
if (firstRect.x == secondRect.x + secondRect.width)
|
||||
{
|
||||
firstRect.x -= secondRect.width;
|
||||
firstRect.width += secondRect.width;
|
||||
m_freeRectangles.erase(m_freeRectangles.begin() + j);
|
||||
--j;
|
||||
}
|
||||
else if (firstRect.x + firstRect.width == secondRect.x)
|
||||
{
|
||||
firstRect.width += secondRect.width;
|
||||
m_freeRectangles.erase(m_freeRectangles.begin() + j);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
case SplitLongerLeftoverAxis:
|
||||
// Split along the longer leftover axis.
|
||||
splitHorizontal = (w > h);
|
||||
break;
|
||||
|
||||
case SplitMaximizeArea:
|
||||
// Maximize the smaller area == minimize the larger area.
|
||||
// Tries to make the rectangles more even-sized.
|
||||
splitHorizontal = (placedRect.width * h <= w * placedRect.height);
|
||||
break;
|
||||
|
||||
case SplitMinimizeArea:
|
||||
// Maximize the larger area == minimize the smaller area.
|
||||
// Tries to make the single bigger rectangle.
|
||||
splitHorizontal = (placedRect.width * h > w * placedRect.height);
|
||||
break;
|
||||
|
||||
case SplitShorterAxis:
|
||||
// Split along the shorter total axis.
|
||||
splitHorizontal = (freeRect.width <= freeRect.height);
|
||||
break;
|
||||
|
||||
case SplitShorterLeftoverAxis:
|
||||
// Split along the shorter leftover axis.
|
||||
splitHorizontal = (w <= h);
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraError("Split heuristic out of enum (0x" + String::Number(method, 16) + ')');
|
||||
splitHorizontal = true;
|
||||
}
|
||||
|
||||
// Perform the actual split.
|
||||
SplitFreeRectAlongAxis(freeRect, placedRect, splitHorizontal);
|
||||
}
|
||||
|
||||
return m_freeRectangles.size() < oriSize;
|
||||
}
|
||||
|
||||
void NzGuillotineBinPack::Reset()
|
||||
{
|
||||
m_height = 0;
|
||||
m_width = 0;
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
void NzGuillotineBinPack::Reset(unsigned int width, unsigned int height)
|
||||
{
|
||||
m_height = height;
|
||||
m_width = width;
|
||||
|
||||
Clear();
|
||||
}
|
||||
|
||||
void NzGuillotineBinPack::Reset(const NzVector2ui& size)
|
||||
{
|
||||
Reset(size.x, size.y);
|
||||
}
|
||||
|
||||
void NzGuillotineBinPack::SplitFreeRectAlongAxis(const NzRectui& freeRect, const NzRectui& placedRect, bool splitHorizontal)
|
||||
{
|
||||
// Form the two new rectangles.
|
||||
NzRectui bottom;
|
||||
bottom.x = freeRect.x;
|
||||
bottom.y = freeRect.y + placedRect.height;
|
||||
bottom.height = freeRect.height - placedRect.height;
|
||||
|
||||
NzRectui right;
|
||||
right.x = freeRect.x + placedRect.width;
|
||||
right.y = freeRect.y;
|
||||
right.width = freeRect.width - placedRect.width;
|
||||
|
||||
if (splitHorizontal)
|
||||
int GuillotineBinPack::ScoreByHeuristic(int width, int height, const Rectui& freeRect, FreeRectChoiceHeuristic rectChoice)
|
||||
{
|
||||
bottom.width = freeRect.width;
|
||||
right.height = placedRect.height;
|
||||
}
|
||||
else // Split vertically
|
||||
{
|
||||
bottom.width = placedRect.width;
|
||||
right.height = freeRect.height;
|
||||
}
|
||||
switch (rectChoice)
|
||||
{
|
||||
case RectBestAreaFit:
|
||||
return ScoreBestAreaFit(width, height, freeRect);
|
||||
|
||||
// Add the new rectangles into the free rectangle pool if they weren't degenerate.
|
||||
if (bottom.width > 0 && bottom.height > 0)
|
||||
m_freeRectangles.push_back(bottom);
|
||||
case RectBestLongSideFit:
|
||||
return ScoreBestLongSideFit(width, height, freeRect);
|
||||
|
||||
if (right.width > 0 && right.height > 0)
|
||||
m_freeRectangles.push_back(right);
|
||||
}
|
||||
|
||||
void NzGuillotineBinPack::SplitFreeRectByHeuristic(const NzRectui& freeRect, const NzRectui& placedRect, GuillotineSplitHeuristic method)
|
||||
{
|
||||
// Compute the lengths of the leftover area.
|
||||
const int w = freeRect.width - placedRect.width;
|
||||
const int h = freeRect.height - placedRect.height;
|
||||
|
||||
// Placing placedRect into freeRect results in an L-shaped free area, which must be split into
|
||||
// two disjoint rectangles. This can be achieved with by splitting the L-shape using a single line.
|
||||
// We have two choices: horizontal or vertical.
|
||||
|
||||
// Use the given heuristic to decide which choice to make.
|
||||
|
||||
bool splitHorizontal;
|
||||
switch (method)
|
||||
{
|
||||
case SplitLongerAxis:
|
||||
// Split along the longer total axis.
|
||||
splitHorizontal = (freeRect.width > freeRect.height);
|
||||
break;
|
||||
|
||||
case SplitLongerLeftoverAxis:
|
||||
// Split along the longer leftover axis.
|
||||
splitHorizontal = (w > h);
|
||||
break;
|
||||
|
||||
case SplitMaximizeArea:
|
||||
// Maximize the smaller area == minimize the larger area.
|
||||
// Tries to make the rectangles more even-sized.
|
||||
splitHorizontal = (placedRect.width * h <= w * placedRect.height);
|
||||
break;
|
||||
|
||||
case SplitMinimizeArea:
|
||||
// Maximize the larger area == minimize the smaller area.
|
||||
// Tries to make the single bigger rectangle.
|
||||
splitHorizontal = (placedRect.width * h > w * placedRect.height);
|
||||
break;
|
||||
|
||||
case SplitShorterAxis:
|
||||
// Split along the shorter total axis.
|
||||
splitHorizontal = (freeRect.width <= freeRect.height);
|
||||
break;
|
||||
|
||||
case SplitShorterLeftoverAxis:
|
||||
// Split along the shorter leftover axis.
|
||||
splitHorizontal = (w <= h);
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraError("Split heuristic out of enum (0x" + NzString::Number(method, 16) + ')');
|
||||
splitHorizontal = true;
|
||||
}
|
||||
|
||||
// Perform the actual split.
|
||||
SplitFreeRectAlongAxis(freeRect, placedRect, splitHorizontal);
|
||||
}
|
||||
|
||||
int NzGuillotineBinPack::ScoreByHeuristic(int width, int height, const NzRectui& freeRect, FreeRectChoiceHeuristic rectChoice)
|
||||
{
|
||||
switch (rectChoice)
|
||||
{
|
||||
case RectBestAreaFit:
|
||||
return ScoreBestAreaFit(width, height, freeRect);
|
||||
|
||||
case RectBestLongSideFit:
|
||||
return ScoreBestLongSideFit(width, height, freeRect);
|
||||
|
||||
case RectBestShortSideFit:
|
||||
return ScoreBestShortSideFit(width, height, freeRect);
|
||||
|
||||
case RectWorstAreaFit:
|
||||
return ScoreWorstAreaFit(width, height, freeRect);
|
||||
|
||||
case RectWorstLongSideFit:
|
||||
return ScoreWorstLongSideFit(width, height, freeRect);
|
||||
|
||||
case RectWorstShortSideFit:
|
||||
return ScoreWorstShortSideFit(width, height, freeRect);
|
||||
}
|
||||
|
||||
NazaraError("Rect choice heuristic out of enum (0x" + NzString::Number(rectChoice, 16) + ')');
|
||||
return std::numeric_limits<int>::max();
|
||||
case RectBestShortSideFit:
|
||||
return ScoreBestShortSideFit(width, height, freeRect);
|
||||
|
||||
case RectWorstAreaFit:
|
||||
return ScoreWorstAreaFit(width, height, freeRect);
|
||||
|
||||
case RectWorstLongSideFit:
|
||||
return ScoreWorstLongSideFit(width, height, freeRect);
|
||||
|
||||
case RectWorstShortSideFit:
|
||||
return ScoreWorstShortSideFit(width, height, freeRect);
|
||||
}
|
||||
|
||||
NazaraError("Rect choice heuristic out of enum (0x" + String::Number(rectChoice, 16) + ')');
|
||||
return std::numeric_limits<int>::max();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,224 +18,227 @@
|
||||
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace
|
||||
namespace Nz
|
||||
{
|
||||
struct VendorString
|
||||
namespace
|
||||
{
|
||||
char vendor[13]; // +1 pour le \0 automatiquement ajouté par le compilateur
|
||||
nzProcessorVendor vendorEnum;
|
||||
};
|
||||
|
||||
// Exceptionellement, la valeur "unknown" est intégrée
|
||||
const char* vendorNames[] =
|
||||
{
|
||||
"Unknown", // nzProcessorVendor_Unknown
|
||||
"Advanced Micro Devices", // nzProcessorVendor_AMD
|
||||
"Centaur Technology", // nzProcessorVendor_Centaur
|
||||
"Cyrix Corporation", // nzProcessorVendor_Cyrix
|
||||
"Intel Corporation", // nzProcessorVendor_Intel
|
||||
"Kernel-based Virtual Machine", // nzProcessorVendor_KVM
|
||||
"Microsoft Hyper-V", // nzProcessorVendor_HyperV
|
||||
"National Semiconductor", // nzProcessorVendor_NSC
|
||||
"NexGen", // nzProcessorVendor_NexGen
|
||||
"Rise Technology", // nzProcessorVendor_Rise
|
||||
"Silicon Integrated Systems", // nzProcessorVendor_SIS
|
||||
"Transmeta Corporation", // nzProcessorVendor_Transmeta
|
||||
"United Microelectronics Corporation", // nzProcessorVendor_UMC
|
||||
"VIA Technologies", // nzProcessorVendor_VIA
|
||||
"VMware", // nzProcessorVendor_VMware
|
||||
"Vortex86", // nzProcessorVendor_Vortex
|
||||
"Xen" // nzProcessorVendor_XenHVM
|
||||
};
|
||||
|
||||
static_assert(sizeof(vendorNames)/sizeof(const char*) == nzProcessorVendor_Max+2, "Processor vendor name array is incomplete");
|
||||
|
||||
VendorString vendorStrings[] =
|
||||
{
|
||||
// Triés par ordre alphabétique (Majuscules primant sur minuscules)
|
||||
{"AMDisbetter!", nzProcessorVendor_AMD},
|
||||
{"AuthenticAMD", nzProcessorVendor_AMD},
|
||||
{"CentaurHauls", nzProcessorVendor_Centaur},
|
||||
{"CyrixInstead", nzProcessorVendor_Cyrix},
|
||||
{"GenuineIntel", nzProcessorVendor_Intel},
|
||||
{"GenuineTMx86", nzProcessorVendor_Transmeta},
|
||||
{"Geode by NSC", nzProcessorVendor_NSC},
|
||||
{"KVMKVMKVMKVM", nzProcessorVendor_KVM},
|
||||
{"Microsoft Hv", nzProcessorVendor_HyperV},
|
||||
{"NexGenDriven", nzProcessorVendor_NexGen},
|
||||
{"RiseRiseRise", nzProcessorVendor_Rise},
|
||||
{"SiS SiS SiS ", nzProcessorVendor_SIS},
|
||||
{"TransmetaCPU", nzProcessorVendor_Transmeta},
|
||||
{"UMC UMC UMC ", nzProcessorVendor_UMC},
|
||||
{"VIA VIA VIA ", nzProcessorVendor_VIA},
|
||||
{"VMwareVMware", nzProcessorVendor_VMware},
|
||||
{"Vortex86 SoC", nzProcessorVendor_Vortex},
|
||||
{"XenVMMXenVMM", nzProcessorVendor_XenHVM}
|
||||
};
|
||||
|
||||
nzProcessorVendor s_vendorEnum = nzProcessorVendor_Unknown;
|
||||
bool s_capabilities[nzProcessorCap_Max+1] = {false};
|
||||
bool s_initialized = false;
|
||||
|
||||
char s_brandString[48] = "Not initialized";
|
||||
}
|
||||
|
||||
void NzHardwareInfo::Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 result[4])
|
||||
{
|
||||
return NzHardwareInfoImpl::Cpuid(functionId, subFunctionId, result);
|
||||
}
|
||||
|
||||
NzString NzHardwareInfo::GetProcessorBrandString()
|
||||
{
|
||||
if (!Initialize())
|
||||
NazaraError("Failed to initialize HardwareInfo");
|
||||
|
||||
return s_brandString;
|
||||
}
|
||||
|
||||
unsigned int NzHardwareInfo::GetProcessorCount()
|
||||
{
|
||||
///DOC: Ne nécessite pas l'initialisation de HardwareInfo pour fonctionner
|
||||
static unsigned int processorCount = std::max(NzHardwareInfoImpl::GetProcessorCount(), 1U);
|
||||
return processorCount;
|
||||
}
|
||||
|
||||
nzProcessorVendor NzHardwareInfo::GetProcessorVendor()
|
||||
{
|
||||
if (!Initialize())
|
||||
NazaraError("Failed to initialize HardwareInfo");
|
||||
|
||||
return s_vendorEnum;
|
||||
}
|
||||
|
||||
NzString NzHardwareInfo::GetProcessorVendorName()
|
||||
{
|
||||
if (!Initialize())
|
||||
NazaraError("Failed to initialize HardwareInfo");
|
||||
|
||||
return vendorNames[s_vendorEnum+1];
|
||||
}
|
||||
|
||||
nzUInt64 NzHardwareInfo::GetTotalMemory()
|
||||
{
|
||||
///DOC: Ne nécessite pas l'initialisation de HardwareInfo pour fonctionner
|
||||
static nzUInt64 totalMemory = NzHardwareInfoImpl::GetTotalMemory();
|
||||
return totalMemory;
|
||||
}
|
||||
|
||||
bool NzHardwareInfo::HasCapability(nzProcessorCap capability)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (capability > nzProcessorCap_Max)
|
||||
{
|
||||
NazaraError("Capability type out of enum");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return s_capabilities[capability];
|
||||
}
|
||||
|
||||
bool NzHardwareInfo::Initialize()
|
||||
{
|
||||
if (s_initialized)
|
||||
return true;
|
||||
|
||||
if (!NzHardwareInfoImpl::IsCpuidSupported())
|
||||
{
|
||||
NazaraError("Cpuid is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_initialized = true;
|
||||
|
||||
nzUInt32 registers[4]; // Récupère les quatre registres (EAX, EBX, ECX et EDX)
|
||||
|
||||
// Pour plus de clarté
|
||||
nzUInt32& eax = registers[0];
|
||||
nzUInt32& ebx = registers[1];
|
||||
nzUInt32& ecx = registers[2];
|
||||
nzUInt32& edx = registers[3];
|
||||
|
||||
// Pour commencer, on va récupérer l'identifiant du constructeur ainsi que l'id de fonction maximal supporté par le CPUID
|
||||
NzHardwareInfoImpl::Cpuid(0, 0, registers);
|
||||
|
||||
// Attention à l'ordre : EBX, EDX, ECX
|
||||
nzUInt32 manufacturerId[3] = {ebx, edx, ecx};
|
||||
|
||||
// Identification du concepteur
|
||||
s_vendorEnum = nzProcessorVendor_Unknown;
|
||||
for (const VendorString& vendorString : vendorStrings)
|
||||
{
|
||||
if (std::memcmp(manufacturerId, vendorString.vendor, 12) == 0)
|
||||
struct VendorString
|
||||
{
|
||||
s_vendorEnum = vendorString.vendorEnum;
|
||||
break;
|
||||
char vendor[13]; // +1 pour le \0 automatiquement ajouté par le compilateur
|
||||
ProcessorVendor vendorEnum;
|
||||
};
|
||||
|
||||
// Exceptionellement, la valeur "unknown" est intégrée
|
||||
const char* vendorNames[] =
|
||||
{
|
||||
"Unknown", // ProcessorVendor_Unknown
|
||||
"Advanced Micro Devices", // ProcessorVendor_AMD
|
||||
"Centaur Technology", // ProcessorVendor_Centaur
|
||||
"Cyrix Corporation", // ProcessorVendor_Cyrix
|
||||
"Intel Corporation", // ProcessorVendor_Intel
|
||||
"Kernel-based Virtual Machine", // ProcessorVendor_KVM
|
||||
"Microsoft Hyper-V", // ProcessorVendor_HyperV
|
||||
"National Semiconductor", // ProcessorVendor_NSC
|
||||
"NexGen", // ProcessorVendor_NexGen
|
||||
"Rise Technology", // ProcessorVendor_Rise
|
||||
"Silicon Integrated Systems", // ProcessorVendor_SIS
|
||||
"Transmeta Corporation", // ProcessorVendor_Transmeta
|
||||
"United Microelectronics Corporation", // ProcessorVendor_UMC
|
||||
"VIA Technologies", // ProcessorVendor_VIA
|
||||
"VMware", // ProcessorVendor_VMware
|
||||
"Vortex86", // ProcessorVendor_Vortex
|
||||
"Xen" // ProcessorVendor_XenHVM
|
||||
};
|
||||
|
||||
static_assert(sizeof(vendorNames)/sizeof(const char*) == ProcessorVendor_Max+2, "Processor vendor name array is incomplete");
|
||||
|
||||
VendorString vendorStrings[] =
|
||||
{
|
||||
// Triés par ordre alphabétique (Majuscules primant sur minuscules)
|
||||
{"AMDisbetter!", ProcessorVendor_AMD},
|
||||
{"AuthenticAMD", ProcessorVendor_AMD},
|
||||
{"CentaurHauls", ProcessorVendor_Centaur},
|
||||
{"CyrixInstead", ProcessorVendor_Cyrix},
|
||||
{"GenuineIntel", ProcessorVendor_Intel},
|
||||
{"GenuineTMx86", ProcessorVendor_Transmeta},
|
||||
{"Geode by NSC", ProcessorVendor_NSC},
|
||||
{"KVMKVMKVMKVM", ProcessorVendor_KVM},
|
||||
{"Microsoft Hv", ProcessorVendor_HyperV},
|
||||
{"NexGenDriven", ProcessorVendor_NexGen},
|
||||
{"RiseRiseRise", ProcessorVendor_Rise},
|
||||
{"SiS SiS SiS ", ProcessorVendor_SIS},
|
||||
{"TransmetaCPU", ProcessorVendor_Transmeta},
|
||||
{"UMC UMC UMC ", ProcessorVendor_UMC},
|
||||
{"VIA VIA VIA ", ProcessorVendor_VIA},
|
||||
{"VMwareVMware", ProcessorVendor_VMware},
|
||||
{"Vortex86 SoC", ProcessorVendor_Vortex},
|
||||
{"XenVMMXenVMM", ProcessorVendor_XenHVM}
|
||||
};
|
||||
|
||||
ProcessorVendor s_vendorEnum = ProcessorVendor_Unknown;
|
||||
bool s_capabilities[ProcessorCap_Max+1] = {false};
|
||||
bool s_initialized = false;
|
||||
|
||||
char s_brandString[48] = "Not initialized";
|
||||
}
|
||||
|
||||
void HardwareInfo::Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 result[4])
|
||||
{
|
||||
return HardwareInfoImpl::Cpuid(functionId, subFunctionId, result);
|
||||
}
|
||||
|
||||
String HardwareInfo::GetProcessorBrandString()
|
||||
{
|
||||
if (!Initialize())
|
||||
NazaraError("Failed to initialize HardwareInfo");
|
||||
|
||||
return s_brandString;
|
||||
}
|
||||
|
||||
unsigned int HardwareInfo::GetProcessorCount()
|
||||
{
|
||||
///DOC: Ne nécessite pas l'initialisation de HardwareInfo pour fonctionner
|
||||
static unsigned int processorCount = std::max(HardwareInfoImpl::GetProcessorCount(), 1U);
|
||||
return processorCount;
|
||||
}
|
||||
|
||||
ProcessorVendor HardwareInfo::GetProcessorVendor()
|
||||
{
|
||||
if (!Initialize())
|
||||
NazaraError("Failed to initialize HardwareInfo");
|
||||
|
||||
return s_vendorEnum;
|
||||
}
|
||||
|
||||
String HardwareInfo::GetProcessorVendorName()
|
||||
{
|
||||
if (!Initialize())
|
||||
NazaraError("Failed to initialize HardwareInfo");
|
||||
|
||||
return vendorNames[s_vendorEnum+1];
|
||||
}
|
||||
|
||||
UInt64 HardwareInfo::GetTotalMemory()
|
||||
{
|
||||
///DOC: Ne nécessite pas l'initialisation de HardwareInfo pour fonctionner
|
||||
static UInt64 totalMemory = HardwareInfoImpl::GetTotalMemory();
|
||||
return totalMemory;
|
||||
}
|
||||
|
||||
bool HardwareInfo::HasCapability(ProcessorCap capability)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (capability > ProcessorCap_Max)
|
||||
{
|
||||
NazaraError("Capability type out of enum");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return s_capabilities[capability];
|
||||
}
|
||||
|
||||
if (eax >= 1)
|
||||
bool HardwareInfo::Initialize()
|
||||
{
|
||||
// Récupération de certaines capacités du processeur (ECX et EDX, fonction 1)
|
||||
NzHardwareInfoImpl::Cpuid(1, 0, registers);
|
||||
if (s_initialized)
|
||||
return true;
|
||||
|
||||
s_capabilities[nzProcessorCap_AVX] = (ecx & (1U << 28)) != 0;
|
||||
s_capabilities[nzProcessorCap_FMA3] = (ecx & (1U << 12)) != 0;
|
||||
s_capabilities[nzProcessorCap_MMX] = (edx & (1U << 23)) != 0;
|
||||
s_capabilities[nzProcessorCap_SSE] = (edx & (1U << 25)) != 0;
|
||||
s_capabilities[nzProcessorCap_SSE2] = (edx & (1U << 26)) != 0;
|
||||
s_capabilities[nzProcessorCap_SSE3] = (ecx & (1U << 0)) != 0;
|
||||
s_capabilities[nzProcessorCap_SSSE3] = (ecx & (1U << 9)) != 0;
|
||||
s_capabilities[nzProcessorCap_SSE41] = (ecx & (1U << 19)) != 0;
|
||||
s_capabilities[nzProcessorCap_SSE42] = (ecx & (1U << 20)) != 0;
|
||||
}
|
||||
|
||||
// Récupération de la plus grande fonction étendue supportée (EAX, fonction 0x80000000)
|
||||
NzHardwareInfoImpl::Cpuid(0x80000000, 0, registers);
|
||||
|
||||
nzUInt32 maxSupportedExtendedFunction = eax;
|
||||
if (maxSupportedExtendedFunction >= 0x80000001)
|
||||
{
|
||||
// Récupération des capacités étendues du processeur (ECX et EDX, fonction 0x80000001)
|
||||
NzHardwareInfoImpl::Cpuid(0x80000001, 0, registers);
|
||||
|
||||
s_capabilities[nzProcessorCap_x64] = (edx & (1U << 29)) != 0; // Support du 64bits, indépendant de l'OS
|
||||
s_capabilities[nzProcessorCap_FMA4] = (ecx & (1U << 16)) != 0;
|
||||
s_capabilities[nzProcessorCap_SSE4a] = (ecx & (1U << 6)) != 0;
|
||||
s_capabilities[nzProcessorCap_XOP] = (ecx & (1U << 11)) != 0;
|
||||
|
||||
if (maxSupportedExtendedFunction >= 0x80000004)
|
||||
if (!HardwareInfoImpl::IsCpuidSupported())
|
||||
{
|
||||
// Récupération d'une chaîne de caractère décrivant le processeur (EAX, EBX, ECX et EDX,
|
||||
// fonctions de 0x80000002 à 0x80000004 compris)
|
||||
char* ptr = &s_brandString[0];
|
||||
for (nzUInt32 code = 0x80000002; code <= 0x80000004; ++code)
|
||||
NazaraError("Cpuid is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_initialized = true;
|
||||
|
||||
UInt32 registers[4]; // Récupère les quatre registres (EAX, EBX, ECX et EDX)
|
||||
|
||||
// Pour plus de clarté
|
||||
UInt32& eax = registers[0];
|
||||
UInt32& ebx = registers[1];
|
||||
UInt32& ecx = registers[2];
|
||||
UInt32& edx = registers[3];
|
||||
|
||||
// Pour commencer, on va récupérer l'identifiant du constructeur ainsi que l'id de fonction maximal supporté par le CPUID
|
||||
HardwareInfoImpl::Cpuid(0, 0, registers);
|
||||
|
||||
// Attention à l'ordre : EBX, EDX, ECX
|
||||
UInt32 manufacturerId[3] = {ebx, edx, ecx};
|
||||
|
||||
// Identification du concepteur
|
||||
s_vendorEnum = ProcessorVendor_Unknown;
|
||||
for (const VendorString& vendorString : vendorStrings)
|
||||
{
|
||||
if (std::memcmp(manufacturerId, vendorString.vendor, 12) == 0)
|
||||
{
|
||||
NzHardwareInfoImpl::Cpuid(code, 0, registers);
|
||||
std::memcpy(ptr, ®isters[0], 4*sizeof(nzUInt32)); // On rajoute les 16 octets à la chaîne
|
||||
|
||||
ptr += 4*sizeof(nzUInt32);
|
||||
s_vendorEnum = vendorString.vendorEnum;
|
||||
break;
|
||||
}
|
||||
|
||||
// Le caractère nul faisant partie de la chaîne retournée par le CPUID, pas besoin de le rajouter
|
||||
}
|
||||
|
||||
if (eax >= 1)
|
||||
{
|
||||
// Récupération de certaines capacités du processeur (ECX et EDX, fonction 1)
|
||||
HardwareInfoImpl::Cpuid(1, 0, registers);
|
||||
|
||||
s_capabilities[ProcessorCap_AVX] = (ecx & (1U << 28)) != 0;
|
||||
s_capabilities[ProcessorCap_FMA3] = (ecx & (1U << 12)) != 0;
|
||||
s_capabilities[ProcessorCap_MMX] = (edx & (1U << 23)) != 0;
|
||||
s_capabilities[ProcessorCap_SSE] = (edx & (1U << 25)) != 0;
|
||||
s_capabilities[ProcessorCap_SSE2] = (edx & (1U << 26)) != 0;
|
||||
s_capabilities[ProcessorCap_SSE3] = (ecx & (1U << 0)) != 0;
|
||||
s_capabilities[ProcessorCap_SSSE3] = (ecx & (1U << 9)) != 0;
|
||||
s_capabilities[ProcessorCap_SSE41] = (ecx & (1U << 19)) != 0;
|
||||
s_capabilities[ProcessorCap_SSE42] = (ecx & (1U << 20)) != 0;
|
||||
}
|
||||
|
||||
// Récupération de la plus grande fonction étendue supportée (EAX, fonction 0x80000000)
|
||||
HardwareInfoImpl::Cpuid(0x80000000, 0, registers);
|
||||
|
||||
UInt32 maxSupportedExtendedFunction = eax;
|
||||
if (maxSupportedExtendedFunction >= 0x80000001)
|
||||
{
|
||||
// Récupération des capacités étendues du processeur (ECX et EDX, fonction 0x80000001)
|
||||
HardwareInfoImpl::Cpuid(0x80000001, 0, registers);
|
||||
|
||||
s_capabilities[ProcessorCap_x64] = (edx & (1U << 29)) != 0; // Support du 64bits, indépendant de l'OS
|
||||
s_capabilities[ProcessorCap_FMA4] = (ecx & (1U << 16)) != 0;
|
||||
s_capabilities[ProcessorCap_SSE4a] = (ecx & (1U << 6)) != 0;
|
||||
s_capabilities[ProcessorCap_XOP] = (ecx & (1U << 11)) != 0;
|
||||
|
||||
if (maxSupportedExtendedFunction >= 0x80000004)
|
||||
{
|
||||
// Récupération d'une chaîne de caractère décrivant le processeur (EAX, EBX, ECX et EDX,
|
||||
// fonctions de 0x80000002 à 0x80000004 compris)
|
||||
char* ptr = &s_brandString[0];
|
||||
for (UInt32 code = 0x80000002; code <= 0x80000004; ++code)
|
||||
{
|
||||
HardwareInfoImpl::Cpuid(code, 0, registers);
|
||||
std::memcpy(ptr, ®isters[0], 4*sizeof(UInt32)); // On rajoute les 16 octets à la chaîne
|
||||
|
||||
ptr += 4*sizeof(UInt32);
|
||||
}
|
||||
|
||||
// Le caractère nul faisant partie de la chaîne retournée par le CPUID, pas besoin de le rajouter
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool HardwareInfo::IsCpuidSupported()
|
||||
{
|
||||
return HardwareInfoImpl::IsCpuidSupported();
|
||||
}
|
||||
|
||||
bool NzHardwareInfo::IsCpuidSupported()
|
||||
{
|
||||
return NzHardwareInfoImpl::IsCpuidSupported();
|
||||
}
|
||||
bool HardwareInfo::IsInitialized()
|
||||
{
|
||||
return s_initialized;
|
||||
}
|
||||
|
||||
bool NzHardwareInfo::IsInitialized()
|
||||
{
|
||||
return s_initialized;
|
||||
}
|
||||
|
||||
void NzHardwareInfo::Uninitialize()
|
||||
{
|
||||
// Rien à faire
|
||||
s_initialized = false;
|
||||
void HardwareInfo::Uninitialize()
|
||||
{
|
||||
// Rien à faire
|
||||
s_initialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// 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/Hash.hpp>
|
||||
#include <Nazara/Core/Hash/CRC32.hpp>
|
||||
#include <Nazara/Core/Hash/Fletcher16.hpp>
|
||||
#include <Nazara/Core/Hash/MD5.hpp>
|
||||
#include <Nazara/Core/Hash/SHA1.hpp>
|
||||
#include <Nazara/Core/Hash/SHA224.hpp>
|
||||
#include <Nazara/Core/Hash/SHA256.hpp>
|
||||
#include <Nazara/Core/Hash/SHA384.hpp>
|
||||
#include <Nazara/Core/Hash/SHA512.hpp>
|
||||
#include <Nazara/Core/Hash/Whirlpool.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzHash::NzHash(nzHash hash)
|
||||
{
|
||||
switch (hash)
|
||||
{
|
||||
case nzHash_Fletcher16:
|
||||
m_impl = new NzHashFletcher16;
|
||||
break;
|
||||
|
||||
case nzHash_CRC32:
|
||||
m_impl = new NzHashCRC32;
|
||||
break;
|
||||
|
||||
case nzHash_MD5:
|
||||
m_impl = new NzHashMD5;
|
||||
break;
|
||||
|
||||
case nzHash_SHA1:
|
||||
m_impl = new NzHashSHA1;
|
||||
break;
|
||||
|
||||
case nzHash_SHA224:
|
||||
m_impl = new NzHashSHA224;
|
||||
break;
|
||||
|
||||
case nzHash_SHA256:
|
||||
m_impl = new NzHashSHA256;
|
||||
break;
|
||||
|
||||
case nzHash_SHA384:
|
||||
m_impl = new NzHashSHA384;
|
||||
break;
|
||||
|
||||
case nzHash_SHA512:
|
||||
m_impl = new NzHashSHA512;
|
||||
break;
|
||||
|
||||
case nzHash_Whirlpool:
|
||||
m_impl = new NzHashWhirlpool;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NzHash::NzHash(NzAbstractHash* hashImpl) :
|
||||
m_impl(hashImpl)
|
||||
{
|
||||
}
|
||||
|
||||
NzHash::~NzHash()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
NzHashDigest NzHash::Hash(const NzHashable& hashable)
|
||||
{
|
||||
m_impl->Begin();
|
||||
if (hashable.FillHash(m_impl))
|
||||
return m_impl->End();
|
||||
else // Erreur
|
||||
{
|
||||
m_impl->End();
|
||||
|
||||
return NzHashDigest();
|
||||
}
|
||||
}
|
||||
@@ -6,125 +6,127 @@
|
||||
#include <Nazara/Core/Endianness.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
struct NzHashCRC32_state
|
||||
namespace Nz
|
||||
{
|
||||
nzUInt32 crc;
|
||||
const nzUInt32* table;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
nzUInt32 crc32_reflect(nzUInt32 ref, unsigned int j)
|
||||
struct HashCRC32_state
|
||||
{
|
||||
nzUInt32 value = 0;
|
||||
|
||||
for (unsigned int i = 1; i <= j; ++i)
|
||||
{
|
||||
if (ref & 1)
|
||||
value |= 1 << (j - i);
|
||||
|
||||
ref >>= 1;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static const nzUInt32 crc32_table[256] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
UInt32 crc;
|
||||
const UInt32* table;
|
||||
};
|
||||
}
|
||||
|
||||
NzHashCRC32::NzHashCRC32(nzUInt32 polynomial)
|
||||
{
|
||||
m_state = new NzHashCRC32_state;
|
||||
|
||||
if (polynomial == 0x04c11db7)
|
||||
m_state->table = crc32_table; // Table précalculée (Bien plus rapide)
|
||||
else
|
||||
namespace
|
||||
{
|
||||
nzUInt32* table = new nzUInt32[256];
|
||||
|
||||
for (unsigned int i = 0; i < 256; ++i)
|
||||
UInt32 crc32_reflect(UInt32 ref, unsigned int j)
|
||||
{
|
||||
table[i] = crc32_reflect(i, 8) << 24;
|
||||
for (unsigned int j = 0; j < 8; ++j)
|
||||
table[i] = (table[i] << 1) ^ (table[i] & ((1 << 31) ? polynomial : 0));
|
||||
UInt32 value = 0;
|
||||
|
||||
table[i] = crc32_reflect(table[i], 32);
|
||||
for (unsigned int i = 1; i <= j; ++i)
|
||||
{
|
||||
if (ref & 1)
|
||||
value |= 1 << (j - i);
|
||||
|
||||
ref >>= 1;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
m_state->table = table;
|
||||
static const UInt32 crc32_table[256] = {
|
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
|
||||
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
|
||||
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
|
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
|
||||
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
|
||||
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
|
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
|
||||
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
|
||||
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
|
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
|
||||
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
|
||||
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
|
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
|
||||
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
|
||||
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
|
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
|
||||
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
|
||||
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
|
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
|
||||
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
|
||||
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
|
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
|
||||
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
|
||||
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
|
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
|
||||
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
|
||||
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
|
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
|
||||
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
|
||||
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
|
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
|
||||
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
|
||||
};
|
||||
}
|
||||
|
||||
HashCRC32::HashCRC32(UInt32 polynomial)
|
||||
{
|
||||
m_state = new HashCRC32_state;
|
||||
|
||||
if (polynomial == 0x04c11db7)
|
||||
m_state->table = crc32_table; // Table précalculée (Bien plus rapide)
|
||||
else
|
||||
{
|
||||
UInt32* table = new UInt32[256];
|
||||
|
||||
for (unsigned int i = 0; i < 256; ++i)
|
||||
{
|
||||
table[i] = crc32_reflect(i, 8) << 24;
|
||||
for (unsigned int j = 0; j < 8; ++j)
|
||||
table[i] = (table[i] << 1) ^ (table[i] & ((1 << 31) ? polynomial : 0));
|
||||
|
||||
table[i] = crc32_reflect(table[i], 32);
|
||||
}
|
||||
|
||||
m_state->table = table;
|
||||
}
|
||||
}
|
||||
|
||||
HashCRC32::~HashCRC32()
|
||||
{
|
||||
if (m_state->table != crc32_table)
|
||||
delete[] m_state->table;
|
||||
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void HashCRC32::Append(const UInt8* data, std::size_t len)
|
||||
{
|
||||
while (len--)
|
||||
m_state->crc = m_state->table[(m_state->crc ^ *data++) & 0xFF] ^ (m_state->crc >> 8);
|
||||
}
|
||||
|
||||
void HashCRC32::Begin()
|
||||
{
|
||||
m_state->crc = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
ByteArray HashCRC32::End()
|
||||
{
|
||||
m_state->crc ^= 0xFFFFFFFF;
|
||||
|
||||
#ifdef NAZARA_LITTLE_ENDIAN
|
||||
SwapBytes(&m_state->crc, sizeof(UInt32));
|
||||
#endif
|
||||
|
||||
return ByteArray(reinterpret_cast<UInt8*>(&m_state->crc), 4);
|
||||
}
|
||||
|
||||
std::size_t HashCRC32::GetDigestLength() const
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
const char* HashCRC32::GetHashName() const
|
||||
{
|
||||
return "CRC32";
|
||||
}
|
||||
}
|
||||
|
||||
NzHashCRC32::~NzHashCRC32()
|
||||
{
|
||||
if (m_state->table != crc32_table)
|
||||
delete[] m_state->table;
|
||||
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void NzHashCRC32::Append(const nzUInt8* data, unsigned int len)
|
||||
{
|
||||
while (len--)
|
||||
m_state->crc = m_state->table[(m_state->crc ^ *data++) & 0xFF] ^ (m_state->crc >> 8);
|
||||
}
|
||||
|
||||
void NzHashCRC32::Begin()
|
||||
{
|
||||
m_state->crc = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
NzHashDigest NzHashCRC32::End()
|
||||
{
|
||||
m_state->crc ^= 0xFFFFFFFF;
|
||||
|
||||
#ifdef NAZARA_LITTLE_ENDIAN
|
||||
NzByteSwap(&m_state->crc, sizeof(nzUInt32));
|
||||
#endif
|
||||
|
||||
return NzHashDigest(GetHashName(), reinterpret_cast<nzUInt8*>(&m_state->crc), 4);
|
||||
}
|
||||
|
||||
unsigned int NzHashCRC32::GetDigestLength()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
NzString NzHashCRC32::GetHashName()
|
||||
{
|
||||
static NzString hashName = "CRC32";
|
||||
return hashName;
|
||||
}
|
||||
|
||||
@@ -6,67 +6,69 @@
|
||||
#include <Nazara/Core/Endianness.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
struct NzHashFletcher16_state
|
||||
namespace Nz
|
||||
{
|
||||
nzUInt16 sum1;
|
||||
nzUInt16 sum2;
|
||||
};
|
||||
|
||||
NzHashFletcher16::NzHashFletcher16()
|
||||
{
|
||||
m_state = new NzHashFletcher16_state;
|
||||
}
|
||||
|
||||
NzHashFletcher16::~NzHashFletcher16()
|
||||
{
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void NzHashFletcher16::Append(const nzUInt8* data, unsigned int len)
|
||||
{
|
||||
while (len)
|
||||
struct HashFletcher16_state
|
||||
{
|
||||
unsigned int tlen = std::min(len, 21U);
|
||||
len -= tlen;
|
||||
do
|
||||
{
|
||||
m_state->sum1 += *data++;
|
||||
m_state->sum2 += m_state->sum1;
|
||||
}
|
||||
while (--tlen);
|
||||
UInt16 sum1;
|
||||
UInt16 sum2;
|
||||
};
|
||||
|
||||
HashFletcher16::HashFletcher16()
|
||||
{
|
||||
m_state = new HashFletcher16_state;
|
||||
}
|
||||
|
||||
HashFletcher16::~HashFletcher16()
|
||||
{
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void HashFletcher16::Append(const UInt8* data, std::size_t len)
|
||||
{
|
||||
while (len)
|
||||
{
|
||||
std::size_t tlen = std::min<std::size_t>(len, 21U);
|
||||
len -= tlen;
|
||||
do
|
||||
{
|
||||
m_state->sum1 += *data++;
|
||||
m_state->sum2 += m_state->sum1;
|
||||
}
|
||||
while (--tlen);
|
||||
|
||||
m_state->sum1 = (m_state->sum1 & 0xff) + (m_state->sum1 >> 8);
|
||||
m_state->sum2 = (m_state->sum2 & 0xff) + (m_state->sum2 >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
void HashFletcher16::Begin()
|
||||
{
|
||||
m_state->sum1 = 0xff;
|
||||
m_state->sum2 = 0xff;
|
||||
}
|
||||
|
||||
ByteArray HashFletcher16::End()
|
||||
{
|
||||
m_state->sum1 = (m_state->sum1 & 0xff) + (m_state->sum1 >> 8);
|
||||
m_state->sum2 = (m_state->sum2 & 0xff) + (m_state->sum2 >> 8);
|
||||
|
||||
UInt32 fletcher = (m_state->sum2 << 8) | m_state->sum1;
|
||||
|
||||
#ifdef NAZARA_BIG_ENDIAN
|
||||
SwapBytes(&fletcher, sizeof(UInt32));
|
||||
#endif
|
||||
|
||||
return ByteArray(reinterpret_cast<UInt8*>(&fletcher), 2);
|
||||
}
|
||||
|
||||
std::size_t HashFletcher16::GetDigestLength() const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
const char* HashFletcher16::GetHashName() const
|
||||
{
|
||||
return "Fletcher16";
|
||||
}
|
||||
}
|
||||
|
||||
void NzHashFletcher16::Begin()
|
||||
{
|
||||
m_state->sum1 = 0xff;
|
||||
m_state->sum2 = 0xff;
|
||||
}
|
||||
|
||||
NzHashDigest NzHashFletcher16::End()
|
||||
{
|
||||
m_state->sum1 = (m_state->sum1 & 0xff) + (m_state->sum1 >> 8);
|
||||
m_state->sum2 = (m_state->sum2 & 0xff) + (m_state->sum2 >> 8);
|
||||
|
||||
nzUInt32 fletcher = (m_state->sum2 << 8) | m_state->sum1;
|
||||
|
||||
#ifdef NAZARA_BIG_ENDIAN
|
||||
NzByteSwap(&fletcher, sizeof(nzUInt32));
|
||||
#endif
|
||||
|
||||
return NzHashDigest(GetHashName(), reinterpret_cast<nzUInt8*>(&fletcher), 2);
|
||||
}
|
||||
|
||||
unsigned int NzHashFletcher16::GetDigestLength()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
NzString NzHashFletcher16::GetHashName()
|
||||
{
|
||||
static NzString hashName = "Fletcher16";
|
||||
return hashName;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include <cstring>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
#define T_MASK (static_cast<nzUInt32>(~0))
|
||||
#define T_MASK (static_cast<UInt32>(~0))
|
||||
#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
|
||||
#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
|
||||
#define T3 0x242070db
|
||||
@@ -97,267 +97,268 @@
|
||||
#define T63 0x2ad7d2bb
|
||||
#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
|
||||
|
||||
struct NzHashMD5_state
|
||||
namespace Nz
|
||||
{
|
||||
nzUInt32 count[2]; /* message length in bits, lsw first */
|
||||
nzUInt32 abcd[4]; /* digest buffer */
|
||||
nzUInt8 buf[64]; /* accumulate block */
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
void md5_process(NzHashMD5_state* state, const nzUInt8* data)
|
||||
struct HashMD5_state
|
||||
{
|
||||
nzUInt32 a = state->abcd[0];
|
||||
nzUInt32 b = state->abcd[1];
|
||||
nzUInt32 c = state->abcd[2];
|
||||
nzUInt32 d = state->abcd[3];
|
||||
nzUInt32 t;
|
||||
|
||||
#ifdef NAZARA_BIG_ENDIAN
|
||||
/* Define storage only for big-endian CPUs. */
|
||||
nzUInt32 X[16];
|
||||
|
||||
/*
|
||||
* On big-endian machines, we must arrange the bytes in the
|
||||
* right order.
|
||||
*/
|
||||
const nzUInt8* xp = data;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 16; ++i, xp += 4)
|
||||
X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
|
||||
#else
|
||||
/* Define storage for little-endian or both types of CPUs. */
|
||||
nzUInt32 xbuf[16];
|
||||
const nzUInt32* X;
|
||||
|
||||
/*
|
||||
* On little-endian machines, we can process properly aligned
|
||||
* data without copying it.
|
||||
*/
|
||||
if (!((data - static_cast<const nzUInt8*>(nullptr)) & 3))
|
||||
{
|
||||
/* data are properly aligned */
|
||||
X = reinterpret_cast<const nzUInt32*>(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not aligned */
|
||||
std::memcpy(xbuf, data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* Round 1. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + F(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 7, T1);
|
||||
SET(d, a, b, c, 1, 12, T2);
|
||||
SET(c, d, a, b, 2, 17, T3);
|
||||
SET(b, c, d, a, 3, 22, T4);
|
||||
SET(a, b, c, d, 4, 7, T5);
|
||||
SET(d, a, b, c, 5, 12, T6);
|
||||
SET(c, d, a, b, 6, 17, T7);
|
||||
SET(b, c, d, a, 7, 22, T8);
|
||||
SET(a, b, c, d, 8, 7, T9);
|
||||
SET(d, a, b, c, 9, 12, T10);
|
||||
SET(c, d, a, b, 10, 17, T11);
|
||||
SET(b, c, d, a, 11, 22, T12);
|
||||
SET(a, b, c, d, 12, 7, T13);
|
||||
SET(d, a, b, c, 13, 12, T14);
|
||||
SET(c, d, a, b, 14, 17, T15);
|
||||
SET(b, c, d, a, 15, 22, T16);
|
||||
#undef SET
|
||||
|
||||
/* Round 2. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + G(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 1, 5, T17);
|
||||
SET(d, a, b, c, 6, 9, T18);
|
||||
SET(c, d, a, b, 11, 14, T19);
|
||||
SET(b, c, d, a, 0, 20, T20);
|
||||
SET(a, b, c, d, 5, 5, T21);
|
||||
SET(d, a, b, c, 10, 9, T22);
|
||||
SET(c, d, a, b, 15, 14, T23);
|
||||
SET(b, c, d, a, 4, 20, T24);
|
||||
SET(a, b, c, d, 9, 5, T25);
|
||||
SET(d, a, b, c, 14, 9, T26);
|
||||
SET(c, d, a, b, 3, 14, T27);
|
||||
SET(b, c, d, a, 8, 20, T28);
|
||||
SET(a, b, c, d, 13, 5, T29);
|
||||
SET(d, a, b, c, 2, 9, T30);
|
||||
SET(c, d, a, b, 7, 14, T31);
|
||||
SET(b, c, d, a, 12, 20, T32);
|
||||
#undef SET
|
||||
|
||||
/* Round 3. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + H(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 5, 4, T33);
|
||||
SET(d, a, b, c, 8, 11, T34);
|
||||
SET(c, d, a, b, 11, 16, T35);
|
||||
SET(b, c, d, a, 14, 23, T36);
|
||||
SET(a, b, c, d, 1, 4, T37);
|
||||
SET(d, a, b, c, 4, 11, T38);
|
||||
SET(c, d, a, b, 7, 16, T39);
|
||||
SET(b, c, d, a, 10, 23, T40);
|
||||
SET(a, b, c, d, 13, 4, T41);
|
||||
SET(d, a, b, c, 0, 11, T42);
|
||||
SET(c, d, a, b, 3, 16, T43);
|
||||
SET(b, c, d, a, 6, 23, T44);
|
||||
SET(a, b, c, d, 9, 4, T45);
|
||||
SET(d, a, b, c, 12, 11, T46);
|
||||
SET(c, d, a, b, 15, 16, T47);
|
||||
SET(b, c, d, a, 2, 23, T48);
|
||||
#undef SET
|
||||
|
||||
/* Round 4. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + I(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 6, T49);
|
||||
SET(d, a, b, c, 7, 10, T50);
|
||||
SET(c, d, a, b, 14, 15, T51);
|
||||
SET(b, c, d, a, 5, 21, T52);
|
||||
SET(a, b, c, d, 12, 6, T53);
|
||||
SET(d, a, b, c, 3, 10, T54);
|
||||
SET(c, d, a, b, 10, 15, T55);
|
||||
SET(b, c, d, a, 1, 21, T56);
|
||||
SET(a, b, c, d, 8, 6, T57);
|
||||
SET(d, a, b, c, 15, 10, T58);
|
||||
SET(c, d, a, b, 6, 15, T59);
|
||||
SET(b, c, d, a, 13, 21, T60);
|
||||
SET(a, b, c, d, 4, 6, T61);
|
||||
SET(d, a, b, c, 11, 10, T62);
|
||||
SET(c, d, a, b, 2, 15, T63);
|
||||
SET(b, c, d, a, 9, 21, T64);
|
||||
#undef SET
|
||||
|
||||
/* Then perform the following additions. (That is increment each
|
||||
of the four registers by the value it had before this block
|
||||
was started.) */
|
||||
state->abcd[0] += a;
|
||||
state->abcd[1] += b;
|
||||
state->abcd[2] += c;
|
||||
state->abcd[3] += d;
|
||||
}
|
||||
}
|
||||
|
||||
NzHashMD5::NzHashMD5()
|
||||
{
|
||||
m_state = new NzHashMD5_state;
|
||||
}
|
||||
|
||||
NzHashMD5::~NzHashMD5()
|
||||
{
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void NzHashMD5::Append(const nzUInt8* data, unsigned int len)
|
||||
{
|
||||
const nzUInt8 *p = data;
|
||||
int left = len;
|
||||
int offset = (m_state->count[0] >> 3) & 63;
|
||||
nzUInt32 nbits = len << 3;
|
||||
|
||||
if (len <= 0)
|
||||
return;
|
||||
|
||||
/* Update the message length. */
|
||||
m_state->count[1] += len >> 29;
|
||||
m_state->count[0] += nbits;
|
||||
if (m_state->count[0] < nbits)
|
||||
m_state->count[1]++;
|
||||
|
||||
/* Process an initial partial block. */
|
||||
if (offset)
|
||||
{
|
||||
int copy = (offset + len > 64 ? 64 - offset : len);
|
||||
|
||||
std::memcpy(m_state->buf + offset, p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
|
||||
p += copy;
|
||||
left -= copy;
|
||||
md5_process(m_state, m_state->buf);
|
||||
}
|
||||
|
||||
/* Process full blocks. */
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
md5_process(m_state, p);
|
||||
|
||||
/* Process a final partial block. */
|
||||
if (left)
|
||||
std::memcpy(m_state->buf, p, left);
|
||||
}
|
||||
|
||||
void NzHashMD5::Begin()
|
||||
{
|
||||
m_state->count[0] = m_state->count[1] = 0;
|
||||
m_state->abcd[0] = 0x67452301;
|
||||
m_state->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
|
||||
m_state->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
|
||||
m_state->abcd[3] = 0x10325476;
|
||||
}
|
||||
|
||||
NzHashDigest NzHashMD5::End()
|
||||
{
|
||||
static const unsigned char pad[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
UInt32 count[2]; /* message length in bits, lsw first */
|
||||
UInt32 abcd[4]; /* digest buffer */
|
||||
UInt8 buf[64]; /* accumulate block */
|
||||
};
|
||||
|
||||
nzUInt8 data[8];
|
||||
int i;
|
||||
namespace
|
||||
{
|
||||
void md5_process(HashMD5_state* state, const UInt8* data)
|
||||
{
|
||||
UInt32 a = state->abcd[0];
|
||||
UInt32 b = state->abcd[1];
|
||||
UInt32 c = state->abcd[2];
|
||||
UInt32 d = state->abcd[3];
|
||||
UInt32 t;
|
||||
|
||||
/* Save the length before padding. */
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = static_cast<nzUInt8>(m_state->count[i >> 2] >> ((i & 3) << 3));
|
||||
/* Pad to 56 bytes mod 64. */
|
||||
Append(pad, ((55 - (m_state->count[0] >> 3)) & 63) + 1);
|
||||
/* Append the length. */
|
||||
Append(data, 8);
|
||||
#ifdef NAZARA_BIG_ENDIAN
|
||||
/* Define storage only for big-endian CPUs. */
|
||||
UInt32 X[16];
|
||||
|
||||
nzUInt8 digest[16];
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = static_cast<nzUInt8>(m_state->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
/*
|
||||
* On big-endian machines, we must arrange the bytes in the
|
||||
* right order.
|
||||
*/
|
||||
const UInt8* xp = data;
|
||||
int i;
|
||||
|
||||
return NzHashDigest(GetHashName(), &digest[0], 16);
|
||||
for (i = 0; i < 16; ++i, xp += 4)
|
||||
X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
|
||||
#else
|
||||
/* Define storage for little-endian or both types of CPUs. */
|
||||
UInt32 xbuf[16];
|
||||
const UInt32* X;
|
||||
|
||||
/*
|
||||
* On little-endian machines, we can process properly aligned
|
||||
* data without copying it.
|
||||
*/
|
||||
if (!((data - static_cast<const UInt8*>(nullptr)) & 3))
|
||||
{
|
||||
/* data are properly aligned */
|
||||
X = reinterpret_cast<const UInt32*>(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* not aligned */
|
||||
std::memcpy(xbuf, data, 64);
|
||||
X = xbuf;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
|
||||
/* Round 1. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + F(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 7, T1);
|
||||
SET(d, a, b, c, 1, 12, T2);
|
||||
SET(c, d, a, b, 2, 17, T3);
|
||||
SET(b, c, d, a, 3, 22, T4);
|
||||
SET(a, b, c, d, 4, 7, T5);
|
||||
SET(d, a, b, c, 5, 12, T6);
|
||||
SET(c, d, a, b, 6, 17, T7);
|
||||
SET(b, c, d, a, 7, 22, T8);
|
||||
SET(a, b, c, d, 8, 7, T9);
|
||||
SET(d, a, b, c, 9, 12, T10);
|
||||
SET(c, d, a, b, 10, 17, T11);
|
||||
SET(b, c, d, a, 11, 22, T12);
|
||||
SET(a, b, c, d, 12, 7, T13);
|
||||
SET(d, a, b, c, 13, 12, T14);
|
||||
SET(c, d, a, b, 14, 17, T15);
|
||||
SET(b, c, d, a, 15, 22, T16);
|
||||
#undef SET
|
||||
|
||||
/* Round 2. */
|
||||
/* Let [abcd k s i] denote the operation
|
||||
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + G(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 1, 5, T17);
|
||||
SET(d, a, b, c, 6, 9, T18);
|
||||
SET(c, d, a, b, 11, 14, T19);
|
||||
SET(b, c, d, a, 0, 20, T20);
|
||||
SET(a, b, c, d, 5, 5, T21);
|
||||
SET(d, a, b, c, 10, 9, T22);
|
||||
SET(c, d, a, b, 15, 14, T23);
|
||||
SET(b, c, d, a, 4, 20, T24);
|
||||
SET(a, b, c, d, 9, 5, T25);
|
||||
SET(d, a, b, c, 14, 9, T26);
|
||||
SET(c, d, a, b, 3, 14, T27);
|
||||
SET(b, c, d, a, 8, 20, T28);
|
||||
SET(a, b, c, d, 13, 5, T29);
|
||||
SET(d, a, b, c, 2, 9, T30);
|
||||
SET(c, d, a, b, 7, 14, T31);
|
||||
SET(b, c, d, a, 12, 20, T32);
|
||||
#undef SET
|
||||
|
||||
/* Round 3. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + H(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 5, 4, T33);
|
||||
SET(d, a, b, c, 8, 11, T34);
|
||||
SET(c, d, a, b, 11, 16, T35);
|
||||
SET(b, c, d, a, 14, 23, T36);
|
||||
SET(a, b, c, d, 1, 4, T37);
|
||||
SET(d, a, b, c, 4, 11, T38);
|
||||
SET(c, d, a, b, 7, 16, T39);
|
||||
SET(b, c, d, a, 10, 23, T40);
|
||||
SET(a, b, c, d, 13, 4, T41);
|
||||
SET(d, a, b, c, 0, 11, T42);
|
||||
SET(c, d, a, b, 3, 16, T43);
|
||||
SET(b, c, d, a, 6, 23, T44);
|
||||
SET(a, b, c, d, 9, 4, T45);
|
||||
SET(d, a, b, c, 12, 11, T46);
|
||||
SET(c, d, a, b, 15, 16, T47);
|
||||
SET(b, c, d, a, 2, 23, T48);
|
||||
#undef SET
|
||||
|
||||
/* Round 4. */
|
||||
/* Let [abcd k s t] denote the operation
|
||||
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
#define SET(a, b, c, d, k, s, Ti)\
|
||||
t = a + I(b,c,d) + X[k] + Ti;\
|
||||
a = ROTATE_LEFT(t, s) + b
|
||||
/* Do the following 16 operations. */
|
||||
SET(a, b, c, d, 0, 6, T49);
|
||||
SET(d, a, b, c, 7, 10, T50);
|
||||
SET(c, d, a, b, 14, 15, T51);
|
||||
SET(b, c, d, a, 5, 21, T52);
|
||||
SET(a, b, c, d, 12, 6, T53);
|
||||
SET(d, a, b, c, 3, 10, T54);
|
||||
SET(c, d, a, b, 10, 15, T55);
|
||||
SET(b, c, d, a, 1, 21, T56);
|
||||
SET(a, b, c, d, 8, 6, T57);
|
||||
SET(d, a, b, c, 15, 10, T58);
|
||||
SET(c, d, a, b, 6, 15, T59);
|
||||
SET(b, c, d, a, 13, 21, T60);
|
||||
SET(a, b, c, d, 4, 6, T61);
|
||||
SET(d, a, b, c, 11, 10, T62);
|
||||
SET(c, d, a, b, 2, 15, T63);
|
||||
SET(b, c, d, a, 9, 21, T64);
|
||||
#undef SET
|
||||
|
||||
/* Then perform the following additions. (That is increment each
|
||||
of the four registers by the value it had before this block
|
||||
was started.) */
|
||||
state->abcd[0] += a;
|
||||
state->abcd[1] += b;
|
||||
state->abcd[2] += c;
|
||||
state->abcd[3] += d;
|
||||
}
|
||||
}
|
||||
|
||||
HashMD5::HashMD5()
|
||||
{
|
||||
m_state = new HashMD5_state;
|
||||
}
|
||||
|
||||
HashMD5::~HashMD5()
|
||||
{
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void HashMD5::Append(const UInt8* data, std::size_t len)
|
||||
{
|
||||
const UInt8 *p = data;
|
||||
int left = len;
|
||||
int offset = (m_state->count[0] >> 3) & 63;
|
||||
UInt32 nbits = len << 3;
|
||||
|
||||
if (len <= 0)
|
||||
return;
|
||||
|
||||
/* Update the message length. */
|
||||
m_state->count[1] += len >> 29;
|
||||
m_state->count[0] += nbits;
|
||||
if (m_state->count[0] < nbits)
|
||||
m_state->count[1]++;
|
||||
|
||||
/* Process an initial partial block. */
|
||||
if (offset)
|
||||
{
|
||||
int copy = (offset + len > 64 ? 64 - offset : len);
|
||||
|
||||
std::memcpy(m_state->buf + offset, p, copy);
|
||||
if (offset + copy < 64)
|
||||
return;
|
||||
|
||||
p += copy;
|
||||
left -= copy;
|
||||
md5_process(m_state, m_state->buf);
|
||||
}
|
||||
|
||||
/* Process full blocks. */
|
||||
for (; left >= 64; p += 64, left -= 64)
|
||||
md5_process(m_state, p);
|
||||
|
||||
/* Process a final partial block. */
|
||||
if (left)
|
||||
std::memcpy(m_state->buf, p, left);
|
||||
}
|
||||
|
||||
void HashMD5::Begin()
|
||||
{
|
||||
m_state->count[0] = m_state->count[1] = 0;
|
||||
m_state->abcd[0] = 0x67452301;
|
||||
m_state->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
|
||||
m_state->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
|
||||
m_state->abcd[3] = 0x10325476;
|
||||
}
|
||||
|
||||
ByteArray HashMD5::End()
|
||||
{
|
||||
static const unsigned char pad[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
UInt8 data[8];
|
||||
int i;
|
||||
|
||||
/* Save the length before padding. */
|
||||
for (i = 0; i < 8; ++i)
|
||||
data[i] = static_cast<UInt8>(m_state->count[i >> 2] >> ((i & 3) << 3));
|
||||
/* Pad to 56 bytes mod 64. */
|
||||
Append(pad, ((55 - (m_state->count[0] >> 3)) & 63) + 1);
|
||||
/* Append the length. */
|
||||
Append(data, 8);
|
||||
|
||||
UInt8 digest[16];
|
||||
for (i = 0; i < 16; ++i)
|
||||
digest[i] = static_cast<UInt8>(m_state->abcd[i >> 2] >> ((i & 3) << 3));
|
||||
|
||||
return ByteArray(&digest[0], 16);
|
||||
}
|
||||
|
||||
std::size_t HashMD5::GetDigestLength() const
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
const char* HashMD5::GetHashName() const
|
||||
{
|
||||
return "MD5";
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int NzHashMD5::GetDigestLength()
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
NzString NzHashMD5::GetHashName()
|
||||
{
|
||||
static NzString hashName = "MD5";
|
||||
return hashName;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -56,52 +56,55 @@
|
||||
#define SHA512_DIGEST_LENGTH 64
|
||||
#define SHA512_DIGEST_STRING_LENGTH (SHA512_DIGEST_LENGTH * 2 + 1)
|
||||
|
||||
union SHA_CTX
|
||||
namespace Nz
|
||||
{
|
||||
/* SHA-1 uses this part of the union: */
|
||||
struct
|
||||
{
|
||||
nzUInt32 state[5];
|
||||
nzUInt64 bitcount;
|
||||
nzUInt8 buffer[64];
|
||||
} s1;
|
||||
union SHA_CTX
|
||||
{
|
||||
/* SHA-1 uses this part of the union: */
|
||||
struct
|
||||
{
|
||||
UInt32 state[5];
|
||||
UInt64 bitcount;
|
||||
UInt8 buffer[64];
|
||||
} s1;
|
||||
|
||||
/* SHA-224 and SHA-256 use this part of the union: */
|
||||
struct
|
||||
{
|
||||
nzUInt32 state[8];
|
||||
nzUInt64 bitcount;
|
||||
nzUInt8 buffer[64];
|
||||
} s256;
|
||||
/* SHA-224 and SHA-256 use this part of the union: */
|
||||
struct
|
||||
{
|
||||
UInt32 state[8];
|
||||
UInt64 bitcount;
|
||||
UInt8 buffer[64];
|
||||
} s256;
|
||||
|
||||
/* SHA-384 and SHA-512 use this part of the union: */
|
||||
struct
|
||||
{
|
||||
nzUInt64 state[8];
|
||||
nzUInt64 bitcount[2];
|
||||
nzUInt8 buffer[128];
|
||||
} s512;
|
||||
};
|
||||
/* SHA-384 and SHA-512 use this part of the union: */
|
||||
struct
|
||||
{
|
||||
UInt64 state[8];
|
||||
UInt64 bitcount[2];
|
||||
UInt8 buffer[128];
|
||||
} s512;
|
||||
};
|
||||
|
||||
void SHA1_Init(SHA_CTX*);
|
||||
void SHA1_Update(SHA_CTX*, const nzUInt8*, std::size_t);
|
||||
void SHA1_End(SHA_CTX*, nzUInt8*);
|
||||
void SHA1_Init(SHA_CTX*);
|
||||
void SHA1_Update(SHA_CTX*, const UInt8*, std::size_t);
|
||||
void SHA1_End(SHA_CTX*, UInt8*);
|
||||
|
||||
void SHA224_Init(SHA_CTX*);
|
||||
void SHA224_Update(SHA_CTX*, const nzUInt8*, std::size_t);
|
||||
void SHA224_End(SHA_CTX*, nzUInt8*);
|
||||
void SHA224_Init(SHA_CTX*);
|
||||
void SHA224_Update(SHA_CTX*, const UInt8*, std::size_t);
|
||||
void SHA224_End(SHA_CTX*, UInt8*);
|
||||
|
||||
void SHA256_Init(SHA_CTX*);
|
||||
void SHA256_Update(SHA_CTX*, const nzUInt8*, std::size_t);
|
||||
void SHA256_End(SHA_CTX*, nzUInt8*);
|
||||
void SHA256_Init(SHA_CTX*);
|
||||
void SHA256_Update(SHA_CTX*, const UInt8*, std::size_t);
|
||||
void SHA256_End(SHA_CTX*, UInt8*);
|
||||
|
||||
void SHA384_Init(SHA_CTX*);
|
||||
void SHA384_Update(SHA_CTX*, const nzUInt8*, std::size_t);
|
||||
void SHA384_End(SHA_CTX*, nzUInt8*);
|
||||
void SHA384_Init(SHA_CTX*);
|
||||
void SHA384_Update(SHA_CTX*, const UInt8*, std::size_t);
|
||||
void SHA384_End(SHA_CTX*, UInt8*);
|
||||
|
||||
void SHA512_Init(SHA_CTX*);
|
||||
void SHA512_Update(SHA_CTX*, const nzUInt8*, std::size_t);
|
||||
void SHA512_End(SHA_CTX*, nzUInt8*);
|
||||
void SHA512_Init(SHA_CTX*);
|
||||
void SHA512_Update(SHA_CTX*, const UInt8*, std::size_t);
|
||||
void SHA512_End(SHA_CTX*, UInt8*);
|
||||
}
|
||||
|
||||
#endif /* NAZARA_HASH_SHA2_INTERNAL_HPP */
|
||||
|
||||
|
||||
@@ -6,42 +6,44 @@
|
||||
#include <Nazara/Core/Hash/SHA/Internal.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzHashSHA1::NzHashSHA1()
|
||||
namespace Nz
|
||||
{
|
||||
m_state = new SHA_CTX;
|
||||
}
|
||||
|
||||
NzHashSHA1::~NzHashSHA1()
|
||||
{
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void NzHashSHA1::Append(const nzUInt8* data, unsigned int len)
|
||||
{
|
||||
SHA1_Update(m_state, data, len);
|
||||
}
|
||||
|
||||
void NzHashSHA1::Begin()
|
||||
{
|
||||
SHA1_Init(m_state);
|
||||
}
|
||||
|
||||
NzHashDigest NzHashSHA1::End()
|
||||
{
|
||||
nzUInt8 digest[SHA1_DIGEST_LENGTH];
|
||||
|
||||
SHA1_End(m_state, digest);
|
||||
|
||||
return NzHashDigest(GetHashName(), digest, SHA1_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
unsigned int NzHashSHA1::GetDigestLength()
|
||||
{
|
||||
return SHA1_DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
NzString NzHashSHA1::GetHashName()
|
||||
{
|
||||
static NzString hashName = "SHA1";
|
||||
return hashName;
|
||||
HashSHA1::HashSHA1()
|
||||
{
|
||||
m_state = new SHA_CTX;
|
||||
}
|
||||
|
||||
HashSHA1::~HashSHA1()
|
||||
{
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void HashSHA1::Append(const UInt8* data, std::size_t len)
|
||||
{
|
||||
SHA1_Update(m_state, data, len);
|
||||
}
|
||||
|
||||
void HashSHA1::Begin()
|
||||
{
|
||||
SHA1_Init(m_state);
|
||||
}
|
||||
|
||||
ByteArray HashSHA1::End()
|
||||
{
|
||||
UInt8 digest[SHA1_DIGEST_LENGTH];
|
||||
|
||||
SHA1_End(m_state, digest);
|
||||
|
||||
return ByteArray(digest, SHA1_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
std::size_t HashSHA1::GetDigestLength() const
|
||||
{
|
||||
return SHA1_DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
const char* HashSHA1::GetHashName() const
|
||||
{
|
||||
return "SHA1";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,42 +6,44 @@
|
||||
#include <Nazara/Core/Hash/SHA/Internal.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzHashSHA224::NzHashSHA224()
|
||||
namespace Nz
|
||||
{
|
||||
m_state = new SHA_CTX;
|
||||
}
|
||||
|
||||
NzHashSHA224::~NzHashSHA224()
|
||||
{
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void NzHashSHA224::Append(const nzUInt8* data, unsigned int len)
|
||||
{
|
||||
SHA224_Update(m_state, data, len);
|
||||
}
|
||||
|
||||
void NzHashSHA224::Begin()
|
||||
{
|
||||
SHA224_Init(m_state);
|
||||
}
|
||||
|
||||
NzHashDigest NzHashSHA224::End()
|
||||
{
|
||||
nzUInt8 digest[SHA224_DIGEST_LENGTH];
|
||||
|
||||
SHA224_End(m_state, digest);
|
||||
|
||||
return NzHashDigest(GetHashName(), digest, SHA224_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
unsigned int NzHashSHA224::GetDigestLength()
|
||||
{
|
||||
return SHA224_DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
NzString NzHashSHA224::GetHashName()
|
||||
{
|
||||
static NzString hashName = "SHA224";
|
||||
return hashName;
|
||||
HashSHA224::HashSHA224()
|
||||
{
|
||||
m_state = new SHA_CTX;
|
||||
}
|
||||
|
||||
HashSHA224::~HashSHA224()
|
||||
{
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void HashSHA224::Append(const UInt8* data, std::size_t len)
|
||||
{
|
||||
SHA224_Update(m_state, data, len);
|
||||
}
|
||||
|
||||
void HashSHA224::Begin()
|
||||
{
|
||||
SHA224_Init(m_state);
|
||||
}
|
||||
|
||||
ByteArray HashSHA224::End()
|
||||
{
|
||||
UInt8 digest[SHA224_DIGEST_LENGTH];
|
||||
|
||||
SHA224_End(m_state, digest);
|
||||
|
||||
return ByteArray(digest, SHA224_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
std::size_t HashSHA224::GetDigestLength() const
|
||||
{
|
||||
return SHA224_DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
const char* HashSHA224::GetHashName() const
|
||||
{
|
||||
return "SHA224";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,42 +6,44 @@
|
||||
#include <Nazara/Core/Hash/SHA/Internal.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzHashSHA256::NzHashSHA256()
|
||||
namespace Nz
|
||||
{
|
||||
m_state = new SHA_CTX;
|
||||
}
|
||||
|
||||
NzHashSHA256::~NzHashSHA256()
|
||||
{
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void NzHashSHA256::Append(const nzUInt8* data, unsigned int len)
|
||||
{
|
||||
SHA256_Update(m_state, data, len);
|
||||
}
|
||||
|
||||
void NzHashSHA256::Begin()
|
||||
{
|
||||
SHA256_Init(m_state);
|
||||
}
|
||||
|
||||
NzHashDigest NzHashSHA256::End()
|
||||
{
|
||||
nzUInt8 digest[SHA256_DIGEST_LENGTH];
|
||||
|
||||
SHA256_End(m_state, digest);
|
||||
|
||||
return NzHashDigest(GetHashName(), digest, SHA256_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
unsigned int NzHashSHA256::GetDigestLength()
|
||||
{
|
||||
return SHA256_DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
NzString NzHashSHA256::GetHashName()
|
||||
{
|
||||
static NzString hashName = "SHA256";
|
||||
return hashName;
|
||||
HashSHA256::HashSHA256()
|
||||
{
|
||||
m_state = new SHA_CTX;
|
||||
}
|
||||
|
||||
HashSHA256::~HashSHA256()
|
||||
{
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void HashSHA256::Append(const UInt8* data, std::size_t len)
|
||||
{
|
||||
SHA256_Update(m_state, data, len);
|
||||
}
|
||||
|
||||
void HashSHA256::Begin()
|
||||
{
|
||||
SHA256_Init(m_state);
|
||||
}
|
||||
|
||||
ByteArray HashSHA256::End()
|
||||
{
|
||||
UInt8 digest[SHA256_DIGEST_LENGTH];
|
||||
|
||||
SHA256_End(m_state, digest);
|
||||
|
||||
return ByteArray(digest, SHA256_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
std::size_t HashSHA256::GetDigestLength() const
|
||||
{
|
||||
return SHA256_DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
const char* HashSHA256::GetHashName() const
|
||||
{
|
||||
return "SHA256";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,42 +6,44 @@
|
||||
#include <Nazara/Core/Hash/SHA/Internal.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzHashSHA384::NzHashSHA384()
|
||||
namespace Nz
|
||||
{
|
||||
m_state = new SHA_CTX;
|
||||
}
|
||||
|
||||
NzHashSHA384::~NzHashSHA384()
|
||||
{
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void NzHashSHA384::Append(const nzUInt8* data, unsigned int len)
|
||||
{
|
||||
SHA384_Update(m_state, data, len);
|
||||
}
|
||||
|
||||
void NzHashSHA384::Begin()
|
||||
{
|
||||
SHA384_Init(m_state);
|
||||
}
|
||||
|
||||
NzHashDigest NzHashSHA384::End()
|
||||
{
|
||||
nzUInt8 digest[SHA384_DIGEST_LENGTH];
|
||||
|
||||
SHA384_End(m_state, digest);
|
||||
|
||||
return NzHashDigest(GetHashName(), digest, SHA384_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
unsigned int NzHashSHA384::GetDigestLength()
|
||||
{
|
||||
return SHA384_DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
NzString NzHashSHA384::GetHashName()
|
||||
{
|
||||
static NzString hashName = "SHA384";
|
||||
return hashName;
|
||||
HashSHA384::HashSHA384()
|
||||
{
|
||||
m_state = new SHA_CTX;
|
||||
}
|
||||
|
||||
HashSHA384::~HashSHA384()
|
||||
{
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void HashSHA384::Append(const UInt8* data, std::size_t len)
|
||||
{
|
||||
SHA384_Update(m_state, data, len);
|
||||
}
|
||||
|
||||
void HashSHA384::Begin()
|
||||
{
|
||||
SHA384_Init(m_state);
|
||||
}
|
||||
|
||||
ByteArray HashSHA384::End()
|
||||
{
|
||||
UInt8 digest[SHA384_DIGEST_LENGTH];
|
||||
|
||||
SHA384_End(m_state, digest);
|
||||
|
||||
return ByteArray(digest, SHA384_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
std::size_t HashSHA384::GetDigestLength() const
|
||||
{
|
||||
return SHA384_DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
const char* HashSHA384::GetHashName() const
|
||||
{
|
||||
return "SHA384";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,42 +6,44 @@
|
||||
#include <Nazara/Core/Hash/SHA/Internal.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzHashSHA512::NzHashSHA512()
|
||||
namespace Nz
|
||||
{
|
||||
m_state = new SHA_CTX;
|
||||
}
|
||||
|
||||
NzHashSHA512::~NzHashSHA512()
|
||||
{
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void NzHashSHA512::Append(const nzUInt8* data, unsigned int len)
|
||||
{
|
||||
SHA512_Update(m_state, data, len);
|
||||
}
|
||||
|
||||
void NzHashSHA512::Begin()
|
||||
{
|
||||
SHA512_Init(m_state);
|
||||
}
|
||||
|
||||
NzHashDigest NzHashSHA512::End()
|
||||
{
|
||||
nzUInt8 digest[SHA512_DIGEST_LENGTH];
|
||||
|
||||
SHA512_End(m_state, digest);
|
||||
|
||||
return NzHashDigest(GetHashName(), digest, SHA512_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
unsigned int NzHashSHA512::GetDigestLength()
|
||||
{
|
||||
return SHA512_DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
NzString NzHashSHA512::GetHashName()
|
||||
{
|
||||
static NzString hashName = "SHA512";
|
||||
return hashName;
|
||||
HashSHA512::HashSHA512()
|
||||
{
|
||||
m_state = new SHA_CTX;
|
||||
}
|
||||
|
||||
HashSHA512::~HashSHA512()
|
||||
{
|
||||
delete m_state;
|
||||
}
|
||||
|
||||
void HashSHA512::Append(const UInt8* data, std::size_t len)
|
||||
{
|
||||
SHA512_Update(m_state, data, len);
|
||||
}
|
||||
|
||||
void HashSHA512::Begin()
|
||||
{
|
||||
SHA512_Init(m_state);
|
||||
}
|
||||
|
||||
ByteArray HashSHA512::End()
|
||||
{
|
||||
UInt8 digest[SHA512_DIGEST_LENGTH];
|
||||
|
||||
SHA512_End(m_state, digest);
|
||||
|
||||
return ByteArray(digest, SHA512_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
std::size_t HashSHA512::GetDigestLength() const
|
||||
{
|
||||
return SHA512_DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
const char* HashSHA512::GetHashName() const
|
||||
{
|
||||
return "SHA512";
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,191 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// 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/HashDigest.hpp>
|
||||
#include <Nazara/Core/Config.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzHashDigest::NzHashDigest() :
|
||||
m_digest(nullptr),
|
||||
m_digestLength(0)
|
||||
{
|
||||
}
|
||||
|
||||
NzHashDigest::NzHashDigest(const NzString& hashName, const nzUInt8* digest, unsigned int length) :
|
||||
m_hashName(hashName),
|
||||
m_digestLength(length)
|
||||
{
|
||||
if (m_digestLength > 0)
|
||||
{
|
||||
m_digest = new nzUInt8[length];
|
||||
std::memcpy(m_digest, digest, length);
|
||||
}
|
||||
else
|
||||
m_digest = nullptr;
|
||||
}
|
||||
|
||||
NzHashDigest::NzHashDigest(const NzHashDigest& rhs) :
|
||||
m_hashName(rhs.m_hashName),
|
||||
m_digestLength(rhs.m_digestLength)
|
||||
{
|
||||
if (m_digestLength > 0)
|
||||
{
|
||||
m_digest = new nzUInt8[m_digestLength];
|
||||
std::memcpy(m_digest, rhs.m_digest, m_digestLength);
|
||||
}
|
||||
else
|
||||
m_digest = nullptr;
|
||||
}
|
||||
|
||||
NzHashDigest::NzHashDigest(NzHashDigest&& rhs) noexcept :
|
||||
m_hashName(std::move(rhs.m_hashName)),
|
||||
m_digest(rhs.m_digest),
|
||||
m_digestLength(rhs.m_digestLength)
|
||||
{
|
||||
rhs.m_digest = nullptr;
|
||||
rhs.m_digestLength = 0;
|
||||
}
|
||||
|
||||
NzHashDigest::~NzHashDigest()
|
||||
{
|
||||
delete[] m_digest;
|
||||
}
|
||||
|
||||
bool NzHashDigest::IsValid() const
|
||||
{
|
||||
return m_digestLength > 0;
|
||||
}
|
||||
|
||||
const nzUInt8* NzHashDigest::GetDigest() const
|
||||
{
|
||||
return m_digest;
|
||||
}
|
||||
|
||||
unsigned int NzHashDigest::GetDigestLength() const
|
||||
{
|
||||
return m_digestLength;
|
||||
}
|
||||
|
||||
NzString NzHashDigest::GetHashName() const
|
||||
{
|
||||
return m_hashName;
|
||||
}
|
||||
|
||||
NzString NzHashDigest::ToHex() const
|
||||
{
|
||||
if (m_digestLength == 0)
|
||||
return NzString();
|
||||
|
||||
unsigned int length = m_digestLength*2;
|
||||
|
||||
NzString hexOutput(length);
|
||||
for (unsigned int i = 0; i < m_digestLength; ++i)
|
||||
std::sprintf(&hexOutput[i*2], "%02x", m_digest[i]);
|
||||
|
||||
return hexOutput;
|
||||
}
|
||||
|
||||
nzUInt8 NzHashDigest::operator[](unsigned int pos) const
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (pos >= m_digestLength)
|
||||
{
|
||||
NazaraError("Position out of range");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_digest[pos];
|
||||
}
|
||||
|
||||
NzHashDigest& NzHashDigest::operator=(const NzHashDigest& rhs)
|
||||
{
|
||||
if (this == &rhs)
|
||||
return *this;
|
||||
|
||||
m_hashName = rhs.m_hashName;
|
||||
|
||||
m_digestLength = rhs.m_digestLength;
|
||||
if (m_digestLength > 0)
|
||||
{
|
||||
m_digest = new nzUInt8[m_digestLength];
|
||||
std::memcpy(m_digest, rhs.m_digest, m_digestLength);
|
||||
}
|
||||
else
|
||||
m_digest = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzHashDigest& NzHashDigest::operator=(NzHashDigest&& rhs) noexcept
|
||||
{
|
||||
std::swap(m_hashName, rhs.m_hashName);
|
||||
std::swap(m_digest, rhs.m_digest);
|
||||
std::swap(m_digestLength, rhs.m_digestLength);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool NzHashDigest::operator==(const NzHashDigest& rhs) const
|
||||
{
|
||||
if (m_digest == nullptr || rhs.m_digest == nullptr)
|
||||
return m_digest == rhs.m_digest;
|
||||
|
||||
if (m_digestLength != rhs.m_digestLength)
|
||||
return false;
|
||||
|
||||
return m_hashName == rhs.m_hashName && std::memcmp(m_digest, rhs.m_digest, m_digestLength) == 0;
|
||||
}
|
||||
|
||||
bool NzHashDigest::operator!=(const NzHashDigest& rhs) const
|
||||
{
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
bool NzHashDigest::operator<(const NzHashDigest& rhs) const
|
||||
{
|
||||
if (rhs.m_digest == nullptr)
|
||||
return false;
|
||||
|
||||
if (m_digest == nullptr)
|
||||
return true;
|
||||
|
||||
int cmp = NzString::Compare(m_hashName, rhs.m_hashName);
|
||||
if (cmp == 0)
|
||||
{
|
||||
cmp = std::memcmp(m_digest, rhs.m_digest, std::min(m_digestLength, rhs.m_digestLength));
|
||||
|
||||
if (cmp == 0)
|
||||
return m_digestLength < rhs.m_digestLength;
|
||||
else
|
||||
return cmp < 0;
|
||||
}
|
||||
else
|
||||
return cmp < 0;
|
||||
}
|
||||
|
||||
bool NzHashDigest::operator<=(const NzHashDigest& rhs) const
|
||||
{
|
||||
return !rhs.operator<(*this);
|
||||
}
|
||||
|
||||
bool NzHashDigest::operator>(const NzHashDigest& rhs) const
|
||||
{
|
||||
return rhs.operator<(*this);
|
||||
}
|
||||
|
||||
bool NzHashDigest::operator>=(const NzHashDigest& rhs) const
|
||||
{
|
||||
return !operator<(rhs);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const NzHashDigest& hashstring)
|
||||
{
|
||||
out << hashstring.ToHex();
|
||||
return out;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// 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/Hashable.hpp>
|
||||
#include <Nazara/Core/Hash.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzHashable::~NzHashable() = default;
|
||||
|
||||
NzHashDigest NzHashable::GetHash(nzHash hash) const
|
||||
{
|
||||
NzHash h(hash);
|
||||
return h.Hash(*this);
|
||||
}
|
||||
|
||||
NzHashDigest NzHashable::GetHash(NzAbstractHash* impl) const
|
||||
{
|
||||
NzHash h(impl);
|
||||
return h.Hash(*this);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// 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/InputStream.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/String.hpp>
|
||||
#include <cstring>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzInputStream::~NzInputStream() = default;
|
||||
|
||||
NzString NzInputStream::ReadLine(unsigned int lineSize)
|
||||
{
|
||||
NzString line;
|
||||
if (lineSize == 0) // Taille maximale indéterminée
|
||||
{
|
||||
const unsigned int bufferSize = 64;
|
||||
|
||||
char buffer[bufferSize+1];
|
||||
buffer[bufferSize] = '\0';
|
||||
|
||||
unsigned int readSize;
|
||||
do
|
||||
{
|
||||
readSize = Read(buffer, bufferSize);
|
||||
|
||||
const char* ptr = std::strchr(buffer, '\n');
|
||||
if (ptr)
|
||||
{
|
||||
unsigned int pos = ptr-buffer;
|
||||
|
||||
if (m_streamOptions & nzStreamOption_Text && pos > 0 && buffer[pos-1] == '\r')
|
||||
line.Append(buffer, pos-1);
|
||||
else
|
||||
line.Append(buffer, pos);
|
||||
|
||||
if (!SetCursorPos(GetCursorPos() - readSize + pos + 1))
|
||||
NazaraWarning("Failed to reset cursos pos");
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
line.Append(buffer, readSize);
|
||||
}
|
||||
while (readSize == bufferSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
line.Set(lineSize, '\0');
|
||||
unsigned int readSize = Read(&line[0], lineSize);
|
||||
unsigned int pos = line.Find('\n');
|
||||
if (pos <= readSize) // Faux uniquement si le caractère n'est pas présent (npos étant le plus grand entier)
|
||||
{
|
||||
if (m_streamOptions & nzStreamOption_Text && pos > 0 && line[pos-1] == '\r')
|
||||
line.Resize(pos);
|
||||
else
|
||||
line.Resize(pos+1);
|
||||
|
||||
if (!SetCursorPos(GetCursorPos() - readSize + pos + 1))
|
||||
NazaraWarning("Failed to reset cursos pos");
|
||||
}
|
||||
else
|
||||
line.Resize(readSize);
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
@@ -6,13 +6,16 @@
|
||||
#include <Nazara/Core/Mutex.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzLockGuard::NzLockGuard(NzMutex& mutex) :
|
||||
m_mutex(mutex)
|
||||
namespace Nz
|
||||
{
|
||||
m_mutex.Lock();
|
||||
}
|
||||
LockGuard::LockGuard(Mutex& mutex) :
|
||||
m_mutex(mutex)
|
||||
{
|
||||
m_mutex.Lock();
|
||||
}
|
||||
|
||||
NzLockGuard::~NzLockGuard()
|
||||
{
|
||||
m_mutex.Unlock();
|
||||
LockGuard::~LockGuard()
|
||||
{
|
||||
m_mutex.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,160 +3,73 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/Config.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Core/StringStream.hpp>
|
||||
#include <ctime>
|
||||
#include <cstring>
|
||||
|
||||
#if NAZARA_CORE_DUPLICATE_LOG_TO_COUT
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
#if NAZARA_CORE_THREADSAFE && NAZARA_THREADSAFETY_LOG
|
||||
#include <Nazara/Core/ThreadSafety.hpp>
|
||||
#else
|
||||
#include <Nazara/Core/ThreadSafetyOff.hpp>
|
||||
#endif
|
||||
|
||||
#include <Nazara/Core/AbstractLogger.hpp>
|
||||
#include <Nazara/Core/FileLogger.hpp>
|
||||
#include <Nazara/Core/StdLogger.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace
|
||||
namespace Nz
|
||||
{
|
||||
const char* errorType[] = {
|
||||
"Assert failed: ", // nzErrorType_AssertFailed
|
||||
"Internal error: ", // nzErrorType_Internal
|
||||
"Error: ", // nzErrorType_Normal
|
||||
"Warning: " // nzErrorType_Warning
|
||||
};
|
||||
|
||||
static_assert(sizeof(errorType)/sizeof(const char*) == nzErrorType_Max+1, "Error type array is incomplete");
|
||||
}
|
||||
|
||||
NzLog::NzLog() :
|
||||
m_filePath("NazaraLog.log"),
|
||||
m_file(nullptr),
|
||||
m_append(false),
|
||||
m_enabled(true),
|
||||
m_writeTime(true)
|
||||
{
|
||||
}
|
||||
|
||||
NzLog::~NzLog()
|
||||
{
|
||||
delete m_file;
|
||||
}
|
||||
|
||||
void NzLog::Enable(bool enable)
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
if (m_enabled == enable)
|
||||
return;
|
||||
|
||||
m_enabled = enable;
|
||||
if (!m_enabled && m_file)
|
||||
namespace
|
||||
{
|
||||
delete m_file;
|
||||
m_file = nullptr;
|
||||
StdLogger s_stdLogger;
|
||||
}
|
||||
}
|
||||
|
||||
void NzLog::EnableAppend(bool enable)
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
m_append = enable;
|
||||
if (!m_append && m_file)
|
||||
void Log::Enable(bool enable)
|
||||
{
|
||||
m_file->Delete();
|
||||
m_file = nullptr;
|
||||
s_enabled = enable;
|
||||
}
|
||||
}
|
||||
|
||||
void NzLog::EnableDateTime(bool enable)
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
m_writeTime = enable;
|
||||
}
|
||||
|
||||
NzString NzLog::GetFile() const
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
if (m_file)
|
||||
return m_file->GetPath();
|
||||
else
|
||||
return NzString();
|
||||
}
|
||||
|
||||
bool NzLog::IsEnabled() const
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
void NzLog::SetFile(const NzString& filePath)
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
m_filePath = filePath;
|
||||
if (m_file)
|
||||
m_file->SetFile(filePath);
|
||||
}
|
||||
|
||||
void NzLog::Write(const NzString& string)
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
if (m_enabled)
|
||||
AbstractLogger* Log::GetLogger()
|
||||
{
|
||||
if (!m_file)
|
||||
m_file = new NzFile(m_filePath, nzOpenMode_Text | nzOpenMode_WriteOnly | ((m_append) ? nzOpenMode_Append : nzOpenMode_Truncate));
|
||||
|
||||
NzString line;
|
||||
|
||||
if (m_writeTime)
|
||||
{
|
||||
line.Reserve(23 + string.GetSize() + 1);
|
||||
line.Set(23, '\0'); // Buffer non-initialisé
|
||||
|
||||
time_t currentTime = std::time(nullptr);
|
||||
std::strftime(&line[0], 24, "%d/%m/%Y - %H:%M:%S: ", std::localtime(¤tTime));
|
||||
}
|
||||
else
|
||||
line.Reserve(string.GetSize() + 1);
|
||||
|
||||
line += string;
|
||||
line += '\n';
|
||||
|
||||
if (m_file->IsOpen())
|
||||
m_file->Write(line);
|
||||
|
||||
#if NAZARA_CORE_DUPLICATE_LOG_TO_COUT
|
||||
std::fputs(line.GetConstBuffer(), stdout);
|
||||
#endif
|
||||
return s_logger;
|
||||
}
|
||||
}
|
||||
|
||||
void NzLog::WriteError(nzErrorType type, const NzString& error)
|
||||
{
|
||||
NzStringStream stream;
|
||||
stream << errorType[type] << error;
|
||||
Write(stream);
|
||||
}
|
||||
bool Log::IsEnabled()
|
||||
{
|
||||
return s_enabled;
|
||||
}
|
||||
|
||||
void NzLog::WriteError(nzErrorType type, const NzString& error, unsigned int line, const NzString& file, const NzString& func)
|
||||
{
|
||||
NzStringStream stream;
|
||||
stream << errorType[type] << error << " (" << file << ':' << line << ": " << func << ')';
|
||||
Write(stream);
|
||||
}
|
||||
void Log::SetLogger(AbstractLogger* logger)
|
||||
{
|
||||
if (s_logger != &s_stdLogger)
|
||||
delete s_logger;
|
||||
|
||||
NzLog* NzLog::Instance()
|
||||
{
|
||||
static NzLog log;
|
||||
return &log;
|
||||
s_logger = logger;
|
||||
if (!s_logger)
|
||||
s_logger = &s_stdLogger;
|
||||
}
|
||||
|
||||
void Log::Write(const String& string)
|
||||
{
|
||||
if (s_enabled)
|
||||
s_logger->Write(string);
|
||||
|
||||
OnLogWrite(string);
|
||||
}
|
||||
|
||||
void Log::WriteError(ErrorType type, const String& error, unsigned int line, const char* file, const char* function)
|
||||
{
|
||||
if (s_enabled)
|
||||
s_logger->WriteError(type, error, line, file, function);
|
||||
|
||||
OnLogWriteError(type, error, line, file, function);
|
||||
}
|
||||
|
||||
bool Log::Initialize()
|
||||
{
|
||||
SetLogger(new FileLogger());
|
||||
return true;
|
||||
}
|
||||
|
||||
void Log::Uninitialize()
|
||||
{
|
||||
SetLogger(nullptr);
|
||||
}
|
||||
|
||||
NazaraStaticSignalImpl(Log, OnLogWrite);
|
||||
NazaraStaticSignalImpl(Log, OnLogWriteError);
|
||||
|
||||
AbstractLogger* Log::s_logger = &s_stdLogger;
|
||||
bool Log::s_enabled = true;
|
||||
}
|
||||
|
||||
@@ -17,320 +17,322 @@
|
||||
|
||||
// Le seul fichier n'ayant pas à inclure Debug.hpp
|
||||
|
||||
namespace
|
||||
namespace Nz
|
||||
{
|
||||
constexpr unsigned int s_allocatedId = 0xDEADB33FUL;
|
||||
constexpr unsigned int s_freedId = 0x4B1DUL;
|
||||
|
||||
struct Block
|
||||
namespace
|
||||
{
|
||||
std::size_t size;
|
||||
const char* file;
|
||||
Block* prev;
|
||||
Block* next;
|
||||
bool array;
|
||||
unsigned int line;
|
||||
unsigned int magic;
|
||||
};
|
||||
constexpr unsigned int s_allocatedId = 0xDEADB33FUL;
|
||||
constexpr unsigned int s_freedId = 0x4B1DUL;
|
||||
|
||||
bool s_allocationFilling = true;
|
||||
bool s_allocationLogging = false;
|
||||
bool s_initialized = false;
|
||||
const char* s_logFileName = "NazaraMemory.log";
|
||||
thread_local const char* s_nextFreeFile = "(Internal error)";
|
||||
thread_local unsigned int s_nextFreeLine = 0;
|
||||
|
||||
Block s_list =
|
||||
{
|
||||
0,
|
||||
nullptr,
|
||||
&s_list,
|
||||
&s_list,
|
||||
false,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
unsigned int s_allocationCount = 0;
|
||||
unsigned int s_allocatedBlock = 0;
|
||||
std::size_t s_allocatedSize = 0;
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
CRITICAL_SECTION s_mutex;
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_t s_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
}
|
||||
|
||||
NzMemoryManager::NzMemoryManager()
|
||||
{
|
||||
}
|
||||
|
||||
NzMemoryManager::~NzMemoryManager()
|
||||
{
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
void* NzMemoryManager::Allocate(std::size_t size, bool multi, const char* file, unsigned int line)
|
||||
{
|
||||
if (!s_initialized)
|
||||
Initialize();
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
EnterCriticalSection(&s_mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_lock(&s_mutex);
|
||||
#endif
|
||||
|
||||
Block* ptr = reinterpret_cast<Block*>(std::malloc(size+sizeof(Block)));
|
||||
if (!ptr)
|
||||
{
|
||||
char timeStr[23];
|
||||
TimeInfo(timeStr);
|
||||
|
||||
FILE* log = std::fopen(s_logFileName, "a");
|
||||
|
||||
if (file)
|
||||
std::fprintf(log, "%s Failed to allocate %zu bytes at %s:%u\n", timeStr, size, file, line);
|
||||
else
|
||||
std::fprintf(log, "%s Failed to allocate %zu bytes at unknown position\n", timeStr, size);
|
||||
|
||||
std::fclose(log);
|
||||
|
||||
throw std::bad_alloc();
|
||||
return nullptr; // Ça me rassure d'avoir un return, aussi inutile soit-il
|
||||
}
|
||||
|
||||
ptr->array = multi;
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = size;
|
||||
ptr->magic = s_allocatedId;
|
||||
|
||||
ptr->prev = s_list.prev;
|
||||
ptr->next = &s_list;
|
||||
s_list.prev->next = ptr;
|
||||
s_list.prev = ptr;
|
||||
|
||||
s_allocatedBlock++;
|
||||
s_allocatedSize += size;
|
||||
s_allocationCount++;
|
||||
|
||||
if (s_allocationFilling)
|
||||
{
|
||||
nzUInt8* data = reinterpret_cast<nzUInt8*>(ptr) + sizeof(Block);
|
||||
std::memset(data, 0xFF, size);
|
||||
}
|
||||
|
||||
if (s_allocationLogging)
|
||||
{
|
||||
char timeStr[23];
|
||||
TimeInfo(timeStr);
|
||||
|
||||
FILE* log = std::fopen(s_logFileName, "a");
|
||||
|
||||
if (file)
|
||||
std::fprintf(log, "%s Allocated %zu bytes at %s:%u\n", timeStr, size, file, line);
|
||||
else
|
||||
std::fprintf(log, "%s Allocated %zu bytes at unknown position\n", timeStr, size);
|
||||
|
||||
std::fclose(log);
|
||||
}
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
LeaveCriticalSection(&s_mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_unlock(&s_mutex);
|
||||
#endif
|
||||
|
||||
return reinterpret_cast<nzUInt8*>(ptr) + sizeof(Block);
|
||||
}
|
||||
|
||||
void NzMemoryManager::EnableAllocationFilling(bool allocationFilling)
|
||||
{
|
||||
s_allocationFilling = allocationFilling;
|
||||
}
|
||||
|
||||
void NzMemoryManager::EnableAllocationLogging(bool logAllocations)
|
||||
{
|
||||
s_allocationLogging = logAllocations;
|
||||
}
|
||||
|
||||
void NzMemoryManager::Free(void* pointer, bool multi)
|
||||
{
|
||||
if (!pointer)
|
||||
return;
|
||||
|
||||
Block* ptr = reinterpret_cast<Block*>(reinterpret_cast<nzUInt8*>(pointer) - sizeof(Block));
|
||||
if (ptr->magic != s_allocatedId)
|
||||
{
|
||||
char timeStr[23];
|
||||
TimeInfo(timeStr);
|
||||
|
||||
FILE* log = std::fopen(s_logFileName, "a");
|
||||
|
||||
const char* error = (ptr->magic == s_freedId) ? "double-delete" : "possible delete of dangling pointer";
|
||||
if (s_nextFreeFile)
|
||||
std::fprintf(log, "%s Warning: %s at %s:%u\n", timeStr, error, s_nextFreeFile, s_nextFreeLine);
|
||||
else
|
||||
std::fprintf(log, "%s Warning: %s at unknown position\n", timeStr, error);
|
||||
|
||||
std::fclose(log);
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
EnterCriticalSection(&s_mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_lock(&s_mutex);
|
||||
#endif
|
||||
|
||||
if (ptr->array != multi)
|
||||
{
|
||||
char timeStr[23];
|
||||
TimeInfo(timeStr);
|
||||
|
||||
FILE* log = std::fopen(s_logFileName, "a");
|
||||
|
||||
const char* error = (multi) ? "delete[] after new" : "delete after new[]";
|
||||
if (s_nextFreeFile)
|
||||
std::fprintf(log, "%s Warning: %s at %s:%u\n", timeStr, error, s_nextFreeFile, s_nextFreeLine);
|
||||
else
|
||||
std::fprintf(log, "%s Warning: %s at unknown position\n", timeStr, error);
|
||||
|
||||
std::fclose(log);
|
||||
}
|
||||
|
||||
ptr->magic = s_freedId;
|
||||
ptr->prev->next = ptr->next;
|
||||
ptr->next->prev = ptr->prev;
|
||||
|
||||
s_allocatedBlock--;
|
||||
s_allocatedSize -= ptr->size;
|
||||
|
||||
if (s_allocationFilling)
|
||||
{
|
||||
nzUInt8* data = reinterpret_cast<nzUInt8*>(ptr) + sizeof(Block);
|
||||
std::memset(data, 0xFF, ptr->size);
|
||||
}
|
||||
|
||||
std::free(ptr);
|
||||
|
||||
s_nextFreeFile = nullptr;
|
||||
s_nextFreeLine = 0;
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
LeaveCriticalSection(&s_mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_unlock(&s_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int NzMemoryManager::GetAllocatedBlockCount()
|
||||
{
|
||||
return s_allocatedBlock;
|
||||
}
|
||||
|
||||
std::size_t NzMemoryManager::GetAllocatedSize()
|
||||
{
|
||||
return s_allocatedSize;
|
||||
}
|
||||
|
||||
unsigned int NzMemoryManager::GetAllocationCount()
|
||||
{
|
||||
return s_allocationCount;
|
||||
}
|
||||
|
||||
bool NzMemoryManager::IsAllocationFillingEnabled()
|
||||
{
|
||||
return s_allocationFilling;
|
||||
}
|
||||
|
||||
bool NzMemoryManager::IsAllocationLoggingEnabled()
|
||||
{
|
||||
return s_allocationLogging;
|
||||
}
|
||||
|
||||
void NzMemoryManager::NextFree(const char* file, unsigned int line)
|
||||
{
|
||||
s_nextFreeFile = file;
|
||||
s_nextFreeLine = line;
|
||||
}
|
||||
|
||||
void NzMemoryManager::Initialize()
|
||||
{
|
||||
char timeStr[23];
|
||||
TimeInfo(timeStr);
|
||||
|
||||
FILE* file = std::fopen(s_logFileName, "w");
|
||||
std::fprintf(file, "%s ==============================\n", timeStr);
|
||||
std::fprintf(file, "%s Nazara Memory Leak Tracker \n", timeStr);
|
||||
std::fprintf(file, "%s ==============================\n", timeStr);
|
||||
std::fclose(file);
|
||||
|
||||
if (std::atexit(Uninitialize) != 0)
|
||||
{
|
||||
static NzMemoryManager manager;
|
||||
}
|
||||
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS
|
||||
InitializeCriticalSection(&s_mutex);
|
||||
//#elif defined(NAZARA_PLATFORM_POSIX) is already done in the namespace
|
||||
#endif
|
||||
|
||||
s_initialized = true;
|
||||
}
|
||||
|
||||
void NzMemoryManager::TimeInfo(char buffer[23])
|
||||
{
|
||||
time_t currentTime = std::time(nullptr);
|
||||
std::strftime(buffer, 23, "%d/%m/%Y - %H:%M:%S:", std::localtime(¤tTime));
|
||||
}
|
||||
|
||||
void NzMemoryManager::Uninitialize()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS
|
||||
DeleteCriticalSection(&s_mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_destroy(&s_mutex);
|
||||
#endif
|
||||
|
||||
FILE* log = std::fopen(s_logFileName, "a");
|
||||
|
||||
char timeStr[23];
|
||||
TimeInfo(timeStr);
|
||||
|
||||
std::fprintf(log, "%s Application finished, checking leaks...\n", timeStr);
|
||||
|
||||
if (s_allocatedBlock == 0)
|
||||
{
|
||||
std::fprintf(log, "%s ==============================\n", timeStr);
|
||||
std::fprintf(log, "%s No leak detected \n", timeStr);
|
||||
std::fprintf(log, "%s ==============================", timeStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fprintf(log, "%s ==============================\n", timeStr);
|
||||
std::fprintf(log, "%s Leaks have been detected \n", timeStr);
|
||||
std::fprintf(log, "%s ==============================\n\n", timeStr);
|
||||
std::fputs("Leak list:\n", log);
|
||||
|
||||
Block* ptr = s_list.next;
|
||||
while (ptr != &s_list)
|
||||
struct Block
|
||||
{
|
||||
if (ptr->file)
|
||||
std::fprintf(log, "-0x%p -> %zu bytes allocated at %s:%u\n", reinterpret_cast<nzUInt8*>(ptr) + sizeof(Block), ptr->size, ptr->file, ptr->line);
|
||||
std::size_t size;
|
||||
const char* file;
|
||||
Block* prev;
|
||||
Block* next;
|
||||
bool array;
|
||||
unsigned int line;
|
||||
unsigned int magic;
|
||||
};
|
||||
|
||||
bool s_allocationFilling = true;
|
||||
bool s_allocationLogging = false;
|
||||
bool s_initialized = false;
|
||||
const char* s_logFileName = "NazaraMemory.log";
|
||||
thread_local const char* s_nextFreeFile = "(Internal error)";
|
||||
thread_local unsigned int s_nextFreeLine = 0;
|
||||
|
||||
Block s_list =
|
||||
{
|
||||
0,
|
||||
nullptr,
|
||||
&s_list,
|
||||
&s_list,
|
||||
false,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
unsigned int s_allocationCount = 0;
|
||||
unsigned int s_allocatedBlock = 0;
|
||||
std::size_t s_allocatedSize = 0;
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
CRITICAL_SECTION s_mutex;
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_t s_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
}
|
||||
|
||||
MemoryManager::MemoryManager()
|
||||
{
|
||||
}
|
||||
|
||||
MemoryManager::~MemoryManager()
|
||||
{
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
void* MemoryManager::Allocate(std::size_t size, bool multi, const char* file, unsigned int line)
|
||||
{
|
||||
if (!s_initialized)
|
||||
Initialize();
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
EnterCriticalSection(&s_mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_lock(&s_mutex);
|
||||
#endif
|
||||
|
||||
Block* ptr = reinterpret_cast<Block*>(std::malloc(size+sizeof(Block)));
|
||||
if (!ptr)
|
||||
{
|
||||
char timeStr[23];
|
||||
TimeInfo(timeStr);
|
||||
|
||||
FILE* log = std::fopen(s_logFileName, "a");
|
||||
|
||||
if (file)
|
||||
std::fprintf(log, "%s Failed to allocate %zu bytes at %s:%u\n", timeStr, size, file, line);
|
||||
else
|
||||
std::fprintf(log, "-0x%p -> %zu bytes allocated at unknown position\n", reinterpret_cast<nzUInt8*>(ptr) + sizeof(Block), ptr->size);
|
||||
std::fprintf(log, "%s Failed to allocate %zu bytes at unknown position\n", timeStr, size);
|
||||
|
||||
void* pointer = ptr;
|
||||
ptr = ptr->next;
|
||||
std::fclose(log);
|
||||
|
||||
std::free(pointer);
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
std::fprintf(log, "\n%u blocks leaked (%zu bytes)", s_allocatedBlock, s_allocatedSize);
|
||||
ptr->array = multi;
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = size;
|
||||
ptr->magic = s_allocatedId;
|
||||
|
||||
ptr->prev = s_list.prev;
|
||||
ptr->next = &s_list;
|
||||
s_list.prev->next = ptr;
|
||||
s_list.prev = ptr;
|
||||
|
||||
s_allocatedBlock++;
|
||||
s_allocatedSize += size;
|
||||
s_allocationCount++;
|
||||
|
||||
if (s_allocationFilling)
|
||||
{
|
||||
UInt8* data = reinterpret_cast<UInt8*>(ptr) + sizeof(Block);
|
||||
std::memset(data, 0xFF, size);
|
||||
}
|
||||
|
||||
if (s_allocationLogging)
|
||||
{
|
||||
char timeStr[23];
|
||||
TimeInfo(timeStr);
|
||||
|
||||
FILE* log = std::fopen(s_logFileName, "a");
|
||||
|
||||
if (file)
|
||||
std::fprintf(log, "%s Allocated %zu bytes at %s:%u\n", timeStr, size, file, line);
|
||||
else
|
||||
std::fprintf(log, "%s Allocated %zu bytes at unknown position\n", timeStr, size);
|
||||
|
||||
std::fclose(log);
|
||||
}
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
LeaveCriticalSection(&s_mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_unlock(&s_mutex);
|
||||
#endif
|
||||
|
||||
return reinterpret_cast<UInt8*>(ptr) + sizeof(Block);
|
||||
}
|
||||
|
||||
std::fclose(log);
|
||||
void MemoryManager::EnableAllocationFilling(bool allocationFilling)
|
||||
{
|
||||
s_allocationFilling = allocationFilling;
|
||||
}
|
||||
|
||||
void MemoryManager::EnableAllocationLogging(bool logAllocations)
|
||||
{
|
||||
s_allocationLogging = logAllocations;
|
||||
}
|
||||
|
||||
void MemoryManager::Free(void* pointer, bool multi)
|
||||
{
|
||||
if (!pointer)
|
||||
return;
|
||||
|
||||
Block* ptr = reinterpret_cast<Block*>(reinterpret_cast<UInt8*>(pointer) - sizeof(Block));
|
||||
if (ptr->magic != s_allocatedId)
|
||||
{
|
||||
char timeStr[23];
|
||||
TimeInfo(timeStr);
|
||||
|
||||
FILE* log = std::fopen(s_logFileName, "a");
|
||||
|
||||
const char* error = (ptr->magic == s_freedId) ? "double-delete" : "possible delete of dangling pointer";
|
||||
if (s_nextFreeFile)
|
||||
std::fprintf(log, "%s Warning: %s at %s:%u\n", timeStr, error, s_nextFreeFile, s_nextFreeLine);
|
||||
else
|
||||
std::fprintf(log, "%s Warning: %s at unknown position\n", timeStr, error);
|
||||
|
||||
std::fclose(log);
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
EnterCriticalSection(&s_mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_lock(&s_mutex);
|
||||
#endif
|
||||
|
||||
if (ptr->array != multi)
|
||||
{
|
||||
char timeStr[23];
|
||||
TimeInfo(timeStr);
|
||||
|
||||
FILE* log = std::fopen(s_logFileName, "a");
|
||||
|
||||
const char* error = (multi) ? "delete[] after new" : "delete after new[]";
|
||||
if (s_nextFreeFile)
|
||||
std::fprintf(log, "%s Warning: %s at %s:%u\n", timeStr, error, s_nextFreeFile, s_nextFreeLine);
|
||||
else
|
||||
std::fprintf(log, "%s Warning: %s at unknown position\n", timeStr, error);
|
||||
|
||||
std::fclose(log);
|
||||
}
|
||||
|
||||
ptr->magic = s_freedId;
|
||||
ptr->prev->next = ptr->next;
|
||||
ptr->next->prev = ptr->prev;
|
||||
|
||||
s_allocatedBlock--;
|
||||
s_allocatedSize -= ptr->size;
|
||||
|
||||
if (s_allocationFilling)
|
||||
{
|
||||
UInt8* data = reinterpret_cast<UInt8*>(ptr) + sizeof(Block);
|
||||
std::memset(data, 0xFF, ptr->size);
|
||||
}
|
||||
|
||||
std::free(ptr);
|
||||
|
||||
s_nextFreeFile = nullptr;
|
||||
s_nextFreeLine = 0;
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
LeaveCriticalSection(&s_mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_unlock(&s_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int MemoryManager::GetAllocatedBlockCount()
|
||||
{
|
||||
return s_allocatedBlock;
|
||||
}
|
||||
|
||||
std::size_t MemoryManager::GetAllocatedSize()
|
||||
{
|
||||
return s_allocatedSize;
|
||||
}
|
||||
|
||||
unsigned int MemoryManager::GetAllocationCount()
|
||||
{
|
||||
return s_allocationCount;
|
||||
}
|
||||
|
||||
bool MemoryManager::IsAllocationFillingEnabled()
|
||||
{
|
||||
return s_allocationFilling;
|
||||
}
|
||||
|
||||
bool MemoryManager::IsAllocationLoggingEnabled()
|
||||
{
|
||||
return s_allocationLogging;
|
||||
}
|
||||
|
||||
void MemoryManager::NextFree(const char* file, unsigned int line)
|
||||
{
|
||||
s_nextFreeFile = file;
|
||||
s_nextFreeLine = line;
|
||||
}
|
||||
|
||||
void MemoryManager::Initialize()
|
||||
{
|
||||
char timeStr[23];
|
||||
TimeInfo(timeStr);
|
||||
|
||||
FILE* file = std::fopen(s_logFileName, "w");
|
||||
std::fprintf(file, "%s ==============================\n", timeStr);
|
||||
std::fprintf(file, "%s Nazara Memory Leak Tracker \n", timeStr);
|
||||
std::fprintf(file, "%s ==============================\n", timeStr);
|
||||
std::fclose(file);
|
||||
|
||||
if (std::atexit(Uninitialize) != 0)
|
||||
{
|
||||
static MemoryManager manager;
|
||||
}
|
||||
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS
|
||||
InitializeCriticalSection(&s_mutex);
|
||||
//#elif defined(NAZARA_PLATFORM_POSIX) is already done in the namespace
|
||||
#endif
|
||||
|
||||
s_initialized = true;
|
||||
}
|
||||
|
||||
void MemoryManager::TimeInfo(char buffer[23])
|
||||
{
|
||||
time_t currentTime = std::time(nullptr);
|
||||
std::strftime(buffer, 23, "%d/%m/%Y - %H:%M:%S:", std::localtime(¤tTime));
|
||||
}
|
||||
|
||||
void MemoryManager::Uninitialize()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS
|
||||
DeleteCriticalSection(&s_mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_destroy(&s_mutex);
|
||||
#endif
|
||||
|
||||
FILE* log = std::fopen(s_logFileName, "a");
|
||||
|
||||
char timeStr[23];
|
||||
TimeInfo(timeStr);
|
||||
|
||||
std::fprintf(log, "%s Application finished, checking leaks...\n", timeStr);
|
||||
|
||||
if (s_allocatedBlock == 0)
|
||||
{
|
||||
std::fprintf(log, "%s ==============================\n", timeStr);
|
||||
std::fprintf(log, "%s No leak detected \n", timeStr);
|
||||
std::fprintf(log, "%s ==============================", timeStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fprintf(log, "%s ==============================\n", timeStr);
|
||||
std::fprintf(log, "%s Leaks have been detected \n", timeStr);
|
||||
std::fprintf(log, "%s ==============================\n\n", timeStr);
|
||||
std::fputs("Leak list:\n", log);
|
||||
|
||||
Block* ptr = s_list.next;
|
||||
while (ptr != &s_list)
|
||||
{
|
||||
if (ptr->file)
|
||||
std::fprintf(log, "-0x%p -> %zu bytes allocated at %s:%u\n", reinterpret_cast<UInt8*>(ptr) + sizeof(Block), ptr->size, ptr->file, ptr->line);
|
||||
else
|
||||
std::fprintf(log, "-0x%p -> %zu bytes allocated at unknown position\n", reinterpret_cast<UInt8*>(ptr) + sizeof(Block), ptr->size);
|
||||
|
||||
void* pointer = ptr;
|
||||
ptr = ptr->next;
|
||||
|
||||
std::free(pointer);
|
||||
}
|
||||
|
||||
std::fprintf(log, "\n%u blocks leaked (%zu bytes)", s_allocatedBlock, s_allocatedSize);
|
||||
}
|
||||
|
||||
std::fclose(log);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// 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/MemoryStream.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzMemoryStream::NzMemoryStream(const void* ptr, nzUInt64 size) :
|
||||
m_ptr(reinterpret_cast<const nzUInt8*>(ptr)),
|
||||
m_pos(0),
|
||||
m_size(size)
|
||||
{
|
||||
}
|
||||
|
||||
NzMemoryStream::~NzMemoryStream()
|
||||
{
|
||||
}
|
||||
|
||||
bool NzMemoryStream::EndOfStream() const
|
||||
{
|
||||
return m_pos == m_size;
|
||||
}
|
||||
|
||||
nzUInt64 NzMemoryStream::GetCursorPos() const
|
||||
{
|
||||
return m_pos;
|
||||
}
|
||||
|
||||
nzUInt64 NzMemoryStream::GetSize() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
std::size_t NzMemoryStream::Read(void* buffer, std::size_t size)
|
||||
{
|
||||
unsigned int readSize = std::min(static_cast<unsigned int>(size), static_cast<unsigned int>(m_size-m_pos));
|
||||
|
||||
if (buffer)
|
||||
std::memcpy(buffer, &m_ptr[m_pos], readSize);
|
||||
|
||||
m_pos += readSize;
|
||||
|
||||
return readSize;
|
||||
}
|
||||
|
||||
bool NzMemoryStream::SetCursorPos(nzUInt64 offset)
|
||||
{
|
||||
m_pos = std::min(offset, m_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
63
src/Nazara/Core/MemoryView.cpp
Normal file
63
src/Nazara/Core/MemoryView.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// 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/MemoryView.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
MemoryView::MemoryView(const void* ptr, UInt64 size) :
|
||||
Stream(StreamOption_None, OpenMode_ReadOnly),
|
||||
m_ptr(reinterpret_cast<const UInt8*>(ptr)),
|
||||
m_pos(0),
|
||||
m_size(size)
|
||||
{
|
||||
}
|
||||
|
||||
bool MemoryView::EndOfStream() const
|
||||
{
|
||||
return m_pos >= m_size;
|
||||
}
|
||||
|
||||
UInt64 MemoryView::GetCursorPos() const
|
||||
{
|
||||
return m_pos;
|
||||
}
|
||||
|
||||
UInt64 MemoryView::GetSize() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
bool MemoryView::SetCursorPos(UInt64 offset)
|
||||
{
|
||||
m_pos = std::min(offset, m_size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MemoryView::FlushStream()
|
||||
{
|
||||
NazaraInternalError("FlushStream has been called on a MemoryView");
|
||||
}
|
||||
|
||||
std::size_t MemoryView::ReadBlock(void* buffer, std::size_t size)
|
||||
{
|
||||
std::size_t readSize = std::min<std::size_t>(size, static_cast<std::size_t>(m_size - m_pos));
|
||||
|
||||
if (buffer)
|
||||
std::memcpy(buffer, &m_ptr[m_pos], readSize);
|
||||
|
||||
m_pos += readSize;
|
||||
return readSize;
|
||||
}
|
||||
|
||||
std::size_t MemoryView::WriteBlock(const void* buffer, std::size_t size)
|
||||
{
|
||||
NazaraInternalError("WriteBlock has been called on a MemoryView");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -14,27 +14,30 @@
|
||||
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzMutex::NzMutex()
|
||||
namespace Nz
|
||||
{
|
||||
m_impl = new NzMutexImpl;
|
||||
}
|
||||
Mutex::Mutex()
|
||||
{
|
||||
m_impl = new MutexImpl;
|
||||
}
|
||||
|
||||
NzMutex::~NzMutex()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
Mutex::~Mutex()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
void NzMutex::Lock()
|
||||
{
|
||||
m_impl->Lock();
|
||||
}
|
||||
void Mutex::Lock()
|
||||
{
|
||||
m_impl->Lock();
|
||||
}
|
||||
|
||||
bool NzMutex::TryLock()
|
||||
{
|
||||
return m_impl->TryLock();
|
||||
}
|
||||
bool Mutex::TryLock()
|
||||
{
|
||||
return m_impl->TryLock();
|
||||
}
|
||||
|
||||
void NzMutex::Unlock()
|
||||
{
|
||||
m_impl->Unlock();
|
||||
void Mutex::Unlock()
|
||||
{
|
||||
m_impl->Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,447 +10,439 @@
|
||||
#include <new>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzParameterList::NzParameterList(const NzParameterList& list)
|
||||
namespace Nz
|
||||
{
|
||||
operator=(list);
|
||||
}
|
||||
|
||||
NzParameterList::NzParameterList(NzParameterList&& list) :
|
||||
m_parameters(std::move(list.m_parameters))
|
||||
{
|
||||
}
|
||||
|
||||
NzParameterList::~NzParameterList()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void NzParameterList::Clear()
|
||||
{
|
||||
for (auto it = m_parameters.begin(); it != m_parameters.end(); ++it)
|
||||
DestroyValue(it->second);
|
||||
|
||||
m_parameters.clear();
|
||||
}
|
||||
|
||||
bool NzParameterList::GetBooleanParameter(const NzString& name, bool* value) const
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it == m_parameters.end())
|
||||
ParameterList::ParameterList(const ParameterList& list)
|
||||
{
|
||||
NazaraError("Parameter \"" + name + "\" is not present");
|
||||
return false;
|
||||
operator=(list);
|
||||
}
|
||||
|
||||
switch (it->second.type)
|
||||
ParameterList::~ParameterList()
|
||||
{
|
||||
case nzParameterType_Boolean:
|
||||
*value = it->second.value.boolVal;
|
||||
return true;
|
||||
Clear();
|
||||
}
|
||||
|
||||
case nzParameterType_Integer:
|
||||
*value = (it->second.value.intVal != 0);
|
||||
return true;
|
||||
void ParameterList::Clear()
|
||||
{
|
||||
for (auto it = m_parameters.begin(); it != m_parameters.end(); ++it)
|
||||
DestroyValue(it->second);
|
||||
|
||||
case nzParameterType_String:
|
||||
m_parameters.clear();
|
||||
}
|
||||
|
||||
bool ParameterList::GetBooleanParameter(const String& name, bool* value) const
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it == m_parameters.end())
|
||||
{
|
||||
bool converted;
|
||||
if (it->second.value.stringVal.ToBool(&converted, NzString::CaseInsensitive))
|
||||
{
|
||||
*value = converted;
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case nzParameterType_Float:
|
||||
case nzParameterType_None:
|
||||
case nzParameterType_Pointer:
|
||||
case nzParameterType_Userdata:
|
||||
break;
|
||||
}
|
||||
|
||||
NazaraError("Parameter value is not representable as a boolean");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NzParameterList::GetFloatParameter(const NzString& name, float* value) const
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it == m_parameters.end())
|
||||
{
|
||||
NazaraError("Parameter \"" + name + "\" is not present");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (it->second.type)
|
||||
{
|
||||
case nzParameterType_Float:
|
||||
*value = it->second.value.floatVal;
|
||||
return true;
|
||||
|
||||
case nzParameterType_Integer:
|
||||
*value = static_cast<float>(it->second.value.intVal);
|
||||
return true;
|
||||
|
||||
case nzParameterType_String:
|
||||
{
|
||||
double converted;
|
||||
if (it->second.value.stringVal.ToDouble(&converted))
|
||||
{
|
||||
*value = static_cast<float>(converted);
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case nzParameterType_Boolean:
|
||||
case nzParameterType_None:
|
||||
case nzParameterType_Pointer:
|
||||
case nzParameterType_Userdata:
|
||||
break;
|
||||
}
|
||||
|
||||
NazaraError("Parameter value is not representable as a float");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NzParameterList::GetIntegerParameter(const NzString& name, int* value) const
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it == m_parameters.end())
|
||||
{
|
||||
NazaraError("Parameter \"" + name + "\" is not present");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (it->second.type)
|
||||
{
|
||||
case nzParameterType_Boolean:
|
||||
*value = (it->second.value.boolVal) ? 1 : 0;
|
||||
return true;
|
||||
|
||||
case nzParameterType_Float:
|
||||
*value = static_cast<int>(it->second.value.floatVal);
|
||||
return true;
|
||||
|
||||
case nzParameterType_Integer:
|
||||
*value = it->second.value.intVal;
|
||||
NazaraError("Parameter \"" + name + "\" is not present");
|
||||
return false;
|
||||
|
||||
case nzParameterType_String:
|
||||
{
|
||||
long long converted;
|
||||
if (it->second.value.stringVal.ToInteger(&converted))
|
||||
{
|
||||
if (converted <= std::numeric_limits<int>::max() && converted >= std::numeric_limits<int>::min())
|
||||
{
|
||||
*value = static_cast<int>(converted);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case nzParameterType_None:
|
||||
case nzParameterType_Pointer:
|
||||
case nzParameterType_Userdata:
|
||||
break;
|
||||
}
|
||||
|
||||
NazaraError("Parameter value is not representable as a integer");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NzParameterList::GetParameterType(const NzString& name, nzParameterType* type) const
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it == m_parameters.end())
|
||||
return false;
|
||||
|
||||
*type = it->second.type;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzParameterList::GetPointerParameter(const NzString& name, void** value) const
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it == m_parameters.end())
|
||||
{
|
||||
NazaraError("Parameter \"" + name + "\" is not present");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (it->second.type)
|
||||
{
|
||||
case nzParameterType_Pointer:
|
||||
*value = it->second.value.ptrVal;
|
||||
return true;
|
||||
|
||||
case nzParameterType_Userdata:
|
||||
*value = it->second.value.userdataVal->ptr;
|
||||
return true;
|
||||
|
||||
case nzParameterType_Boolean:
|
||||
case nzParameterType_Float:
|
||||
case nzParameterType_Integer:
|
||||
case nzParameterType_None:
|
||||
case nzParameterType_String:
|
||||
break;
|
||||
}
|
||||
|
||||
NazaraError("Parameter value is not a pointer");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NzParameterList::GetStringParameter(const NzString& name, NzString* value) const
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it == m_parameters.end())
|
||||
{
|
||||
NazaraError("Parameter \"" + name + "\" is not present");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (it->second.type)
|
||||
{
|
||||
case nzParameterType_Boolean:
|
||||
*value = NzString::Boolean(it->second.value.boolVal);
|
||||
return true;
|
||||
|
||||
case nzParameterType_Float:
|
||||
*value = NzString::Number(it->second.value.floatVal);
|
||||
return true;
|
||||
|
||||
case nzParameterType_Integer:
|
||||
*value = NzString::Number(it->second.value.intVal);
|
||||
return true;
|
||||
|
||||
case nzParameterType_String:
|
||||
*value = it->second.value.stringVal;
|
||||
return true;
|
||||
|
||||
case nzParameterType_Pointer:
|
||||
*value = NzString::Pointer(it->second.value.ptrVal);
|
||||
return true;
|
||||
|
||||
case nzParameterType_Userdata:
|
||||
*value = NzString::Pointer(it->second.value.userdataVal->ptr);
|
||||
return true;
|
||||
|
||||
case nzParameterType_None:
|
||||
*value = NzString();
|
||||
return true;
|
||||
}
|
||||
|
||||
NazaraInternalError("Parameter value is not valid");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NzParameterList::GetUserdataParameter(const NzString& name, void** value) const
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it == m_parameters.end())
|
||||
{
|
||||
NazaraError("Parameter \"" + name + "\" is not present");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (it->second.type == nzParameterType_Userdata)
|
||||
{
|
||||
*value = it->second.value.userdataVal->ptr;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraError("Parameter value is not a userdata");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool NzParameterList::HasParameter(const NzString& name) const
|
||||
{
|
||||
return m_parameters.find(name) != m_parameters.end();
|
||||
}
|
||||
|
||||
void NzParameterList::RemoveParameter(const NzString& name)
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it != m_parameters.end())
|
||||
{
|
||||
DestroyValue(it->second);
|
||||
m_parameters.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void NzParameterList::SetParameter(const NzString& name)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = nzParameterType_None;
|
||||
}
|
||||
|
||||
void NzParameterList::SetParameter(const NzString& name, const NzString& value)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = nzParameterType_String;
|
||||
|
||||
NzPlacementNew<NzString>(¶meter.value.stringVal, value);
|
||||
}
|
||||
|
||||
void NzParameterList::SetParameter(const NzString& name, const char* value)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = nzParameterType_String;
|
||||
|
||||
NzPlacementNew<NzString>(¶meter.value.stringVal, value);
|
||||
}
|
||||
|
||||
void NzParameterList::SetParameter(const NzString& name, void* value)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = nzParameterType_Pointer;
|
||||
parameter.value.ptrVal = value;
|
||||
}
|
||||
|
||||
void NzParameterList::SetParameter(const NzString& name, void* value, Destructor destructor)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = nzParameterType_Userdata;
|
||||
parameter.value.userdataVal = new Parameter::UserdataValue(destructor, value);
|
||||
}
|
||||
|
||||
void NzParameterList::SetParameter(const NzString& name, bool value)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = nzParameterType_Boolean;
|
||||
parameter.value.boolVal = value;
|
||||
}
|
||||
|
||||
void NzParameterList::SetParameter(const NzString& name, float value)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = nzParameterType_Float;
|
||||
parameter.value.floatVal = value;
|
||||
}
|
||||
|
||||
void NzParameterList::SetParameter(const NzString& name, int value)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = nzParameterType_Integer;
|
||||
parameter.value.intVal = value;
|
||||
}
|
||||
|
||||
NzParameterList& NzParameterList::operator=(const NzParameterList& list)
|
||||
{
|
||||
Clear();
|
||||
|
||||
for (auto it = list.m_parameters.begin(); it != list.m_parameters.end(); ++it)
|
||||
{
|
||||
Parameter& parameter = m_parameters[it->first];
|
||||
|
||||
switch (it->second.type)
|
||||
{
|
||||
case nzParameterType_Boolean:
|
||||
case nzParameterType_Float:
|
||||
case nzParameterType_Integer:
|
||||
case nzParameterType_Pointer:
|
||||
std::memcpy(¶meter, &it->second, sizeof(Parameter));
|
||||
break;
|
||||
case ParameterType_Boolean:
|
||||
*value = it->second.value.boolVal;
|
||||
return true;
|
||||
|
||||
case nzParameterType_String:
|
||||
parameter.type = nzParameterType_String;
|
||||
case ParameterType_Integer:
|
||||
*value = (it->second.value.intVal != 0);
|
||||
return true;
|
||||
|
||||
NzPlacementNew<NzString>(¶meter.value.stringVal, it->second.value.stringVal);
|
||||
break;
|
||||
|
||||
case nzParameterType_Userdata:
|
||||
parameter.type = nzParameterType_Userdata;
|
||||
parameter.value.userdataVal = it->second.value.userdataVal;
|
||||
++(parameter.value.userdataVal->counter);
|
||||
break;
|
||||
|
||||
case nzParameterType_None:
|
||||
parameter.type = nzParameterType_None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzParameterList& NzParameterList::operator=(NzParameterList&& list)
|
||||
{
|
||||
m_parameters = std::move(list.m_parameters);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void NzParameterList::DestroyValue(Parameter& parameter)
|
||||
{
|
||||
switch (parameter.type)
|
||||
{
|
||||
case nzParameterType_String:
|
||||
parameter.value.stringVal.~NzString();
|
||||
break;
|
||||
|
||||
case nzParameterType_Userdata:
|
||||
{
|
||||
Parameter::UserdataValue* userdata = parameter.value.userdataVal;
|
||||
if (--userdata->counter == 0)
|
||||
case ParameterType_String:
|
||||
{
|
||||
userdata->destructor(userdata->ptr);
|
||||
delete userdata;
|
||||
bool converted;
|
||||
if (it->second.value.stringVal.ToBool(&converted, String::CaseInsensitive))
|
||||
{
|
||||
*value = converted;
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case ParameterType_Float:
|
||||
case ParameterType_None:
|
||||
case ParameterType_Pointer:
|
||||
case ParameterType_Userdata:
|
||||
break;
|
||||
}
|
||||
|
||||
case nzParameterType_Boolean:
|
||||
case nzParameterType_Float:
|
||||
case nzParameterType_Integer:
|
||||
case nzParameterType_None:
|
||||
case nzParameterType_Pointer:
|
||||
break;
|
||||
NazaraError("Parameter value is not representable as a boolean");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParameterList::GetFloatParameter(const String& name, float* value) const
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it == m_parameters.end())
|
||||
{
|
||||
NazaraError("Parameter \"" + name + "\" is not present");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (it->second.type)
|
||||
{
|
||||
case ParameterType_Float:
|
||||
*value = it->second.value.floatVal;
|
||||
return true;
|
||||
|
||||
case ParameterType_Integer:
|
||||
*value = static_cast<float>(it->second.value.intVal);
|
||||
return true;
|
||||
|
||||
case ParameterType_String:
|
||||
{
|
||||
double converted;
|
||||
if (it->second.value.stringVal.ToDouble(&converted))
|
||||
{
|
||||
*value = static_cast<float>(converted);
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ParameterType_Boolean:
|
||||
case ParameterType_None:
|
||||
case ParameterType_Pointer:
|
||||
case ParameterType_Userdata:
|
||||
break;
|
||||
}
|
||||
|
||||
NazaraError("Parameter value is not representable as a float");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParameterList::GetIntegerParameter(const String& name, int* value) const
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it == m_parameters.end())
|
||||
{
|
||||
NazaraError("Parameter \"" + name + "\" is not present");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (it->second.type)
|
||||
{
|
||||
case ParameterType_Boolean:
|
||||
*value = (it->second.value.boolVal) ? 1 : 0;
|
||||
return true;
|
||||
|
||||
case ParameterType_Float:
|
||||
*value = static_cast<int>(it->second.value.floatVal);
|
||||
return true;
|
||||
|
||||
case ParameterType_Integer:
|
||||
*value = it->second.value.intVal;
|
||||
return false;
|
||||
|
||||
case ParameterType_String:
|
||||
{
|
||||
long long converted;
|
||||
if (it->second.value.stringVal.ToInteger(&converted))
|
||||
{
|
||||
if (converted <= std::numeric_limits<int>::max() && converted >= std::numeric_limits<int>::min())
|
||||
{
|
||||
*value = static_cast<int>(converted);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ParameterType_None:
|
||||
case ParameterType_Pointer:
|
||||
case ParameterType_Userdata:
|
||||
break;
|
||||
}
|
||||
|
||||
NazaraError("Parameter value is not representable as a integer");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParameterList::GetParameterType(const String& name, ParameterType* type) const
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it == m_parameters.end())
|
||||
return false;
|
||||
|
||||
*type = it->second.type;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParameterList::GetPointerParameter(const String& name, void** value) const
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it == m_parameters.end())
|
||||
{
|
||||
NazaraError("Parameter \"" + name + "\" is not present");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (it->second.type)
|
||||
{
|
||||
case ParameterType_Pointer:
|
||||
*value = it->second.value.ptrVal;
|
||||
return true;
|
||||
|
||||
case ParameterType_Userdata:
|
||||
*value = it->second.value.userdataVal->ptr;
|
||||
return true;
|
||||
|
||||
case ParameterType_Boolean:
|
||||
case ParameterType_Float:
|
||||
case ParameterType_Integer:
|
||||
case ParameterType_None:
|
||||
case ParameterType_String:
|
||||
break;
|
||||
}
|
||||
|
||||
NazaraError("Parameter value is not a pointer");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParameterList::GetStringParameter(const String& name, String* value) const
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it == m_parameters.end())
|
||||
{
|
||||
NazaraError("Parameter \"" + name + "\" is not present");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (it->second.type)
|
||||
{
|
||||
case ParameterType_Boolean:
|
||||
*value = String::Boolean(it->second.value.boolVal);
|
||||
return true;
|
||||
|
||||
case ParameterType_Float:
|
||||
*value = String::Number(it->second.value.floatVal);
|
||||
return true;
|
||||
|
||||
case ParameterType_Integer:
|
||||
*value = String::Number(it->second.value.intVal);
|
||||
return true;
|
||||
|
||||
case ParameterType_String:
|
||||
*value = it->second.value.stringVal;
|
||||
return true;
|
||||
|
||||
case ParameterType_Pointer:
|
||||
*value = String::Pointer(it->second.value.ptrVal);
|
||||
return true;
|
||||
|
||||
case ParameterType_Userdata:
|
||||
*value = String::Pointer(it->second.value.userdataVal->ptr);
|
||||
return true;
|
||||
|
||||
case ParameterType_None:
|
||||
*value = String();
|
||||
return true;
|
||||
}
|
||||
|
||||
NazaraInternalError("Parameter value is not valid");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ParameterList::GetUserdataParameter(const String& name, void** value) const
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it == m_parameters.end())
|
||||
{
|
||||
NazaraError("Parameter \"" + name + "\" is not present");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (it->second.type == ParameterType_Userdata)
|
||||
{
|
||||
*value = it->second.value.userdataVal->ptr;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraError("Parameter value is not a userdata");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ParameterList::HasParameter(const String& name) const
|
||||
{
|
||||
return m_parameters.find(name) != m_parameters.end();
|
||||
}
|
||||
|
||||
void ParameterList::RemoveParameter(const String& name)
|
||||
{
|
||||
auto it = m_parameters.find(name);
|
||||
if (it != m_parameters.end())
|
||||
{
|
||||
DestroyValue(it->second);
|
||||
m_parameters.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void ParameterList::SetParameter(const String& name)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = ParameterType_None;
|
||||
}
|
||||
|
||||
void ParameterList::SetParameter(const String& name, const String& value)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = ParameterType_String;
|
||||
|
||||
PlacementNew<String>(¶meter.value.stringVal, value);
|
||||
}
|
||||
|
||||
void ParameterList::SetParameter(const String& name, const char* value)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = ParameterType_String;
|
||||
|
||||
PlacementNew<String>(¶meter.value.stringVal, value);
|
||||
}
|
||||
|
||||
void ParameterList::SetParameter(const String& name, void* value)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = ParameterType_Pointer;
|
||||
parameter.value.ptrVal = value;
|
||||
}
|
||||
|
||||
void ParameterList::SetParameter(const String& name, void* value, Destructor destructor)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = ParameterType_Userdata;
|
||||
parameter.value.userdataVal = new Parameter::UserdataValue(destructor, value);
|
||||
}
|
||||
|
||||
void ParameterList::SetParameter(const String& name, bool value)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = ParameterType_Boolean;
|
||||
parameter.value.boolVal = value;
|
||||
}
|
||||
|
||||
void ParameterList::SetParameter(const String& name, float value)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = ParameterType_Float;
|
||||
parameter.value.floatVal = value;
|
||||
}
|
||||
|
||||
void ParameterList::SetParameter(const String& name, int value)
|
||||
{
|
||||
std::pair<ParameterMap::iterator, bool> pair = m_parameters.insert(std::make_pair(name, Parameter()));
|
||||
Parameter& parameter = pair.first->second;
|
||||
|
||||
if (!pair.second)
|
||||
DestroyValue(parameter);
|
||||
|
||||
parameter.type = ParameterType_Integer;
|
||||
parameter.value.intVal = value;
|
||||
}
|
||||
|
||||
ParameterList& ParameterList::operator=(const ParameterList& list)
|
||||
{
|
||||
Clear();
|
||||
|
||||
for (auto it = list.m_parameters.begin(); it != list.m_parameters.end(); ++it)
|
||||
{
|
||||
Parameter& parameter = m_parameters[it->first];
|
||||
|
||||
switch (it->second.type)
|
||||
{
|
||||
case ParameterType_Boolean:
|
||||
case ParameterType_Float:
|
||||
case ParameterType_Integer:
|
||||
case ParameterType_Pointer:
|
||||
std::memcpy(¶meter, &it->second, sizeof(Parameter));
|
||||
break;
|
||||
|
||||
case ParameterType_String:
|
||||
parameter.type = ParameterType_String;
|
||||
|
||||
PlacementNew<String>(¶meter.value.stringVal, it->second.value.stringVal);
|
||||
break;
|
||||
|
||||
case ParameterType_Userdata:
|
||||
parameter.type = ParameterType_Userdata;
|
||||
parameter.value.userdataVal = it->second.value.userdataVal;
|
||||
++(parameter.value.userdataVal->counter);
|
||||
break;
|
||||
|
||||
case ParameterType_None:
|
||||
parameter.type = ParameterType_None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ParameterList::DestroyValue(Parameter& parameter)
|
||||
{
|
||||
switch (parameter.type)
|
||||
{
|
||||
case ParameterType_String:
|
||||
parameter.value.stringVal.~String();
|
||||
break;
|
||||
|
||||
case ParameterType_Userdata:
|
||||
{
|
||||
Parameter::UserdataValue* userdata = parameter.value.userdataVal;
|
||||
if (--userdata->counter == 0)
|
||||
{
|
||||
userdata->destructor(userdata->ptr);
|
||||
delete userdata;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ParameterType_Boolean:
|
||||
case ParameterType_Float:
|
||||
case ParameterType_Integer:
|
||||
case ParameterType_None:
|
||||
case ParameterType_Pointer:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,176 +10,179 @@
|
||||
#include <memory>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace
|
||||
namespace Nz
|
||||
{
|
||||
using PluginLoad = int (*)();
|
||||
using PluginUnload = void (*)();
|
||||
|
||||
NzString s_pluginFiles[] =
|
||||
namespace
|
||||
{
|
||||
"NazaraAssimp", // nzPlugin_Assimp
|
||||
"NazaraFreetype" // nzPlugin_FreeType
|
||||
};
|
||||
}
|
||||
using PluginLoad = int (*)();
|
||||
using PluginUnload = void (*)();
|
||||
|
||||
void NzPluginManager::AddDirectory(const NzString& directoryPath)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize PluginManager");
|
||||
return;
|
||||
}
|
||||
|
||||
s_directories.insert(NzFile::AbsolutePath(directoryPath));
|
||||
}
|
||||
|
||||
bool NzPluginManager::Initialize()
|
||||
{
|
||||
if (s_initialized)
|
||||
return true;
|
||||
|
||||
s_initialized = true;
|
||||
|
||||
AddDirectory(".");
|
||||
AddDirectory("plugins");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzPluginManager::Mount(nzPlugin plugin)
|
||||
{
|
||||
return Mount(s_pluginFiles[plugin]);
|
||||
}
|
||||
|
||||
bool NzPluginManager::Mount(const NzString& pluginPath, bool appendExtension)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize PluginManager");
|
||||
return false;
|
||||
}
|
||||
|
||||
NzString path = pluginPath;
|
||||
if (appendExtension && !path.EndsWith(NAZARA_DYNLIB_EXTENSION))
|
||||
path += NAZARA_DYNLIB_EXTENSION;
|
||||
|
||||
bool exists = false;
|
||||
if (!NzFile::IsAbsolute(path))
|
||||
{
|
||||
for (const NzString& dir : s_directories)
|
||||
String s_pluginFiles[] =
|
||||
{
|
||||
NzString testPath;
|
||||
testPath.Reserve(dir.GetSize() + path.GetSize() + 10);
|
||||
"NazaraAssimp", // Plugin_Assimp
|
||||
"NazaraFreetype" // Plugin_FreeType
|
||||
};
|
||||
}
|
||||
|
||||
testPath = dir;
|
||||
testPath += NAZARA_DIRECTORY_SEPARATOR;
|
||||
testPath += path;
|
||||
void PluginManager::AddDirectory(const String& directoryPath)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize PluginManager");
|
||||
return;
|
||||
}
|
||||
|
||||
if (NzFile::Exists(testPath))
|
||||
s_directories.insert(File::AbsolutePath(directoryPath));
|
||||
}
|
||||
|
||||
bool PluginManager::Initialize()
|
||||
{
|
||||
if (s_initialized)
|
||||
return true;
|
||||
|
||||
s_initialized = true;
|
||||
|
||||
AddDirectory(".");
|
||||
AddDirectory("plugins");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PluginManager::Mount(Plugin plugin)
|
||||
{
|
||||
return Mount(s_pluginFiles[plugin]);
|
||||
}
|
||||
|
||||
bool PluginManager::Mount(const String& pluginPath, bool appendExtension)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize PluginManager");
|
||||
return false;
|
||||
}
|
||||
|
||||
String path = pluginPath;
|
||||
if (appendExtension && !path.EndsWith(NAZARA_DYNLIB_EXTENSION))
|
||||
path += NAZARA_DYNLIB_EXTENSION;
|
||||
|
||||
bool exists = false;
|
||||
if (!File::IsAbsolute(path))
|
||||
{
|
||||
for (const String& dir : s_directories)
|
||||
{
|
||||
path = testPath;
|
||||
exists = true;
|
||||
break;
|
||||
String testPath;
|
||||
testPath.Reserve(dir.GetSize() + path.GetSize() + 10);
|
||||
|
||||
testPath = dir;
|
||||
testPath += NAZARA_DIRECTORY_SEPARATOR;
|
||||
testPath += path;
|
||||
|
||||
if (File::Exists(testPath))
|
||||
{
|
||||
path = testPath;
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (NzFile::Exists(path))
|
||||
exists = true;
|
||||
else if (File::Exists(path))
|
||||
exists = true;
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
NazaraError("Failed to find plugin file");
|
||||
return false;
|
||||
if (!exists)
|
||||
{
|
||||
NazaraError("Failed to find plugin file");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<DynLib> library(new DynLib);
|
||||
if (!library->Load(path))
|
||||
{
|
||||
NazaraError("Failed to load plugin");
|
||||
return false;
|
||||
}
|
||||
|
||||
PluginLoad func = reinterpret_cast<PluginLoad>(library->GetSymbol("PluginLoad"));
|
||||
if (!func)
|
||||
{
|
||||
NazaraError("Failed to get symbol PluginLoad");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!func())
|
||||
{
|
||||
NazaraError("Plugin failed to load");
|
||||
return false;
|
||||
}
|
||||
|
||||
s_plugins[pluginPath] = library.release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<NzDynLib> library(new NzDynLib);
|
||||
if (!library->Load(path))
|
||||
void PluginManager::RemoveDirectory(const String& directoryPath)
|
||||
{
|
||||
NazaraError("Failed to load plugin");
|
||||
return false;
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize PluginManager");
|
||||
return;
|
||||
}
|
||||
|
||||
s_directories.erase(File::AbsolutePath(directoryPath));
|
||||
}
|
||||
|
||||
PluginLoad func = reinterpret_cast<PluginLoad>(library->GetSymbol("NzPluginLoad"));
|
||||
if (!func)
|
||||
void PluginManager::Unmount(Plugin plugin)
|
||||
{
|
||||
NazaraError("Failed to get symbol NzPluginLoad");
|
||||
return false;
|
||||
Unmount(s_pluginFiles[plugin]);
|
||||
}
|
||||
|
||||
if (!func())
|
||||
void PluginManager::Unmount(const String& pluginPath)
|
||||
{
|
||||
NazaraError("Plugin failed to load");
|
||||
return false;
|
||||
}
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize PluginManager");
|
||||
return;
|
||||
}
|
||||
|
||||
s_plugins[pluginPath] = library.release();
|
||||
auto it = s_plugins.find(pluginPath);
|
||||
if (it == s_plugins.end())
|
||||
{
|
||||
NazaraError("Plugin not loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzPluginManager::RemoveDirectory(const NzString& directoryPath)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize PluginManager");
|
||||
return;
|
||||
}
|
||||
|
||||
s_directories.erase(NzFile::AbsolutePath(directoryPath));
|
||||
}
|
||||
|
||||
void NzPluginManager::Unmount(nzPlugin plugin)
|
||||
{
|
||||
Unmount(s_pluginFiles[plugin]);
|
||||
}
|
||||
|
||||
void NzPluginManager::Unmount(const NzString& pluginPath)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize PluginManager");
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = s_plugins.find(pluginPath);
|
||||
if (it == s_plugins.end())
|
||||
{
|
||||
NazaraError("Plugin not loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
PluginUnload func = reinterpret_cast<PluginUnload>(it->second->GetSymbol("NzPluginUnload"));
|
||||
if (func)
|
||||
func();
|
||||
|
||||
it->second->Unload();
|
||||
delete it->second;
|
||||
|
||||
s_plugins.erase(it);
|
||||
}
|
||||
|
||||
void NzPluginManager::Uninitialize()
|
||||
{
|
||||
if (!s_initialized)
|
||||
return;
|
||||
|
||||
s_initialized = false;
|
||||
|
||||
s_directories.clear();
|
||||
|
||||
for (auto& pair : s_plugins)
|
||||
{
|
||||
PluginUnload func = reinterpret_cast<PluginUnload>(pair.second->GetSymbol("NzPluginUnload"));
|
||||
PluginUnload func = reinterpret_cast<PluginUnload>(it->second->GetSymbol("PluginUnload"));
|
||||
if (func)
|
||||
func();
|
||||
|
||||
pair.second->Unload();
|
||||
delete pair.second;
|
||||
it->second->Unload();
|
||||
delete it->second;
|
||||
|
||||
s_plugins.erase(it);
|
||||
}
|
||||
|
||||
s_plugins.clear();
|
||||
}
|
||||
void PluginManager::Uninitialize()
|
||||
{
|
||||
if (!s_initialized)
|
||||
return;
|
||||
|
||||
std::set<NzString> NzPluginManager::s_directories;
|
||||
std::unordered_map<NzString, NzDynLib*> NzPluginManager::s_plugins;
|
||||
bool NzPluginManager::s_initialized = false;
|
||||
s_initialized = false;
|
||||
|
||||
s_directories.clear();
|
||||
|
||||
for (auto& pair : s_plugins)
|
||||
{
|
||||
PluginUnload func = reinterpret_cast<PluginUnload>(pair.second->GetSymbol("PluginUnload"));
|
||||
if (func)
|
||||
func();
|
||||
|
||||
pair.second->Unload();
|
||||
delete pair.second;
|
||||
}
|
||||
|
||||
s_plugins.clear();
|
||||
}
|
||||
|
||||
std::set<String> PluginManager::s_directories;
|
||||
std::unordered_map<String, DynLib*> PluginManager::s_plugins;
|
||||
bool PluginManager::s_initialized = false;
|
||||
}
|
||||
|
||||
@@ -8,21 +8,24 @@
|
||||
#include <sys/time.h>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
bool NzClockImplInitializeHighPrecision()
|
||||
namespace Nz
|
||||
{
|
||||
return true; // No initialization needed
|
||||
}
|
||||
bool ClockImplInitializeHighPrecision()
|
||||
{
|
||||
return true; // No initialization needed
|
||||
}
|
||||
|
||||
nzUInt64 NzClockImplGetMicroseconds()
|
||||
{
|
||||
timeval clock;
|
||||
gettimeofday(&clock, nullptr);
|
||||
return static_cast<nzUInt64>(clock.tv_sec*1000000 + clock.tv_usec);
|
||||
}
|
||||
UInt64 ClockImplGetElapsedMicroseconds()
|
||||
{
|
||||
timeval clock;
|
||||
gettimeofday(&clock, nullptr);
|
||||
return static_cast<UInt64>(clock.tv_sec*1000000 + clock.tv_usec);
|
||||
}
|
||||
|
||||
nzUInt64 NzClockImplGetMilliseconds()
|
||||
{
|
||||
timeval clock;
|
||||
gettimeofday(&clock, nullptr);
|
||||
return static_cast<nzUInt64>(clock.tv_sec*1000 + (clock.tv_usec/1000));
|
||||
UInt64 ClockImplGetElapsedMilliseconds()
|
||||
{
|
||||
timeval clock;
|
||||
gettimeofday(&clock, nullptr);
|
||||
return static_cast<UInt64>(clock.tv_sec*1000 + (clock.tv_usec/1000));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
|
||||
bool NzClockImplInitializeHighPrecision();
|
||||
nzUInt64 NzClockImplGetMicroseconds();
|
||||
nzUInt64 NzClockImplGetMilliseconds();
|
||||
namespace Nz
|
||||
{
|
||||
bool ClockImplInitializeHighPrecision();
|
||||
UInt64 ClockImplGetElapsedMicroseconds();
|
||||
UInt64 ClockImplGetElapsedMilliseconds();
|
||||
}
|
||||
|
||||
#endif // NAZARA_CLOCKIMPL_POSIX_HPP
|
||||
|
||||
@@ -6,42 +6,45 @@
|
||||
#include <Nazara/Core/Posix/MutexImpl.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzConditionVariableImpl::NzConditionVariableImpl()
|
||||
namespace Nz
|
||||
{
|
||||
pthread_cond_init(&m_cv, nullptr);
|
||||
}
|
||||
|
||||
NzConditionVariableImpl::~NzConditionVariableImpl()
|
||||
{
|
||||
pthread_cond_destroy(&m_cv);
|
||||
}
|
||||
|
||||
void NzConditionVariableImpl::Signal()
|
||||
{
|
||||
pthread_cond_signal(&m_cv);
|
||||
}
|
||||
|
||||
void NzConditionVariableImpl::SignalAll()
|
||||
{
|
||||
pthread_cond_broadcast(&m_cv);
|
||||
}
|
||||
|
||||
void NzConditionVariableImpl::Wait(NzMutexImpl* mutex)
|
||||
{
|
||||
pthread_cond_wait(&m_cv, &mutex->m_handle);
|
||||
}
|
||||
|
||||
bool NzConditionVariableImpl::Wait(NzMutexImpl* mutex, nzUInt32 timeout)
|
||||
{
|
||||
// get the current time
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
// construct the time limit (current time + time to wait)
|
||||
timespec ti;
|
||||
ti.tv_nsec = (tv.tv_usec + (timeout % 1000)) * 1000000;
|
||||
ti.tv_sec = tv.tv_sec + (timeout / 1000) + (ti.tv_nsec / 1000000000);
|
||||
ti.tv_nsec %= 1000000000;
|
||||
|
||||
return pthread_cond_timedwait(&m_cv,&mutex->m_handle, &ti) != 0;
|
||||
ConditionVariableImpl::ConditionVariableImpl()
|
||||
{
|
||||
pthread_cond_init(&m_cv, nullptr);
|
||||
}
|
||||
|
||||
ConditionVariableImpl::~ConditionVariableImpl()
|
||||
{
|
||||
pthread_cond_destroy(&m_cv);
|
||||
}
|
||||
|
||||
void ConditionVariableImpl::Signal()
|
||||
{
|
||||
pthread_cond_signal(&m_cv);
|
||||
}
|
||||
|
||||
void ConditionVariableImpl::SignalAll()
|
||||
{
|
||||
pthread_cond_broadcast(&m_cv);
|
||||
}
|
||||
|
||||
void ConditionVariableImpl::Wait(MutexImpl* mutex)
|
||||
{
|
||||
pthread_cond_wait(&m_cv, &mutex->m_handle);
|
||||
}
|
||||
|
||||
bool ConditionVariableImpl::Wait(MutexImpl* mutex, UInt32 timeout)
|
||||
{
|
||||
// get the current time
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
// construct the time limit (current time + time to wait)
|
||||
timespec ti;
|
||||
ti.tv_nsec = (tv.tv_usec + (timeout % 1000)) * 1000000;
|
||||
ti.tv_sec = tv.tv_sec + (timeout / 1000) + (ti.tv_nsec / 1000000000);
|
||||
ti.tv_nsec %= 1000000000;
|
||||
|
||||
return pthread_cond_timedwait(&m_cv,&mutex->m_handle, &ti) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,22 +14,25 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
class NzMutexImpl;
|
||||
|
||||
class NzConditionVariableImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzConditionVariableImpl();
|
||||
~NzConditionVariableImpl();
|
||||
class MutexImpl;
|
||||
|
||||
void Signal();
|
||||
void SignalAll();
|
||||
class ConditionVariableImpl
|
||||
{
|
||||
public:
|
||||
ConditionVariableImpl();
|
||||
~ConditionVariableImpl();
|
||||
|
||||
void Wait(NzMutexImpl* mutex);
|
||||
bool Wait(NzMutexImpl* mutex, nzUInt32 timeout);
|
||||
void Signal();
|
||||
void SignalAll();
|
||||
|
||||
private:
|
||||
pthread_cond_t m_cv;
|
||||
};
|
||||
void Wait(MutexImpl* mutex);
|
||||
bool Wait(MutexImpl* mutex, UInt32 timeout);
|
||||
|
||||
private:
|
||||
pthread_cond_t m_cv;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_CONDITIONVARIABLEIMPL_HPP
|
||||
|
||||
@@ -9,95 +9,98 @@
|
||||
#include <errno.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
NzDirectoryImpl::NzDirectoryImpl(const NzDirectory* parent)
|
||||
namespace Nz
|
||||
{
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
DirectoryImpl::DirectoryImpl(const Directory* parent)
|
||||
{
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
void NzDirectoryImpl::Close()
|
||||
{
|
||||
closedir(m_handle);
|
||||
}
|
||||
void DirectoryImpl::Close()
|
||||
{
|
||||
closedir(m_handle);
|
||||
}
|
||||
|
||||
NzString NzDirectoryImpl::GetResultName() const
|
||||
{
|
||||
return m_result->d_name;
|
||||
}
|
||||
String DirectoryImpl::GetResultName() const
|
||||
{
|
||||
return m_result->d_name;
|
||||
}
|
||||
|
||||
nzUInt64 NzDirectoryImpl::GetResultSize() const
|
||||
{
|
||||
struct stat64 resulststat;
|
||||
stat64(m_result->d_name, &resulststat);
|
||||
UInt64 DirectoryImpl::GetResultSize() const
|
||||
{
|
||||
struct stat64 resulststat;
|
||||
stat64(m_result->d_name, &resulststat);
|
||||
|
||||
return static_cast<nzUInt64>(resulststat.st_size);
|
||||
}
|
||||
return static_cast<UInt64>(resulststat.st_size);
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::IsResultDirectory() const
|
||||
{
|
||||
struct stat64 filestats;
|
||||
if (stat64(m_result->d_name, &filestats) == -1) // error
|
||||
return false;
|
||||
bool DirectoryImpl::IsResultDirectory() const
|
||||
{
|
||||
struct stat64 filestats;
|
||||
if (stat64(m_result->d_name, &filestats) == -1) // error
|
||||
return false;
|
||||
|
||||
return S_ISDIR(filestats.st_mode);
|
||||
}
|
||||
return S_ISDIR(filestats.st_mode);
|
||||
}
|
||||
|
||||
bool DirectoryImpl::NextResult()
|
||||
{
|
||||
if ((m_result = readdir64(m_handle)))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
NazaraError("Unable to get next result: " + Error::GetLastSystemError());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DirectoryImpl::Open(const String& dirPath)
|
||||
{
|
||||
m_handle = opendir(dirPath.GetConstBuffer());
|
||||
if (!m_handle)
|
||||
{
|
||||
NazaraError("Unable to open directory: " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::NextResult()
|
||||
{
|
||||
if ((m_result = readdir64(m_handle)))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
NazaraError("Unable to get next result: " + NzError::GetLastSystemError());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::Open(const NzString& dirPath)
|
||||
{
|
||||
m_handle = opendir(dirPath.GetConstBuffer());
|
||||
if (!m_handle)
|
||||
{
|
||||
NazaraError("Unable to open directory: " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::Create(const NzString& dirPath)
|
||||
{
|
||||
mode_t permissions; // TODO: check permissions
|
||||
|
||||
return mkdir(dirPath.GetConstBuffer(), permissions) != -1;;
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::Exists(const NzString& dirPath)
|
||||
{
|
||||
struct stat64 filestats;
|
||||
if (stat64(dirPath.GetConstBuffer(), &filestats) == -1) // error
|
||||
return false;
|
||||
|
||||
return S_ISDIR(filestats.st_mode) || S_ISREG(filestats.st_mode);
|
||||
}
|
||||
|
||||
NzString NzDirectoryImpl::GetCurrent()
|
||||
{
|
||||
NzString currentPath;
|
||||
|
||||
char path[MAXPATHLEN];
|
||||
if (getcwd(path, MAXPATHLEN))
|
||||
currentPath = path;
|
||||
else
|
||||
NazaraError("Unable to get current directory: " + NzError::GetLastSystemError()); // Bug: initialisation -> if no path for log !
|
||||
|
||||
return currentPath;
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::Remove(const NzString& dirPath)
|
||||
{
|
||||
bool success = rmdir(dirPath.GetConstBuffer()) != -1;
|
||||
|
||||
return success;
|
||||
bool DirectoryImpl::Create(const String& dirPath)
|
||||
{
|
||||
mode_t permissions; // TODO: check permissions
|
||||
|
||||
return mkdir(dirPath.GetConstBuffer(), permissions) != -1;;
|
||||
}
|
||||
|
||||
bool DirectoryImpl::Exists(const String& dirPath)
|
||||
{
|
||||
struct stat64 filestats;
|
||||
if (stat64(dirPath.GetConstBuffer(), &filestats) == -1) // error
|
||||
return false;
|
||||
|
||||
return S_ISDIR(filestats.st_mode) || S_ISREG(filestats.st_mode);
|
||||
}
|
||||
|
||||
String DirectoryImpl::GetCurrent()
|
||||
{
|
||||
String currentPath;
|
||||
|
||||
char path[MAXPATHLEN];
|
||||
if (getcwd(path, MAXPATHLEN))
|
||||
currentPath = path;
|
||||
else
|
||||
NazaraError("Unable to get current directory: " + Error::GetLastSystemError()); // Bug: initialisation -> if no path for log !
|
||||
|
||||
return currentPath;
|
||||
}
|
||||
|
||||
bool DirectoryImpl::Remove(const String& dirPath)
|
||||
{
|
||||
bool success = rmdir(dirPath.GetConstBuffer()) != -1;
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,40 +8,47 @@
|
||||
#define NAZARA_DIRECTORYIMPL_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Core/NonCopyable.hpp>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
class NzDirectory;
|
||||
class NzString;
|
||||
|
||||
class NzDirectoryImpl : NzNonCopyable
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzDirectoryImpl(const NzDirectory* parent);
|
||||
~NzDirectoryImpl() = default;
|
||||
class Directory;
|
||||
class String;
|
||||
|
||||
void Close();
|
||||
class DirectoryImpl
|
||||
{
|
||||
public:
|
||||
DirectoryImpl(const Directory* parent);
|
||||
DirectoryImpl(const DirectoryImpl&) = delete;
|
||||
DirectoryImpl(DirectoryImpl&&) = delete; ///TODO
|
||||
~DirectoryImpl() = default;
|
||||
|
||||
NzString GetResultName() const;
|
||||
nzUInt64 GetResultSize() const;
|
||||
void Close();
|
||||
|
||||
bool IsResultDirectory() const;
|
||||
String GetResultName() const;
|
||||
UInt64 GetResultSize() const;
|
||||
|
||||
bool NextResult();
|
||||
bool IsResultDirectory() const;
|
||||
|
||||
bool Open(const NzString& dirPath);
|
||||
bool NextResult();
|
||||
|
||||
static bool Create(const NzString& dirPath);
|
||||
static bool Exists(const NzString& dirPath);
|
||||
static NzString GetCurrent();
|
||||
static bool Remove(const NzString& dirPath);
|
||||
bool Open(const String& dirPath);
|
||||
|
||||
private:
|
||||
DIR* m_handle;
|
||||
dirent64* m_result;
|
||||
};
|
||||
DirectoryImpl& operator=(const DirectoryImpl&) = delete;
|
||||
DirectoryImpl& operator=(DirectoryImpl&&) = delete; ///TODO
|
||||
|
||||
static bool Create(const String& dirPath);
|
||||
static bool Exists(const String& dirPath);
|
||||
static String GetCurrent();
|
||||
static bool Remove(const String& dirPath);
|
||||
|
||||
private:
|
||||
DIR* m_handle;
|
||||
dirent64* m_result;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_DIRECTORYIMPL_HPP
|
||||
|
||||
@@ -8,55 +8,58 @@
|
||||
#include <Nazara/Core/String.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzDynLibImpl::NzDynLibImpl(NzDynLib* parent)
|
||||
namespace Nz
|
||||
{
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
NzDynLibFunc NzDynLibImpl::GetSymbol(const NzString& symbol, NzString* errorMessage) const
|
||||
{
|
||||
/*
|
||||
Il n'est pas standard de cast un pointeur d'objet vers un pointeur de fonction.
|
||||
Nous devons donc utiliser des techniques diaboliques venant du malin lui-même.. :D
|
||||
Au moins ce n'est pas aussi terrible qu'un const_cast
|
||||
-Lynix
|
||||
*/
|
||||
union
|
||||
DynLibImpl::DynLibImpl(DynLib* parent)
|
||||
{
|
||||
NzDynLibFunc func;
|
||||
void* pointer;
|
||||
} converter;
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
dlerror(); // Clear error flag
|
||||
|
||||
converter.pointer = dlsym(m_handle, symbol.GetConstBuffer());
|
||||
if (!converter.pointer)
|
||||
*errorMessage = dlerror();
|
||||
|
||||
return converter.func;
|
||||
}
|
||||
|
||||
bool NzDynLibImpl::Load(const NzString& libraryPath, NzString* errorMessage)
|
||||
{
|
||||
NzString path = libraryPath;
|
||||
|
||||
unsigned int pos = path.FindLast(".so");
|
||||
if (pos == NzString::npos || (path.GetLength() > pos+3 && path[pos+3] != '.'))
|
||||
path += ".so";
|
||||
|
||||
dlerror(); // Clear error flag
|
||||
m_handle = dlopen(path.GetConstBuffer(), RTLD_LAZY | RTLD_GLOBAL);
|
||||
|
||||
if (m_handle)
|
||||
return true;
|
||||
else
|
||||
DynLibFunc DynLibImpl::GetSymbol(const String& symbol, String* errorMessage) const
|
||||
{
|
||||
*errorMessage = dlerror();
|
||||
return false;
|
||||
/*
|
||||
Il n'est pas standard de cast un pointeur d'objet vers un pointeur de fonction.
|
||||
Nous devons donc utiliser des techniques diaboliques venant du malin lui-même.. :D
|
||||
Au moins ce n'est pas aussi terrible qu'un const_cast
|
||||
-Lynix
|
||||
*/
|
||||
union
|
||||
{
|
||||
DynLibFunc func;
|
||||
void* pointer;
|
||||
} converter;
|
||||
|
||||
dlerror(); // Clear error flag
|
||||
|
||||
converter.pointer = dlsym(m_handle, symbol.GetConstBuffer());
|
||||
if (!converter.pointer)
|
||||
*errorMessage = dlerror();
|
||||
|
||||
return converter.func;
|
||||
}
|
||||
|
||||
bool DynLibImpl::Load(const String& libraryPath, String* errorMessage)
|
||||
{
|
||||
String path = libraryPath;
|
||||
|
||||
unsigned int pos = path.FindLast(".so");
|
||||
if (pos == String::npos || (path.GetLength() > pos+3 && path[pos+3] != '.'))
|
||||
path += ".so";
|
||||
|
||||
dlerror(); // Clear error flag
|
||||
m_handle = dlopen(path.GetConstBuffer(), RTLD_LAZY | RTLD_GLOBAL);
|
||||
|
||||
if (m_handle)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
*errorMessage = dlerror();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DynLibImpl::Unload()
|
||||
{
|
||||
dlclose(m_handle);
|
||||
}
|
||||
}
|
||||
|
||||
void NzDynLibImpl::Unload()
|
||||
{
|
||||
dlclose(m_handle);
|
||||
}
|
||||
|
||||
@@ -8,23 +8,25 @@
|
||||
#define NAZARA_DYNLIBIMPL_HPP
|
||||
|
||||
#include <Nazara/Core/DynLib.hpp>
|
||||
#include <Nazara/Core/NonCopyable.hpp>
|
||||
#include <dlfcn.h>
|
||||
|
||||
class NzString;
|
||||
|
||||
class NzDynLibImpl : NzNonCopyable
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzDynLibImpl(NzDynLib* m_parent);
|
||||
~NzDynLibImpl() = default;
|
||||
class String;
|
||||
|
||||
NzDynLibFunc GetSymbol(const NzString& symbol, NzString* errorMessage) const;
|
||||
bool Load(const NzString& libraryPath, NzString* errorMessage);
|
||||
void Unload();
|
||||
class DynLibImpl
|
||||
{
|
||||
public:
|
||||
DynLibImpl(DynLib* m_parent);
|
||||
~DynLibImpl() = default;
|
||||
|
||||
private:
|
||||
void* m_handle;
|
||||
};
|
||||
DynLibFunc GetSymbol(const String& symbol, String* errorMessage) const;
|
||||
bool Load(const String& libraryPath, String* errorMessage);
|
||||
void Unload();
|
||||
|
||||
private:
|
||||
void* m_handle;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_DYNLIBIMPL_HPP
|
||||
|
||||
@@ -7,236 +7,230 @@
|
||||
#include <cstdio>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzFileImpl::NzFileImpl(const NzFile* parent) :
|
||||
m_endOfFile(false),
|
||||
m_endOfFileUpdated(true)
|
||||
namespace Nz
|
||||
{
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
void NzFileImpl::Close()
|
||||
{
|
||||
close(m_fileDescriptor);
|
||||
}
|
||||
|
||||
bool NzFileImpl::EndOfFile() const
|
||||
{
|
||||
if (!m_endOfFileUpdated)
|
||||
FileImpl::FileImpl(const File* parent) :
|
||||
m_endOfFile(false),
|
||||
m_endOfFileUpdated(true)
|
||||
{
|
||||
struct stat64 fileSize;
|
||||
if (fstat64(m_fileDescriptor, &fileSize) == -1)
|
||||
fileSize.st_size = 0;
|
||||
|
||||
m_endOfFile = (GetCursorPos() >= static_cast<nzUInt64>(fileSize.st_size));
|
||||
m_endOfFileUpdated = true;
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
return m_endOfFile;
|
||||
}
|
||||
|
||||
void NzFileImpl::Flush()
|
||||
{
|
||||
if (fsync(m_fileDescriptor) == -1)
|
||||
NazaraError("Unable to flush file: " + NzError::GetLastSystemError());
|
||||
}
|
||||
|
||||
nzUInt64 NzFileImpl::GetCursorPos() const
|
||||
{
|
||||
off64_t position = lseek64(m_fileDescriptor, 0, SEEK_CUR);
|
||||
return static_cast<nzUInt64>(position);
|
||||
}
|
||||
|
||||
bool NzFileImpl::Open(const NzString& filePath, unsigned int mode)
|
||||
{
|
||||
int flags;
|
||||
mode_t permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
|
||||
if (mode & nzOpenMode_ReadOnly)
|
||||
flags = O_RDONLY;
|
||||
else if (mode & nzOpenMode_ReadWrite)
|
||||
void FileImpl::Close()
|
||||
{
|
||||
flags = O_CREAT | O_RDWR;
|
||||
|
||||
if (mode & nzOpenMode_Append)
|
||||
flags |= O_APPEND;
|
||||
|
||||
if (mode & nzOpenMode_Truncate)
|
||||
flags |= O_TRUNC;
|
||||
}
|
||||
else if (mode & nzOpenMode_WriteOnly)
|
||||
{
|
||||
flags = O_CREAT | O_WRONLY;
|
||||
|
||||
if (mode & nzOpenMode_Append)
|
||||
flags |= O_APPEND;
|
||||
|
||||
if (mode & nzOpenMode_Truncate)
|
||||
flags |= O_TRUNC;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
///TODO: lock
|
||||
// if ((mode & nzOpenMode_Lock) == 0)
|
||||
// shareMode |= FILE_SHARE_WRITE;
|
||||
|
||||
m_fileDescriptor = open64(filePath.GetConstBuffer(), flags, permissions);
|
||||
return m_fileDescriptor != -1;
|
||||
}
|
||||
|
||||
std::size_t NzFileImpl::Read(void* buffer, std::size_t size)
|
||||
{
|
||||
ssize_t bytes;
|
||||
if ((bytes = read(m_fileDescriptor, buffer, size)) != -1)
|
||||
{
|
||||
m_endOfFile = (static_cast<std::size_t>(bytes) != size);
|
||||
m_endOfFileUpdated = true;
|
||||
|
||||
return static_cast<std::size_t>(bytes);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool NzFileImpl::SetCursorPos(nzCursorPosition pos, nzInt64 offset)
|
||||
{
|
||||
int moveMethod;
|
||||
switch (pos)
|
||||
{
|
||||
case nzCursorPosition_AtBegin:
|
||||
moveMethod = SEEK_SET;
|
||||
break;
|
||||
|
||||
case nzCursorPosition_AtCurrent:
|
||||
moveMethod = SEEK_CUR;
|
||||
break;
|
||||
|
||||
case nzCursorPosition_AtEnd:
|
||||
moveMethod = SEEK_END;
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Cursor position not handled (0x" + NzString::Number(pos, 16) + ')');
|
||||
return false;
|
||||
if (m_fileDescriptor != -1)
|
||||
close(m_fileDescriptor);
|
||||
}
|
||||
|
||||
m_endOfFileUpdated = false;
|
||||
|
||||
return lseek64(m_fileDescriptor, offset, moveMethod) != -1;
|
||||
}
|
||||
|
||||
std::size_t NzFileImpl::Write(const void* buffer, std::size_t size)
|
||||
{
|
||||
lockf64(m_fileDescriptor, F_LOCK, size);
|
||||
ssize_t written = write(m_fileDescriptor, buffer, size);
|
||||
lockf64(m_fileDescriptor, F_ULOCK, size);
|
||||
|
||||
m_endOfFileUpdated = false;
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
bool NzFileImpl::Copy(const NzString& sourcePath, const NzString& targetPath)
|
||||
{
|
||||
int fd1 = open64(sourcePath.GetConstBuffer(), O_RDONLY);
|
||||
if (fd1 == -1)
|
||||
bool FileImpl::EndOfFile() const
|
||||
{
|
||||
NazaraError("Fail to open input file (" + sourcePath + "): " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
|
||||
mode_t permissions; // TODO : get permission from first file
|
||||
int fd2 = open64(targetPath.GetConstBuffer(), O_WRONLY | O_TRUNC, permissions);
|
||||
if (fd2 == -1)
|
||||
{
|
||||
NazaraError("Fail to open output file (" + targetPath + "): " + NzError::GetLastSystemError()); // TODO: more info ?
|
||||
close(fd1);
|
||||
return false;
|
||||
}
|
||||
|
||||
char buffer[512];
|
||||
ssize_t bytes;
|
||||
do
|
||||
{
|
||||
bytes = read(fd1,buffer,512);
|
||||
if (bytes == -1)
|
||||
if (!m_endOfFileUpdated)
|
||||
{
|
||||
close(fd1);
|
||||
close(fd2);
|
||||
NazaraError("An error occured from copy : " + NzError::GetLastSystemError());
|
||||
struct stat64 fileSize;
|
||||
if (fstat64(m_fileDescriptor, &fileSize) == -1)
|
||||
fileSize.st_size = 0;
|
||||
|
||||
m_endOfFile = (GetCursorPos() >= static_cast<UInt64>(fileSize.st_size));
|
||||
m_endOfFileUpdated = true;
|
||||
}
|
||||
|
||||
return m_endOfFile;
|
||||
}
|
||||
|
||||
void FileImpl::Flush()
|
||||
{
|
||||
if (fsync(m_fileDescriptor) == -1)
|
||||
NazaraError("Unable to flush file: " + Error::GetLastSystemError());
|
||||
}
|
||||
|
||||
UInt64 FileImpl::GetCursorPos() const
|
||||
{
|
||||
off64_t position = lseek64(m_fileDescriptor, 0, SEEK_CUR);
|
||||
return static_cast<UInt64>(position);
|
||||
}
|
||||
|
||||
bool FileImpl::Open(const String& filePath, UInt32 mode)
|
||||
{
|
||||
int flags;
|
||||
mode_t permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
||||
|
||||
if (mode & OpenMode_ReadWrite)
|
||||
flags = O_CREAT | O_RDWR;
|
||||
else if (mode & OpenMode_ReadOnly)
|
||||
flags = O_RDONLY;
|
||||
else if (mode & OpenMode_WriteOnly)
|
||||
flags = O_CREAT | O_WRONLY;
|
||||
else
|
||||
return false;
|
||||
|
||||
if (mode & OpenMode_Append)
|
||||
flags |= O_APPEND;
|
||||
|
||||
if (mode & OpenMode_Truncate)
|
||||
flags |= O_TRUNC;
|
||||
|
||||
///TODO: lock
|
||||
// if ((mode & OpenMode_Lock) == 0)
|
||||
// shareMode |= FILE_SHARE_WRITE;
|
||||
|
||||
m_fileDescriptor = open64(filePath.GetConstBuffer(), flags, permissions);
|
||||
return m_fileDescriptor != -1;
|
||||
}
|
||||
|
||||
std::size_t FileImpl::Read(void* buffer, std::size_t size)
|
||||
{
|
||||
ssize_t bytes;
|
||||
if ((bytes = read(m_fileDescriptor, buffer, size)) != -1)
|
||||
{
|
||||
m_endOfFile = (static_cast<std::size_t>(bytes) != size);
|
||||
m_endOfFileUpdated = true;
|
||||
|
||||
return static_cast<std::size_t>(bytes);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool FileImpl::SetCursorPos(CursorPosition pos, Int64 offset)
|
||||
{
|
||||
int moveMethod;
|
||||
switch (pos)
|
||||
{
|
||||
case CursorPosition_AtBegin:
|
||||
moveMethod = SEEK_SET;
|
||||
break;
|
||||
|
||||
case CursorPosition_AtCurrent:
|
||||
moveMethod = SEEK_CUR;
|
||||
break;
|
||||
|
||||
case CursorPosition_AtEnd:
|
||||
moveMethod = SEEK_END;
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Cursor position not handled (0x" + String::Number(pos, 16) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
m_endOfFileUpdated = false;
|
||||
|
||||
return lseek64(m_fileDescriptor, offset, moveMethod) != -1;
|
||||
}
|
||||
|
||||
std::size_t FileImpl::Write(const void* buffer, std::size_t size)
|
||||
{
|
||||
lockf64(m_fileDescriptor, F_LOCK, size);
|
||||
ssize_t written = write(m_fileDescriptor, buffer, size);
|
||||
lockf64(m_fileDescriptor, F_ULOCK, size);
|
||||
|
||||
m_endOfFileUpdated = false;
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
bool FileImpl::Copy(const String& sourcePath, const String& targetPath)
|
||||
{
|
||||
int fd1 = open64(sourcePath.GetConstBuffer(), O_RDONLY);
|
||||
if (fd1 == -1)
|
||||
{
|
||||
NazaraError("Fail to open input file (" + sourcePath + "): " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
write(fd2,buffer,bytes);
|
||||
}
|
||||
while (bytes == 512);
|
||||
|
||||
close(fd1);
|
||||
close(fd2);
|
||||
return true;
|
||||
}
|
||||
mode_t permissions; // TODO : get permission from first file
|
||||
int fd2 = open64(targetPath.GetConstBuffer(), O_WRONLY | O_TRUNC, permissions);
|
||||
if (fd2 == -1)
|
||||
{
|
||||
NazaraError("Fail to open output file (" + targetPath + "): " + Error::GetLastSystemError()); // TODO: more info ?
|
||||
close(fd1);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NzFileImpl::Delete(const NzString& filePath)
|
||||
{
|
||||
bool success = unlink(filePath.GetConstBuffer()) != -1;
|
||||
char buffer[512];
|
||||
ssize_t bytes;
|
||||
do
|
||||
{
|
||||
bytes = read(fd1,buffer,512);
|
||||
if (bytes == -1)
|
||||
{
|
||||
close(fd1);
|
||||
close(fd2);
|
||||
NazaraError("An error occured from copy : " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
write(fd2,buffer,bytes);
|
||||
}
|
||||
while (bytes == 512);
|
||||
|
||||
if (success)
|
||||
close(fd1);
|
||||
close(fd2);
|
||||
return true;
|
||||
else
|
||||
}
|
||||
|
||||
bool FileImpl::Delete(const String& filePath)
|
||||
{
|
||||
NazaraError("Failed to delete file (" + filePath + "): " + NzError::GetLastSystemError());
|
||||
bool success = unlink(filePath.GetConstBuffer()) != -1;
|
||||
|
||||
if (success)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
NazaraError("Failed to delete file (" + filePath + "): " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool FileImpl::Exists(const String& filePath)
|
||||
{
|
||||
const char* path = filePath.GetConstBuffer();
|
||||
if (access(path, F_OK) != -1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool NzFileImpl::Exists(const NzString& filePath)
|
||||
{
|
||||
const char* path = filePath.GetConstBuffer();
|
||||
if (access(path, F_OK) != -1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
time_t NzFileImpl::GetCreationTime(const NzString& filePath)
|
||||
{
|
||||
NazaraWarning("Posix has no creation time information");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
time_t NzFileImpl::GetLastAccessTime(const NzString& filePath)
|
||||
{
|
||||
struct stat64 stats;
|
||||
stat64(filePath.GetConstBuffer(), &stats);
|
||||
|
||||
return stats.st_atime;
|
||||
}
|
||||
|
||||
time_t NzFileImpl::GetLastWriteTime(const NzString& filePath)
|
||||
{
|
||||
struct stat64 stats;
|
||||
stat64(filePath.GetConstBuffer(), &stats);
|
||||
|
||||
return stats.st_mtime;
|
||||
}
|
||||
|
||||
nzUInt64 NzFileImpl::GetSize(const NzString& filePath)
|
||||
{
|
||||
struct stat64 stats;
|
||||
stat64(filePath.GetConstBuffer(), &stats);
|
||||
|
||||
return static_cast<nzUInt64>(stats.st_size);
|
||||
}
|
||||
|
||||
bool NzFileImpl::Rename(const NzString& sourcePath, const NzString& targetPath)
|
||||
{
|
||||
bool success = std::rename(sourcePath.GetConstBuffer(), targetPath.GetConstBuffer()) != -1;
|
||||
|
||||
if (success)
|
||||
return true;
|
||||
else
|
||||
time_t FileImpl::GetCreationTime(const String& filePath)
|
||||
{
|
||||
NazaraError("Unable to rename file: " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
NazaraWarning("Posix has no creation time information");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
time_t FileImpl::GetLastAccessTime(const String& filePath)
|
||||
{
|
||||
struct stat64 stats;
|
||||
stat64(filePath.GetConstBuffer(), &stats);
|
||||
|
||||
return stats.st_atime;
|
||||
}
|
||||
|
||||
time_t FileImpl::GetLastWriteTime(const String& filePath)
|
||||
{
|
||||
struct stat64 stats;
|
||||
stat64(filePath.GetConstBuffer(), &stats);
|
||||
|
||||
return stats.st_mtime;
|
||||
}
|
||||
|
||||
UInt64 FileImpl::GetSize(const String& filePath)
|
||||
{
|
||||
struct stat64 stats;
|
||||
stat64(filePath.GetConstBuffer(), &stats);
|
||||
|
||||
return static_cast<UInt64>(stats.st_size);
|
||||
}
|
||||
|
||||
bool FileImpl::Rename(const String& sourcePath, const String& targetPath)
|
||||
{
|
||||
bool success = std::rename(sourcePath.GetConstBuffer(), targetPath.GetConstBuffer()) != -1;
|
||||
|
||||
if (success)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
NazaraError("Unable to rename file: " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,44 +13,51 @@
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Core/NonCopyable.hpp>
|
||||
#include <ctime>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
class NzFile;
|
||||
class NzString;
|
||||
|
||||
class NzFileImpl : NzNonCopyable
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzFileImpl(const NzFile* parent);
|
||||
~NzFileImpl() = default;
|
||||
class File;
|
||||
class String;
|
||||
|
||||
void Close();
|
||||
bool EndOfFile() const;
|
||||
void Flush();
|
||||
nzUInt64 GetCursorPos() const;
|
||||
bool Open(const NzString& filePath, unsigned int mode);
|
||||
std::size_t Read(void* buffer, std::size_t size);
|
||||
bool SetCursorPos(nzCursorPosition pos, nzInt64 offset);
|
||||
std::size_t Write(const void* buffer, std::size_t size);
|
||||
class FileImpl
|
||||
{
|
||||
public:
|
||||
FileImpl(const File* parent);
|
||||
FileImpl(const FileImpl&) = delete;
|
||||
FileImpl(FileImpl&&) = delete; ///TODO
|
||||
~FileImpl() = default;
|
||||
|
||||
static bool Copy(const NzString& sourcePath, const NzString& targetPath);
|
||||
static bool Delete(const NzString& filePath);
|
||||
static bool Exists(const NzString& filePath);
|
||||
static time_t GetCreationTime(const NzString& filePath);
|
||||
static time_t GetLastAccessTime(const NzString& filePath);
|
||||
static time_t GetLastWriteTime(const NzString& filePath);
|
||||
static nzUInt64 GetSize(const NzString& filePath);
|
||||
static bool Rename(const NzString& sourcePath, const NzString& targetPath);
|
||||
void Close();
|
||||
bool EndOfFile() const;
|
||||
void Flush();
|
||||
UInt64 GetCursorPos() const;
|
||||
bool Open(const String& filePath, UInt32 mode);
|
||||
std::size_t Read(void* buffer, std::size_t size);
|
||||
bool SetCursorPos(CursorPosition pos, Int64 offset);
|
||||
std::size_t Write(const void* buffer, std::size_t size);
|
||||
|
||||
private:
|
||||
int m_fileDescriptor;
|
||||
mutable bool m_endOfFile;
|
||||
mutable bool m_endOfFileUpdated;
|
||||
};
|
||||
FileImpl& operator=(const FileImpl&) = delete;
|
||||
FileImpl& operator=(FileImpl&&) = delete; ///TODO
|
||||
|
||||
static bool Copy(const String& sourcePath, const String& targetPath);
|
||||
static bool Delete(const String& filePath);
|
||||
static bool Exists(const String& filePath);
|
||||
static time_t GetCreationTime(const String& filePath);
|
||||
static time_t GetLastAccessTime(const String& filePath);
|
||||
static time_t GetLastWriteTime(const String& filePath);
|
||||
static UInt64 GetSize(const String& filePath);
|
||||
static bool Rename(const String& sourcePath, const String& targetPath);
|
||||
|
||||
private:
|
||||
int m_fileDescriptor;
|
||||
mutable bool m_endOfFile;
|
||||
mutable bool m_endOfFileUpdated;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_FILEIMPL_HPP
|
||||
|
||||
@@ -6,58 +6,61 @@
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
void NzHardwareInfoImpl::Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 registers[4])
|
||||
namespace Nz
|
||||
{
|
||||
#if defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
|
||||
// Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c
|
||||
asm volatile ("cpuid" // Besoin d'être volatile ?
|
||||
: "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) // output
|
||||
: "a" (functionId), "c" (subFunctionId)); // input
|
||||
#else
|
||||
NazaraInternalError("Cpuid has been called although it is not supported");
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int NzHardwareInfoImpl::GetProcessorCount()
|
||||
{
|
||||
// Plus simple (et plus portable) que de passer par le CPUID
|
||||
return sysconf(_SC_NPROCESSORS_CONF);
|
||||
}
|
||||
|
||||
nzUInt64 NzHardwareInfoImpl::GetTotalMemory()
|
||||
{
|
||||
nzUInt64 pages = sysconf(_SC_PHYS_PAGES);
|
||||
nzUInt64 page_size = sysconf(_SC_PAGE_SIZE);
|
||||
|
||||
return pages * page_size;
|
||||
}
|
||||
|
||||
bool NzHardwareInfoImpl::IsCpuidSupported()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_x64
|
||||
return true; // Toujours supporté sur un processeur 64 bits
|
||||
#else
|
||||
void HardwareInfoImpl::Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 registers[4])
|
||||
{
|
||||
#if defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
|
||||
int supported;
|
||||
asm volatile (" pushfl\n"
|
||||
" pop %%eax\n"
|
||||
" mov %%eax, %%ecx\n"
|
||||
" xor $0x200000, %%eax\n"
|
||||
" push %%eax\n"
|
||||
" popfl\n"
|
||||
" pushfl\n"
|
||||
" pop %%eax\n"
|
||||
" xor %%ecx, %%eax\n"
|
||||
" mov %%eax, %0\n"
|
||||
" push %%ecx\n"
|
||||
" popfl"
|
||||
: "=m" (supported) // output
|
||||
: // input
|
||||
: "eax", "ecx", "memory"); // clobbered register
|
||||
|
||||
return supported != 0;
|
||||
// Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c
|
||||
asm volatile ("cpuid" // Besoin d'être volatile ?
|
||||
: "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) // output
|
||||
: "a" (functionId), "c" (subFunctionId)); // input
|
||||
#else
|
||||
return false;
|
||||
NazaraInternalError("Cpuid has been called although it is not supported");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int HardwareInfoImpl::GetProcessorCount()
|
||||
{
|
||||
// Plus simple (et plus portable) que de passer par le CPUID
|
||||
return sysconf(_SC_NPROCESSORS_CONF);
|
||||
}
|
||||
|
||||
UInt64 HardwareInfoImpl::GetTotalMemory()
|
||||
{
|
||||
UInt64 pages = sysconf(_SC_PHYS_PAGES);
|
||||
UInt64 page_size = sysconf(_SC_PAGE_SIZE);
|
||||
|
||||
return pages * page_size;
|
||||
}
|
||||
|
||||
bool HardwareInfoImpl::IsCpuidSupported()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_x64
|
||||
return true; // Toujours supporté sur un processeur 64 bits
|
||||
#else
|
||||
#if defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
|
||||
int supported;
|
||||
asm volatile (" pushfl\n"
|
||||
" pop %%eax\n"
|
||||
" mov %%eax, %%ecx\n"
|
||||
" xor $0x200000, %%eax\n"
|
||||
" push %%eax\n"
|
||||
" popfl\n"
|
||||
" pushfl\n"
|
||||
" pop %%eax\n"
|
||||
" xor %%ecx, %%eax\n"
|
||||
" mov %%eax, %0\n"
|
||||
" push %%ecx\n"
|
||||
" popfl"
|
||||
: "=m" (supported) // output
|
||||
: // input
|
||||
: "eax", "ecx", "memory"); // clobbered register
|
||||
|
||||
return supported != 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,16 @@
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <unistd.h>
|
||||
|
||||
class NzHardwareInfoImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
static void Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 registers[4]);
|
||||
static unsigned int GetProcessorCount();
|
||||
static nzUInt64 GetTotalMemory();
|
||||
static bool IsCpuidSupported();
|
||||
};
|
||||
class HardwareInfoImpl
|
||||
{
|
||||
public:
|
||||
static void Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 registers[4]);
|
||||
static unsigned int GetProcessorCount();
|
||||
static UInt64 GetTotalMemory();
|
||||
static bool IsCpuidSupported();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_HARDWAREINFOIMPL_POSIX_HPP
|
||||
|
||||
@@ -5,31 +5,34 @@
|
||||
#include <Nazara/Core/Posix/MutexImpl.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzMutexImpl::NzMutexImpl()
|
||||
namespace Nz
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
MutexImpl::MutexImpl()
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
|
||||
pthread_mutex_init(&m_handle, &attr);
|
||||
}
|
||||
pthread_mutex_init(&m_handle, &attr);
|
||||
}
|
||||
|
||||
NzMutexImpl::~NzMutexImpl()
|
||||
{
|
||||
pthread_mutex_destroy(&m_handle);
|
||||
}
|
||||
MutexImpl::~MutexImpl()
|
||||
{
|
||||
pthread_mutex_destroy(&m_handle);
|
||||
}
|
||||
|
||||
void NzMutexImpl::Lock()
|
||||
{
|
||||
pthread_mutex_lock(&m_handle);
|
||||
}
|
||||
void MutexImpl::Lock()
|
||||
{
|
||||
pthread_mutex_lock(&m_handle);
|
||||
}
|
||||
|
||||
bool NzMutexImpl::TryLock()
|
||||
{
|
||||
return pthread_mutex_trylock(&m_handle) == 0;
|
||||
}
|
||||
bool MutexImpl::TryLock()
|
||||
{
|
||||
return pthread_mutex_trylock(&m_handle) == 0;
|
||||
}
|
||||
|
||||
void NzMutexImpl::Unlock()
|
||||
{
|
||||
pthread_mutex_unlock(&m_handle);
|
||||
void MutexImpl::Unlock()
|
||||
{
|
||||
pthread_mutex_unlock(&m_handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,20 +9,23 @@
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
class NzMutexImpl
|
||||
namespace Nz
|
||||
{
|
||||
friend class NzConditionVariableImpl;
|
||||
class MutexImpl
|
||||
{
|
||||
friend class ConditionVariableImpl;
|
||||
|
||||
public:
|
||||
NzMutexImpl();
|
||||
~NzMutexImpl();
|
||||
public:
|
||||
MutexImpl();
|
||||
~MutexImpl();
|
||||
|
||||
void Lock();
|
||||
bool TryLock();
|
||||
void Unlock();
|
||||
void Lock();
|
||||
bool TryLock();
|
||||
void Unlock();
|
||||
|
||||
private:
|
||||
pthread_mutex_t m_handle;
|
||||
};
|
||||
private:
|
||||
pthread_mutex_t m_handle;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_MUTEXIMPL_HPP
|
||||
|
||||
@@ -9,63 +9,66 @@
|
||||
#include <sys/time.h>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzSemaphoreImpl::NzSemaphoreImpl(unsigned int count)
|
||||
namespace Nz
|
||||
{
|
||||
if(sem_init(&m_semaphore, 0, count) != 0)
|
||||
NazaraError("Failed to create semaphore: " + NzError::GetLastSystemError());
|
||||
}
|
||||
|
||||
NzSemaphoreImpl::~NzSemaphoreImpl()
|
||||
{
|
||||
sem_destroy(&m_semaphore);
|
||||
}
|
||||
|
||||
unsigned int NzSemaphoreImpl::GetCount() const
|
||||
{
|
||||
int count=0;
|
||||
sem_getvalue(const_cast<sem_t*>(&m_semaphore), &count);
|
||||
return static_cast<unsigned int>(count);
|
||||
}
|
||||
|
||||
void NzSemaphoreImpl::Post()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (sem_post(&m_semaphore)==-1)
|
||||
NazaraError("Failed to release semaphore: " + NzError::GetLastSystemError());
|
||||
#else
|
||||
sem_post(&m_semaphore);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NzSemaphoreImpl::Wait()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (sem_wait(&m_semaphore) == -1 )
|
||||
NazaraError("Failed to wait for semaphore: " + NzError::GetLastSystemError());
|
||||
#else
|
||||
sem_wait(&m_semaphore);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool NzSemaphoreImpl::Wait(nzUInt32 timeout)
|
||||
{
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
timespec ti;
|
||||
ti.tv_nsec = (tv.tv_usec + (timeout % 1000)) * 1000000;
|
||||
ti.tv_sec = tv.tv_sec + (timeout / 1000) + (ti.tv_nsec / 1000000000);
|
||||
ti.tv_nsec %= 1000000000;
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (sem_timedwait(&m_semaphore, &ti) != 0)
|
||||
SemaphoreImpl::SemaphoreImpl(unsigned int count)
|
||||
{
|
||||
NazaraError("Failed to wait for semaphore: " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
if(sem_init(&m_semaphore, 0, count) != 0)
|
||||
NazaraError("Failed to create semaphore: " + Error::GetLastSystemError());
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return sem_timedwait(&m_semaphore, &ti) != 0;
|
||||
#endif
|
||||
SemaphoreImpl::~SemaphoreImpl()
|
||||
{
|
||||
sem_destroy(&m_semaphore);
|
||||
}
|
||||
|
||||
unsigned int SemaphoreImpl::GetCount() const
|
||||
{
|
||||
int count=0;
|
||||
sem_getvalue(const_cast<sem_t*>(&m_semaphore), &count);
|
||||
return static_cast<unsigned int>(count);
|
||||
}
|
||||
|
||||
void SemaphoreImpl::Post()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (sem_post(&m_semaphore)==-1)
|
||||
NazaraError("Failed to release semaphore: " + Error::GetLastSystemError());
|
||||
#else
|
||||
sem_post(&m_semaphore);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SemaphoreImpl::Wait()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (sem_wait(&m_semaphore) == -1 )
|
||||
NazaraError("Failed to wait for semaphore: " + Error::GetLastSystemError());
|
||||
#else
|
||||
sem_wait(&m_semaphore);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SemaphoreImpl::Wait(UInt32 timeout)
|
||||
{
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
timespec ti;
|
||||
ti.tv_nsec = (tv.tv_usec + (timeout % 1000)) * 1000000;
|
||||
ti.tv_sec = tv.tv_sec + (timeout / 1000) + (ti.tv_nsec / 1000000000);
|
||||
ti.tv_nsec %= 1000000000;
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (sem_timedwait(&m_semaphore, &ti) != 0)
|
||||
{
|
||||
NazaraError("Failed to wait for semaphore: " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
return sem_timedwait(&m_semaphore, &ti) != 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,19 +10,22 @@
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <semaphore.h>
|
||||
|
||||
class NzSemaphoreImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzSemaphoreImpl(unsigned int count);
|
||||
~NzSemaphoreImpl();
|
||||
class SemaphoreImpl
|
||||
{
|
||||
public:
|
||||
SemaphoreImpl(unsigned int count);
|
||||
~SemaphoreImpl();
|
||||
|
||||
unsigned int GetCount() const;
|
||||
void Post();
|
||||
void Wait();
|
||||
bool Wait(nzUInt32 timeout);
|
||||
unsigned int GetCount() const;
|
||||
void Post();
|
||||
void Wait();
|
||||
bool Wait(UInt32 timeout);
|
||||
|
||||
private:
|
||||
sem_t m_semaphore;
|
||||
};
|
||||
private:
|
||||
sem_t m_semaphore;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_SEMAPHOREIMPL_HPP
|
||||
|
||||
@@ -7,186 +7,189 @@
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
bool NzTaskSchedulerImpl::Initialize(unsigned int workerCount)
|
||||
namespace Nz
|
||||
{
|
||||
if (IsInitialized())
|
||||
return true; // Déjà initialisé
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (workerCount == 0)
|
||||
bool TaskSchedulerImpl::Initialize(unsigned int workerCount)
|
||||
{
|
||||
NazaraError("Invalid worker count ! (0)");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (IsInitialized())
|
||||
return true; // Déjà initialisé
|
||||
|
||||
s_workerCount = workerCount;
|
||||
s_isDone = false;
|
||||
s_isWaiting = false;
|
||||
s_shouldFinish = false;
|
||||
|
||||
s_threads.reset(new pthread_t[workerCount]);
|
||||
|
||||
// On initialise les conditions variables, mutex et barrière.
|
||||
pthread_cond_init(&s_cvEmpty, nullptr);
|
||||
pthread_cond_init(&s_cvNotEmpty, nullptr);
|
||||
pthread_mutex_init(&s_mutexQueue, nullptr);
|
||||
pthread_barrier_init(&s_barrier, nullptr, workerCount + 1);
|
||||
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
// Le thread va se lancer, attendre que tous se créent et attendre d'être réveillé.
|
||||
pthread_create(&s_threads[i], nullptr, WorkerProc, nullptr);
|
||||
}
|
||||
|
||||
pthread_barrier_wait(&s_barrier); // On attend que les enfants soient bien créés.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzTaskSchedulerImpl::IsInitialized()
|
||||
{
|
||||
return s_workerCount > 0;
|
||||
}
|
||||
|
||||
void NzTaskSchedulerImpl::Run(NzFunctor** tasks, unsigned int count)
|
||||
{
|
||||
// On s'assure que des tâches ne sont pas déjà en cours
|
||||
Wait();
|
||||
|
||||
pthread_mutex_lock(&s_mutexQueue);
|
||||
s_isDone = false;
|
||||
|
||||
while (count--)
|
||||
s_tasks.push(*tasks++);
|
||||
|
||||
pthread_cond_signal(&s_cvNotEmpty);
|
||||
pthread_mutex_unlock(&s_mutexQueue);
|
||||
}
|
||||
|
||||
void NzTaskSchedulerImpl::Uninitialize()
|
||||
{
|
||||
#ifdef NAZARA_CORE_SAFE
|
||||
if (s_workerCount == 0)
|
||||
{
|
||||
NazaraError("Task scheduler is not initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// On réveille les threads pour qu'ils sortent de la boucle et terminent.
|
||||
pthread_mutex_lock(&s_mutexQueue);
|
||||
// On commence par vider la queue et demander qu'ils s'arrêtent.
|
||||
std::queue<NzFunctor*> emptyQueue;
|
||||
std::swap(s_tasks, emptyQueue);
|
||||
s_shouldFinish = true;
|
||||
pthread_cond_broadcast(&s_cvNotEmpty);
|
||||
pthread_mutex_unlock(&s_mutexQueue);
|
||||
|
||||
// On attend que chaque thread se termine
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
pthread_join(s_threads[i], nullptr);
|
||||
|
||||
// Et on libère les ressources
|
||||
pthread_barrier_destroy(&s_barrier);
|
||||
pthread_cond_destroy(&s_cvEmpty);
|
||||
pthread_cond_destroy(&s_cvNotEmpty);
|
||||
pthread_mutex_destroy(&s_mutexQueue);
|
||||
|
||||
s_workerCount = 0;
|
||||
}
|
||||
|
||||
void NzTaskSchedulerImpl::WaitForTasks()
|
||||
{
|
||||
#ifdef NAZARA_CORE_SAFE
|
||||
if (s_workerCount == 0)
|
||||
{
|
||||
NazaraError("Task scheduler is not initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Wait();
|
||||
}
|
||||
|
||||
NzFunctor* NzTaskSchedulerImpl::PopQueue()
|
||||
{
|
||||
NzFunctor* task = nullptr;
|
||||
|
||||
pthread_mutex_lock(&s_mutexQueue);
|
||||
|
||||
if (!s_tasks.empty())
|
||||
{
|
||||
task = s_tasks.front();
|
||||
s_tasks.pop();
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&s_mutexQueue);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
void NzTaskSchedulerImpl::Wait()
|
||||
{
|
||||
if (s_isDone)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&s_mutexQueue);
|
||||
s_isWaiting = true;
|
||||
pthread_cond_broadcast(&s_cvNotEmpty);
|
||||
pthread_cond_wait(&s_cvEmpty, &s_mutexQueue);
|
||||
pthread_mutex_unlock(&s_mutexQueue);
|
||||
|
||||
s_isDone = true;
|
||||
}
|
||||
|
||||
void* NzTaskSchedulerImpl::WorkerProc(void* /*userdata*/)
|
||||
{
|
||||
// On s'assure que tous les threads soient correctement lancés.
|
||||
pthread_barrier_wait(&s_barrier);
|
||||
|
||||
// On quitte s'il doit terminer.
|
||||
while (!s_shouldFinish)
|
||||
{
|
||||
NzFunctor* task = PopQueue();
|
||||
|
||||
if (task)
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (workerCount == 0)
|
||||
{
|
||||
// On exécute la tâche avant de la supprimer
|
||||
task->Run();
|
||||
delete task;
|
||||
NazaraError("Invalid worker count ! (0)");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
||||
s_workerCount = workerCount;
|
||||
s_isDone = false;
|
||||
s_isWaiting = false;
|
||||
s_shouldFinish = false;
|
||||
|
||||
s_threads.reset(new pthread_t[workerCount]);
|
||||
|
||||
// On initialise les conditions variables, mutex et barrière.
|
||||
pthread_cond_init(&s_cvEmpty, nullptr);
|
||||
pthread_cond_init(&s_cvNotEmpty, nullptr);
|
||||
pthread_mutex_init(&s_mutexQueue, nullptr);
|
||||
pthread_barrier_init(&s_barrier, nullptr, workerCount + 1);
|
||||
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
pthread_mutex_lock(&s_mutexQueue);
|
||||
if (s_tasks.empty())
|
||||
s_isDone = true;
|
||||
// Le thread va se lancer, attendre que tous se créent et attendre d'être réveillé.
|
||||
pthread_create(&s_threads[i], nullptr, WorkerProc, nullptr);
|
||||
}
|
||||
|
||||
while (!(!s_tasks.empty() || s_isWaiting || s_shouldFinish))
|
||||
pthread_cond_wait(&s_cvNotEmpty, &s_mutexQueue);
|
||||
pthread_barrier_wait(&s_barrier); // On attend que les enfants soient bien créés.
|
||||
|
||||
if (s_tasks.empty() && s_isWaiting)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TaskSchedulerImpl::IsInitialized()
|
||||
{
|
||||
return s_workerCount > 0;
|
||||
}
|
||||
|
||||
void TaskSchedulerImpl::Run(Functor** tasks, unsigned int count)
|
||||
{
|
||||
// On s'assure que des tâches ne sont pas déjà en cours
|
||||
Wait();
|
||||
|
||||
pthread_mutex_lock(&s_mutexQueue);
|
||||
s_isDone = false;
|
||||
|
||||
while (count--)
|
||||
s_tasks.push(*tasks++);
|
||||
|
||||
pthread_cond_signal(&s_cvNotEmpty);
|
||||
pthread_mutex_unlock(&s_mutexQueue);
|
||||
}
|
||||
|
||||
void TaskSchedulerImpl::Uninitialize()
|
||||
{
|
||||
#ifdef NAZARA_CORE_SAFE
|
||||
if (s_workerCount == 0)
|
||||
{
|
||||
NazaraError("Task scheduler is not initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// On réveille les threads pour qu'ils sortent de la boucle et terminent.
|
||||
pthread_mutex_lock(&s_mutexQueue);
|
||||
// On commence par vider la queue et demander qu'ils s'arrêtent.
|
||||
std::queue<Functor*> emptyQueue;
|
||||
std::swap(s_tasks, emptyQueue);
|
||||
s_shouldFinish = true;
|
||||
pthread_cond_broadcast(&s_cvNotEmpty);
|
||||
pthread_mutex_unlock(&s_mutexQueue);
|
||||
|
||||
// On attend que chaque thread se termine
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
pthread_join(s_threads[i], nullptr);
|
||||
|
||||
// Et on libère les ressources
|
||||
pthread_barrier_destroy(&s_barrier);
|
||||
pthread_cond_destroy(&s_cvEmpty);
|
||||
pthread_cond_destroy(&s_cvNotEmpty);
|
||||
pthread_mutex_destroy(&s_mutexQueue);
|
||||
|
||||
s_workerCount = 0;
|
||||
}
|
||||
|
||||
void TaskSchedulerImpl::WaitForTasks()
|
||||
{
|
||||
#ifdef NAZARA_CORE_SAFE
|
||||
if (s_workerCount == 0)
|
||||
{
|
||||
NazaraError("Task scheduler is not initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
Wait();
|
||||
}
|
||||
|
||||
Functor* TaskSchedulerImpl::PopQueue()
|
||||
{
|
||||
Functor* task = nullptr;
|
||||
|
||||
pthread_mutex_lock(&s_mutexQueue);
|
||||
|
||||
if (!s_tasks.empty())
|
||||
{
|
||||
task = s_tasks.front();
|
||||
s_tasks.pop();
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&s_mutexQueue);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
void TaskSchedulerImpl::Wait()
|
||||
{
|
||||
if (s_isDone)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&s_mutexQueue);
|
||||
s_isWaiting = true;
|
||||
pthread_cond_broadcast(&s_cvNotEmpty);
|
||||
pthread_cond_wait(&s_cvEmpty, &s_mutexQueue);
|
||||
pthread_mutex_unlock(&s_mutexQueue);
|
||||
|
||||
s_isDone = true;
|
||||
}
|
||||
|
||||
void* TaskSchedulerImpl::WorkerProc(void* /*userdata*/)
|
||||
{
|
||||
// On s'assure que tous les threads soient correctement lancés.
|
||||
pthread_barrier_wait(&s_barrier);
|
||||
|
||||
// On quitte s'il doit terminer.
|
||||
while (!s_shouldFinish)
|
||||
{
|
||||
Functor* task = PopQueue();
|
||||
|
||||
if (task)
|
||||
{
|
||||
// On prévient le thread qui attend que les tâches soient effectuées.
|
||||
s_isWaiting = false;
|
||||
pthread_cond_signal(&s_cvEmpty);
|
||||
// On exécute la tâche avant de la supprimer
|
||||
task->Run();
|
||||
delete task;
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_lock(&s_mutexQueue);
|
||||
if (s_tasks.empty())
|
||||
s_isDone = true;
|
||||
|
||||
pthread_mutex_unlock(&s_mutexQueue);
|
||||
while (!(!s_tasks.empty() || s_isWaiting || s_shouldFinish))
|
||||
pthread_cond_wait(&s_cvNotEmpty, &s_mutexQueue);
|
||||
|
||||
if (s_tasks.empty() && s_isWaiting)
|
||||
{
|
||||
// On prévient le thread qui attend que les tâches soient effectuées.
|
||||
s_isWaiting = false;
|
||||
pthread_cond_signal(&s_cvEmpty);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&s_mutexQueue);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
std::queue<Functor*> TaskSchedulerImpl::s_tasks;
|
||||
std::unique_ptr<pthread_t[]> TaskSchedulerImpl::s_threads;
|
||||
std::atomic<bool> TaskSchedulerImpl::s_isDone;
|
||||
std::atomic<bool> TaskSchedulerImpl::s_isWaiting;
|
||||
std::atomic<bool> TaskSchedulerImpl::s_shouldFinish;
|
||||
unsigned int TaskSchedulerImpl::s_workerCount;
|
||||
|
||||
pthread_mutex_t TaskSchedulerImpl::s_mutexQueue;
|
||||
pthread_cond_t TaskSchedulerImpl::s_cvEmpty;
|
||||
pthread_cond_t TaskSchedulerImpl::s_cvNotEmpty;
|
||||
pthread_barrier_t TaskSchedulerImpl::s_barrier;
|
||||
}
|
||||
|
||||
std::queue<NzFunctor*> NzTaskSchedulerImpl::s_tasks;
|
||||
std::unique_ptr<pthread_t[]> NzTaskSchedulerImpl::s_threads;
|
||||
std::atomic<bool> NzTaskSchedulerImpl::s_isDone;
|
||||
std::atomic<bool> NzTaskSchedulerImpl::s_isWaiting;
|
||||
std::atomic<bool> NzTaskSchedulerImpl::s_shouldFinish;
|
||||
unsigned int NzTaskSchedulerImpl::s_workerCount;
|
||||
|
||||
pthread_mutex_t NzTaskSchedulerImpl::s_mutexQueue;
|
||||
pthread_cond_t NzTaskSchedulerImpl::s_cvEmpty;
|
||||
pthread_cond_t NzTaskSchedulerImpl::s_cvNotEmpty;
|
||||
pthread_barrier_t NzTaskSchedulerImpl::s_barrier;
|
||||
|
||||
@@ -14,34 +14,37 @@
|
||||
#include <pthread.h>
|
||||
#include <queue>
|
||||
|
||||
class NzTaskSchedulerImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzTaskSchedulerImpl() = delete;
|
||||
~NzTaskSchedulerImpl() = delete;
|
||||
class TaskSchedulerImpl
|
||||
{
|
||||
public:
|
||||
TaskSchedulerImpl() = delete;
|
||||
~TaskSchedulerImpl() = delete;
|
||||
|
||||
static bool Initialize(unsigned int workerCount);
|
||||
static bool IsInitialized();
|
||||
static void Run(NzFunctor** tasks, unsigned int count);
|
||||
static void Uninitialize();
|
||||
static void WaitForTasks();
|
||||
static bool Initialize(unsigned int workerCount);
|
||||
static bool IsInitialized();
|
||||
static void Run(Functor** tasks, unsigned int count);
|
||||
static void Uninitialize();
|
||||
static void WaitForTasks();
|
||||
|
||||
private:
|
||||
static NzFunctor* PopQueue();
|
||||
static void Wait();
|
||||
static void* WorkerProc(void* userdata);
|
||||
private:
|
||||
static Functor* PopQueue();
|
||||
static void Wait();
|
||||
static void* WorkerProc(void* userdata);
|
||||
|
||||
static std::queue<NzFunctor*> s_tasks;
|
||||
static std::unique_ptr<pthread_t[]> s_threads;
|
||||
static std::atomic<bool> s_isDone;
|
||||
static std::atomic<bool> s_isWaiting;
|
||||
static std::atomic<bool> s_shouldFinish;
|
||||
static unsigned int s_workerCount;
|
||||
static std::queue<Functor*> s_tasks;
|
||||
static std::unique_ptr<pthread_t[]> s_threads;
|
||||
static std::atomic<bool> s_isDone;
|
||||
static std::atomic<bool> s_isWaiting;
|
||||
static std::atomic<bool> s_shouldFinish;
|
||||
static unsigned int s_workerCount;
|
||||
|
||||
static pthread_mutex_t s_mutexQueue;
|
||||
static pthread_cond_t s_cvEmpty;
|
||||
static pthread_cond_t s_cvNotEmpty;
|
||||
static pthread_barrier_t s_barrier;
|
||||
};
|
||||
static pthread_mutex_t s_mutexQueue;
|
||||
static pthread_cond_t s_cvEmpty;
|
||||
static pthread_cond_t s_cvNotEmpty;
|
||||
static pthread_barrier_t s_barrier;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_TASKSCHEDULERIMPL_HPP
|
||||
|
||||
@@ -9,64 +9,67 @@
|
||||
#include <sys/time.h>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzThreadImpl::NzThreadImpl(NzFunctor* functor)
|
||||
namespace Nz
|
||||
{
|
||||
int error = pthread_create(&m_handle, nullptr, &NzThreadImpl::ThreadProc, functor);
|
||||
if (error != 0)
|
||||
NazaraInternalError("Failed to create thread: " + NzError::GetLastSystemError());
|
||||
}
|
||||
|
||||
void NzThreadImpl::Detach()
|
||||
{
|
||||
pthread_detach(m_handle);
|
||||
}
|
||||
|
||||
void NzThreadImpl::Join()
|
||||
{
|
||||
pthread_join(m_handle, nullptr);
|
||||
}
|
||||
|
||||
void* NzThreadImpl::ThreadProc(void* userdata)
|
||||
{
|
||||
NzFunctor* func = static_cast<NzFunctor*>(userdata);
|
||||
func->Run();
|
||||
delete func;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NzThreadImpl::Sleep(nzUInt32 time)
|
||||
{
|
||||
// code from SFML2 Unix SleepImpl.cpp source https://github.com/LaurentGomila/SFML/blob/master/src/SFML/System/Unix/SleepImpl.cpp
|
||||
|
||||
// usleep is not reliable enough (it might block the
|
||||
// whole process instead of just the current thread)
|
||||
// so we must use pthread_cond_timedwait instead
|
||||
|
||||
// this implementation is inspired from Qt
|
||||
|
||||
// get the current time
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
// construct the time limit (current time + time to wait)
|
||||
timespec ti;
|
||||
ti.tv_nsec = (tv.tv_usec + (time % 1000)) * 1000;
|
||||
ti.tv_sec = tv.tv_sec + (time / 1000) + (ti.tv_nsec / 1000000000);
|
||||
ti.tv_nsec %= 1000000000;
|
||||
|
||||
// create a mutex and thread condition
|
||||
pthread_mutex_t mutex;
|
||||
pthread_mutex_init(&mutex, nullptr);
|
||||
pthread_cond_t condition;
|
||||
pthread_cond_init(&condition, nullptr);
|
||||
|
||||
// wait...
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_cond_timedwait(&condition, &mutex, &ti);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
// destroy the mutex and condition
|
||||
pthread_cond_destroy(&condition);
|
||||
pthread_mutex_destroy(&mutex);
|
||||
ThreadImpl::ThreadImpl(Functor* functor)
|
||||
{
|
||||
int error = pthread_create(&m_handle, nullptr, &ThreadImpl::ThreadProc, functor);
|
||||
if (error != 0)
|
||||
NazaraInternalError("Failed to create thread: " + Error::GetLastSystemError());
|
||||
}
|
||||
|
||||
void ThreadImpl::Detach()
|
||||
{
|
||||
pthread_detach(m_handle);
|
||||
}
|
||||
|
||||
void ThreadImpl::Join()
|
||||
{
|
||||
pthread_join(m_handle, nullptr);
|
||||
}
|
||||
|
||||
void* ThreadImpl::ThreadProc(void* userdata)
|
||||
{
|
||||
Functor* func = static_cast<Functor*>(userdata);
|
||||
func->Run();
|
||||
delete func;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ThreadImpl::Sleep(UInt32 time)
|
||||
{
|
||||
// code from SFML2 Unix SleepImpl.cpp source https://github.com/LaurentGomila/SFML/blob/master/src/SFML/System/Unix/SleepImpl.cpp
|
||||
|
||||
// usleep is not reliable enough (it might block the
|
||||
// whole process instead of just the current thread)
|
||||
// so we must use pthread_cond_timedwait instead
|
||||
|
||||
// this implementation is inspired from Qt
|
||||
|
||||
// get the current time
|
||||
timeval tv;
|
||||
gettimeofday(&tv, nullptr);
|
||||
|
||||
// construct the time limit (current time + time to wait)
|
||||
timespec ti;
|
||||
ti.tv_nsec = (tv.tv_usec + (time % 1000)) * 1000;
|
||||
ti.tv_sec = tv.tv_sec + (time / 1000) + (ti.tv_nsec / 1000000000);
|
||||
ti.tv_nsec %= 1000000000;
|
||||
|
||||
// create a mutex and thread condition
|
||||
pthread_mutex_t mutex;
|
||||
pthread_mutex_init(&mutex, nullptr);
|
||||
pthread_cond_t condition;
|
||||
pthread_cond_init(&condition, nullptr);
|
||||
|
||||
// wait...
|
||||
pthread_mutex_lock(&mutex);
|
||||
pthread_cond_timedwait(&condition, &mutex, &ti);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
// destroy the mutex and condition
|
||||
pthread_cond_destroy(&condition);
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,22 +10,25 @@
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <pthread.h>
|
||||
|
||||
struct NzFunctor;
|
||||
|
||||
class NzThreadImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzThreadImpl(NzFunctor* threadFunc);
|
||||
struct Functor;
|
||||
|
||||
void Detach();
|
||||
void Join();
|
||||
class ThreadImpl
|
||||
{
|
||||
public:
|
||||
ThreadImpl(Functor* threadFunc);
|
||||
|
||||
static void Sleep(nzUInt32 time);
|
||||
void Detach();
|
||||
void Join();
|
||||
|
||||
private:
|
||||
static void* ThreadProc(void* userdata);
|
||||
static void Sleep(UInt32 time);
|
||||
|
||||
pthread_t m_handle;
|
||||
};
|
||||
private:
|
||||
static void* ThreadProc(void* userdata);
|
||||
|
||||
pthread_t m_handle;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_THREADIMPL_HPP
|
||||
|
||||
@@ -6,112 +6,99 @@
|
||||
#include <Nazara/Core/Config.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
void NzPrimitiveList::AddBox(const NzVector3f& lengths, const NzVector3ui& subdivision, const NzMatrix4f& transformMatrix)
|
||||
namespace Nz
|
||||
{
|
||||
m_primitives.push_back(NzPrimitive::Box(lengths, subdivision, transformMatrix));
|
||||
}
|
||||
|
||||
void NzPrimitiveList::AddBox(const NzVector3f& lengths, const NzVector3ui& subdivision, const NzVector3f& position, const NzQuaternionf& rotation)
|
||||
{
|
||||
m_primitives.push_back(NzPrimitive::Box(lengths, subdivision, position, rotation));
|
||||
}
|
||||
|
||||
void NzPrimitiveList::AddCone(float length, float radius, unsigned int subdivision, const NzMatrix4f& transformMatrix)
|
||||
{
|
||||
m_primitives.push_back(NzPrimitive::Cone(length, radius, subdivision, transformMatrix));
|
||||
}
|
||||
|
||||
void NzPrimitiveList::AddCone(float length, float radius, unsigned int subdivision, const NzVector3f& position, const NzQuaternionf& rotation)
|
||||
{
|
||||
m_primitives.push_back(NzPrimitive::Cone(length, radius, subdivision, position, rotation));
|
||||
}
|
||||
|
||||
void NzPrimitiveList::AddCubicSphere(float size, unsigned int subdivision, const NzMatrix4f& transformMatrix)
|
||||
{
|
||||
m_primitives.push_back(NzPrimitive::CubicSphere(size, subdivision, transformMatrix));
|
||||
}
|
||||
|
||||
void NzPrimitiveList::AddCubicSphere(float size, unsigned int subdivision, const NzVector3f& position, const NzQuaternionf& rotation)
|
||||
{
|
||||
m_primitives.push_back(NzPrimitive::CubicSphere(size, subdivision, position, rotation));
|
||||
}
|
||||
|
||||
void NzPrimitiveList::AddIcoSphere(float size, unsigned int recursionLevel, const NzMatrix4f& transformMatrix)
|
||||
{
|
||||
m_primitives.push_back(NzPrimitive::IcoSphere(size, recursionLevel, transformMatrix));
|
||||
}
|
||||
|
||||
void NzPrimitiveList::AddIcoSphere(float size, unsigned int recursionLevel, const NzVector3f& position, const NzQuaternionf& rotation)
|
||||
{
|
||||
m_primitives.push_back(NzPrimitive::IcoSphere(size, recursionLevel, position, rotation));
|
||||
}
|
||||
|
||||
void NzPrimitiveList::AddPlane(const NzVector2f& size, const NzVector2ui& subdivision, const NzMatrix4f& transformMatrix)
|
||||
{
|
||||
m_primitives.push_back(NzPrimitive::Plane(size, subdivision, transformMatrix));
|
||||
}
|
||||
|
||||
void NzPrimitiveList::AddPlane(const NzVector2f& size, const NzVector2ui& subdivision, const NzPlanef& planeInfo)
|
||||
{
|
||||
m_primitives.push_back(NzPrimitive::Plane(size, subdivision, planeInfo));
|
||||
}
|
||||
|
||||
void NzPrimitiveList::AddPlane(const NzVector2f& size, const NzVector2ui& subdivision, const NzVector3f& position, const NzQuaternionf& rotation)
|
||||
{
|
||||
m_primitives.push_back(NzPrimitive::Plane(size, subdivision, position, rotation));
|
||||
}
|
||||
|
||||
void NzPrimitiveList::AddUVSphere(float size, unsigned int sliceCount, unsigned int stackCount, const NzMatrix4f& transformMatrix)
|
||||
{
|
||||
m_primitives.push_back(NzPrimitive::UVSphere(size, sliceCount, stackCount, transformMatrix));
|
||||
}
|
||||
|
||||
void NzPrimitiveList::AddUVSphere(float size, unsigned int sliceCount, unsigned int stackCount, const NzVector3f& position, const NzQuaternionf& rotation)
|
||||
{
|
||||
m_primitives.push_back(NzPrimitive::UVSphere(size, sliceCount, stackCount, position, rotation));
|
||||
}
|
||||
|
||||
NzPrimitive& NzPrimitiveList::GetPrimitive(unsigned int i)
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (i >= m_primitives.size())
|
||||
void PrimitiveList::AddBox(const Vector3f& lengths, const Vector3ui& subdivision, const Matrix4f& transformMatrix)
|
||||
{
|
||||
NazaraError("Primitive index out of range (" + NzString::Number(i) + " >= " + NzString::Number(m_primitives.size()) + ')');
|
||||
|
||||
static NzPrimitive dummy;
|
||||
return dummy;
|
||||
m_primitives.push_back(Primitive::Box(lengths, subdivision, transformMatrix));
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_primitives[i];
|
||||
}
|
||||
|
||||
const NzPrimitive& NzPrimitiveList::GetPrimitive(unsigned int i) const
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (i >= m_primitives.size())
|
||||
void PrimitiveList::AddBox(const Vector3f& lengths, const Vector3ui& subdivision, const Vector3f& position, const Quaternionf& rotation)
|
||||
{
|
||||
NazaraError("Primitive index out of range (" + NzString::Number(i) + " >= " + NzString::Number(m_primitives.size()) + ')');
|
||||
|
||||
static NzPrimitive dummy;
|
||||
return dummy;
|
||||
m_primitives.push_back(Primitive::Box(lengths, subdivision, position, rotation));
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_primitives[i];
|
||||
}
|
||||
void PrimitiveList::AddCone(float length, float radius, unsigned int subdivision, const Matrix4f& transformMatrix)
|
||||
{
|
||||
m_primitives.push_back(Primitive::Cone(length, radius, subdivision, transformMatrix));
|
||||
}
|
||||
|
||||
unsigned int NzPrimitiveList::GetSize() const
|
||||
{
|
||||
return m_primitives.size();
|
||||
}
|
||||
void PrimitiveList::AddCone(float length, float radius, unsigned int subdivision, const Vector3f& position, const Quaternionf& rotation)
|
||||
{
|
||||
m_primitives.push_back(Primitive::Cone(length, radius, subdivision, position, rotation));
|
||||
}
|
||||
|
||||
NzPrimitive& NzPrimitiveList::operator()(unsigned int i)
|
||||
{
|
||||
return GetPrimitive(i);
|
||||
}
|
||||
void PrimitiveList::AddCubicSphere(float size, unsigned int subdivision, const Matrix4f& transformMatrix)
|
||||
{
|
||||
m_primitives.push_back(Primitive::CubicSphere(size, subdivision, transformMatrix));
|
||||
}
|
||||
|
||||
const NzPrimitive& NzPrimitiveList::operator()(unsigned int i) const
|
||||
{
|
||||
return GetPrimitive(i);
|
||||
void PrimitiveList::AddCubicSphere(float size, unsigned int subdivision, const Vector3f& position, const Quaternionf& rotation)
|
||||
{
|
||||
m_primitives.push_back(Primitive::CubicSphere(size, subdivision, position, rotation));
|
||||
}
|
||||
|
||||
void PrimitiveList::AddIcoSphere(float size, unsigned int recursionLevel, const Matrix4f& transformMatrix)
|
||||
{
|
||||
m_primitives.push_back(Primitive::IcoSphere(size, recursionLevel, transformMatrix));
|
||||
}
|
||||
|
||||
void PrimitiveList::AddIcoSphere(float size, unsigned int recursionLevel, const Vector3f& position, const Quaternionf& rotation)
|
||||
{
|
||||
m_primitives.push_back(Primitive::IcoSphere(size, recursionLevel, position, rotation));
|
||||
}
|
||||
|
||||
void PrimitiveList::AddPlane(const Vector2f& size, const Vector2ui& subdivision, const Matrix4f& transformMatrix)
|
||||
{
|
||||
m_primitives.push_back(Primitive::Plane(size, subdivision, transformMatrix));
|
||||
}
|
||||
|
||||
void PrimitiveList::AddPlane(const Vector2f& size, const Vector2ui& subdivision, const Planef& planeInfo)
|
||||
{
|
||||
m_primitives.push_back(Primitive::Plane(size, subdivision, planeInfo));
|
||||
}
|
||||
|
||||
void PrimitiveList::AddPlane(const Vector2f& size, const Vector2ui& subdivision, const Vector3f& position, const Quaternionf& rotation)
|
||||
{
|
||||
m_primitives.push_back(Primitive::Plane(size, subdivision, position, rotation));
|
||||
}
|
||||
|
||||
void PrimitiveList::AddUVSphere(float size, unsigned int sliceCount, unsigned int stackCount, const Matrix4f& transformMatrix)
|
||||
{
|
||||
m_primitives.push_back(Primitive::UVSphere(size, sliceCount, stackCount, transformMatrix));
|
||||
}
|
||||
|
||||
void PrimitiveList::AddUVSphere(float size, unsigned int sliceCount, unsigned int stackCount, const Vector3f& position, const Quaternionf& rotation)
|
||||
{
|
||||
m_primitives.push_back(Primitive::UVSphere(size, sliceCount, stackCount, position, rotation));
|
||||
}
|
||||
|
||||
Primitive& PrimitiveList::GetPrimitive(std::size_t i)
|
||||
{
|
||||
NazaraAssert(i < m_primitives.size(), "Primitive index out of range");
|
||||
|
||||
return m_primitives[i];
|
||||
}
|
||||
|
||||
const Primitive& PrimitiveList::GetPrimitive(std::size_t i) const
|
||||
{
|
||||
NazaraAssert(i < m_primitives.size(), "Primitive index out of range");
|
||||
|
||||
return m_primitives[i];
|
||||
}
|
||||
|
||||
std::size_t PrimitiveList::GetSize() const
|
||||
{
|
||||
return m_primitives.size();
|
||||
}
|
||||
|
||||
Primitive& PrimitiveList::operator()(unsigned int i)
|
||||
{
|
||||
return GetPrimitive(i);
|
||||
}
|
||||
|
||||
const Primitive& PrimitiveList::operator()(unsigned int i) const
|
||||
{
|
||||
return GetPrimitive(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,66 +14,68 @@
|
||||
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzRefCounted::NzRefCounted(bool persistent) :
|
||||
m_persistent(persistent),
|
||||
m_referenceCount(0)
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
NzRefCounted::~NzRefCounted()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (m_referenceCount > 0)
|
||||
NazaraWarning("Resource destroyed while still referenced " + NzString::Number(m_referenceCount) + " time(s)");
|
||||
#endif
|
||||
}
|
||||
|
||||
void NzRefCounted::AddReference() const
|
||||
{
|
||||
m_referenceCount++;
|
||||
}
|
||||
|
||||
unsigned int NzRefCounted::GetReferenceCount() const
|
||||
{
|
||||
return m_referenceCount;
|
||||
}
|
||||
|
||||
bool NzRefCounted::IsPersistent() const
|
||||
{
|
||||
return m_persistent;
|
||||
}
|
||||
|
||||
bool NzRefCounted::RemoveReference() const
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (m_referenceCount == 0)
|
||||
RefCounted::RefCounted(bool persistent) :
|
||||
m_persistent(persistent),
|
||||
m_referenceCount(0)
|
||||
{
|
||||
NazaraError("Impossible to remove reference (Ref. counter is already 0)");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (--m_referenceCount == 0 && !m_persistent)
|
||||
RefCounted::~RefCounted()
|
||||
{
|
||||
delete this; // Suicide
|
||||
|
||||
return true;
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (m_referenceCount > 0)
|
||||
NazaraWarning("Resource destroyed while still referenced " + String::Number(m_referenceCount) + " time(s)");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NzRefCounted::SetPersistent(bool persistent, bool checkReferenceCount)
|
||||
{
|
||||
m_persistent = persistent;
|
||||
|
||||
if (checkReferenceCount && !persistent && m_referenceCount == 0)
|
||||
void RefCounted::AddReference() const
|
||||
{
|
||||
delete this;
|
||||
|
||||
return true;
|
||||
m_referenceCount++;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int RefCounted::GetReferenceCount() const
|
||||
{
|
||||
return m_referenceCount;
|
||||
}
|
||||
|
||||
bool RefCounted::IsPersistent() const
|
||||
{
|
||||
return m_persistent;
|
||||
}
|
||||
|
||||
bool RefCounted::RemoveReference() const
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (m_referenceCount == 0)
|
||||
{
|
||||
NazaraError("Impossible to remove reference (Ref. counter is already 0)");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (--m_referenceCount == 0 && !m_persistent)
|
||||
{
|
||||
delete this; // Suicide
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RefCounted::SetPersistent(bool persistent, bool checkReferenceCount)
|
||||
{
|
||||
m_persistent = persistent;
|
||||
|
||||
if (checkReferenceCount && !persistent && m_referenceCount == 0)
|
||||
{
|
||||
delete this;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,14 +5,17 @@
|
||||
#include <Nazara/Core/Resource.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzResource::~NzResource() = default;
|
||||
|
||||
const NzString& NzResource::GetFilePath() const
|
||||
namespace Nz
|
||||
{
|
||||
return m_filePath;
|
||||
}
|
||||
Resource::~Resource() = default;
|
||||
|
||||
void NzResource::SetFilePath(const NzString& filePath)
|
||||
{
|
||||
m_filePath = filePath;
|
||||
const String& Resource::GetFilePath() const
|
||||
{
|
||||
return m_filePath;
|
||||
}
|
||||
|
||||
void Resource::SetFilePath(const String& filePath)
|
||||
{
|
||||
m_filePath = filePath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,32 +14,35 @@
|
||||
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzSemaphore::NzSemaphore(unsigned int count)
|
||||
namespace Nz
|
||||
{
|
||||
m_impl = new NzSemaphoreImpl(count);
|
||||
}
|
||||
Semaphore::Semaphore(unsigned int count)
|
||||
{
|
||||
m_impl = new SemaphoreImpl(count);
|
||||
}
|
||||
|
||||
NzSemaphore::~NzSemaphore()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
Semaphore::~Semaphore()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
unsigned int NzSemaphore::GetCount() const
|
||||
{
|
||||
return m_impl->GetCount();
|
||||
}
|
||||
unsigned int Semaphore::GetCount() const
|
||||
{
|
||||
return m_impl->GetCount();
|
||||
}
|
||||
|
||||
void NzSemaphore::Post()
|
||||
{
|
||||
m_impl->Post();
|
||||
}
|
||||
void Semaphore::Post()
|
||||
{
|
||||
m_impl->Post();
|
||||
}
|
||||
|
||||
void NzSemaphore::Wait()
|
||||
{
|
||||
m_impl->Wait();
|
||||
}
|
||||
void Semaphore::Wait()
|
||||
{
|
||||
m_impl->Wait();
|
||||
}
|
||||
|
||||
bool NzSemaphore::Wait(nzUInt32 timeout)
|
||||
{
|
||||
return m_impl->Wait(timeout);
|
||||
bool Semaphore::Wait(UInt32 timeout)
|
||||
{
|
||||
return m_impl->Wait(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
86
src/Nazara/Core/StdLogger.cpp
Normal file
86
src/Nazara/Core/StdLogger.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// 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/StdLogger.hpp>
|
||||
#include <cstdio>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
namespace
|
||||
{
|
||||
const char* errorType[] = {
|
||||
"Assert failed", // ErrorType_AssertFailed
|
||||
"Internal error", // ErrorType_Internal
|
||||
"Error", // ErrorType_Normal
|
||||
"Warning" // ErrorType_Warning
|
||||
};
|
||||
|
||||
static_assert(sizeof(errorType) / sizeof(const char*) == ErrorType_Max + 1, "Error type array is incomplete");
|
||||
}
|
||||
|
||||
/*!
|
||||
* \class Nz::StdLogger
|
||||
* \brief Logger writing to standard output (stdout, stderr)
|
||||
*/
|
||||
|
||||
StdLogger::~StdLogger() = default;
|
||||
|
||||
/*!
|
||||
* \brief Enable replication to standard output
|
||||
*
|
||||
* Does nothing, as the std logger always write to standard output
|
||||
*/
|
||||
|
||||
void StdLogger::EnableStdReplication(bool enable)
|
||||
{
|
||||
NazaraUnused(enable);
|
||||
// We always replicate to std, that's our purpose
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Get the standard output replication status
|
||||
*
|
||||
* Always returns true
|
||||
*/
|
||||
|
||||
bool StdLogger::IsStdReplicationEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Write to the console
|
||||
* \param string The log to write to the console
|
||||
*
|
||||
* \see WriteError
|
||||
*/
|
||||
|
||||
void StdLogger::Write(const String& string)
|
||||
{
|
||||
fputs(string.GetConstBuffer(), stdout);
|
||||
fputc('\n', stdout);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Write an error to the console
|
||||
* \param type The error type
|
||||
* \param error The error text
|
||||
* \param line The line the error occurred
|
||||
* \param file The file the error occurred
|
||||
* \param function The function the error occurred
|
||||
*
|
||||
* \see Write
|
||||
*/
|
||||
|
||||
void StdLogger::WriteError(ErrorType type, const String& error, unsigned int line, const char* file, const char* function)
|
||||
{
|
||||
fprintf(stderr, "%s: %s", errorType[type], error.GetConstBuffer());
|
||||
|
||||
if (line != 0 && file && function)
|
||||
fprintf(stderr, " (in %s at %s:%d)", function, file, line);
|
||||
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
}
|
||||
@@ -3,26 +3,105 @@
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Core/Stream.hpp>
|
||||
#include <Nazara/Core/ByteArray.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/String.hpp>
|
||||
#include <cstring>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzStream::~NzStream() = default;
|
||||
|
||||
NzString NzStream::GetDirectory() const
|
||||
namespace Nz
|
||||
{
|
||||
return NzString();
|
||||
}
|
||||
Stream::~Stream() = default;
|
||||
|
||||
NzString NzStream::GetPath() const
|
||||
{
|
||||
return NzString();
|
||||
}
|
||||
String Stream::GetDirectory() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
unsigned int NzStream::GetStreamOptions() const
|
||||
{
|
||||
return m_streamOptions;
|
||||
}
|
||||
String Stream::GetPath() const
|
||||
{
|
||||
return String();
|
||||
}
|
||||
|
||||
void NzStream::SetStreamOptions(unsigned int options)
|
||||
{
|
||||
m_streamOptions = options;
|
||||
String Stream::ReadLine(unsigned int lineSize)
|
||||
{
|
||||
String line;
|
||||
if (lineSize == 0) // Taille maximale indéterminée
|
||||
{
|
||||
const unsigned int bufferSize = 64;
|
||||
|
||||
char buffer[bufferSize + 1];
|
||||
buffer[bufferSize] = '\0';
|
||||
|
||||
std::size_t readSize;
|
||||
do
|
||||
{
|
||||
readSize = Read(buffer, bufferSize);
|
||||
|
||||
const char* ptr = std::strchr(buffer, '\n');
|
||||
if (ptr)
|
||||
{
|
||||
std::ptrdiff_t pos = ptr - buffer;
|
||||
|
||||
if (m_streamOptions & StreamOption_Text && pos > 0 && buffer[pos - 1] == '\r')
|
||||
line.Append(buffer, pos - 1);
|
||||
else
|
||||
line.Append(buffer, pos);
|
||||
|
||||
if (!SetCursorPos(GetCursorPos() - readSize + pos + 1))
|
||||
NazaraWarning("Failed to reset cursos pos");
|
||||
|
||||
break;
|
||||
}
|
||||
else
|
||||
line.Append(buffer, readSize);
|
||||
}
|
||||
while (readSize == bufferSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
line.Set(lineSize, '\0');
|
||||
std::size_t readSize = Read(&line[0], lineSize);
|
||||
std::size_t pos = line.Find('\n');
|
||||
if (pos <= readSize) // Faux uniquement si le caractère n'est pas présent (npos étant le plus grand entier)
|
||||
{
|
||||
if (m_streamOptions & StreamOption_Text && pos > 0 && line[pos - 1] == '\r')
|
||||
line.Resize(pos);
|
||||
else
|
||||
line.Resize(pos + 1);
|
||||
|
||||
if (!SetCursorPos(GetCursorPos() - readSize + pos + 1))
|
||||
NazaraWarning("Failed to reset cursos pos");
|
||||
}
|
||||
else
|
||||
line.Resize(readSize);
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
bool Stream::Write(const ByteArray& byteArray)
|
||||
{
|
||||
ByteArray::size_type size = byteArray.GetSize();
|
||||
return Write(byteArray.GetConstBuffer(), size) == size;
|
||||
}
|
||||
|
||||
bool Stream::Write(const String& string)
|
||||
{
|
||||
String temp(string);
|
||||
|
||||
if (m_streamOptions & StreamOption_Text)
|
||||
{
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
temp.Replace("\n", "\r\n");
|
||||
#elif defined(NAZARA_PLATFORM_LINUX)
|
||||
// Nothing to do
|
||||
#elif defined(NAZARA_PLATFORM_MACOS)
|
||||
temp.Replace('\n', '\r');
|
||||
#endif
|
||||
}
|
||||
|
||||
std::size_t size = temp.GetSize();
|
||||
return Write(temp.GetConstBuffer(), size) == size;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,173 +5,176 @@
|
||||
#include <Nazara/Core/StringStream.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzStringStream::NzStringStream() :
|
||||
m_bufferSize(0)
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
NzStringStream::NzStringStream(const NzString& str) :
|
||||
m_bufferSize(str.GetSize())
|
||||
{
|
||||
m_strings.push_back(str);
|
||||
}
|
||||
|
||||
NzString NzStringStream::ToString() const
|
||||
{
|
||||
NzString string;
|
||||
string.Reserve(m_bufferSize);
|
||||
|
||||
for (const NzString& str : m_strings)
|
||||
string += str;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(bool boolean)
|
||||
{
|
||||
m_strings.push_back(NzString::Boolean(boolean));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(short number)
|
||||
{
|
||||
m_strings.push_back(NzString::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(unsigned short number)
|
||||
{
|
||||
m_strings.push_back(NzString::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(int number)
|
||||
{
|
||||
m_strings.push_back(NzString::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(unsigned int number)
|
||||
{
|
||||
m_strings.push_back(NzString::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(long number)
|
||||
{
|
||||
m_strings.push_back(NzString::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(unsigned long number)
|
||||
{
|
||||
m_strings.push_back(NzString::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(long long number)
|
||||
{
|
||||
m_strings.push_back(NzString::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(unsigned long long number)
|
||||
{
|
||||
m_strings.push_back(NzString::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(float number)
|
||||
{
|
||||
m_strings.push_back(NzString::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(double number)
|
||||
{
|
||||
m_strings.push_back(NzString::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(long double number)
|
||||
{
|
||||
m_strings.push_back(NzString::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(char character)
|
||||
{
|
||||
m_strings.push_back(NzString(character));
|
||||
m_bufferSize++;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(unsigned char character)
|
||||
{
|
||||
m_strings.push_back(NzString(static_cast<char>(character)));
|
||||
m_bufferSize++;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(const char* string)
|
||||
{
|
||||
m_strings.push_back(string);
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(const std::string& string)
|
||||
{
|
||||
m_strings.push_back(string);
|
||||
m_bufferSize += string.size();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(const NzString& string)
|
||||
{
|
||||
m_strings.push_back(string);
|
||||
m_bufferSize += string.GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream& NzStringStream::operator<<(const void* ptr)
|
||||
{
|
||||
m_strings.push_back(NzString::Pointer(ptr));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzStringStream::operator NzString() const
|
||||
{
|
||||
return ToString();
|
||||
StringStream::StringStream() :
|
||||
m_bufferSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
StringStream::StringStream(const String& str) :
|
||||
m_bufferSize(str.GetSize())
|
||||
{
|
||||
m_strings.push_back(str);
|
||||
}
|
||||
|
||||
String StringStream::ToString() const
|
||||
{
|
||||
String string;
|
||||
string.Reserve(m_bufferSize);
|
||||
|
||||
for (const String& str : m_strings)
|
||||
string += str;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(bool boolean)
|
||||
{
|
||||
m_strings.push_back(String::Boolean(boolean));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(short number)
|
||||
{
|
||||
m_strings.push_back(String::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(unsigned short number)
|
||||
{
|
||||
m_strings.push_back(String::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(int number)
|
||||
{
|
||||
m_strings.push_back(String::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(unsigned int number)
|
||||
{
|
||||
m_strings.push_back(String::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(long number)
|
||||
{
|
||||
m_strings.push_back(String::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(unsigned long number)
|
||||
{
|
||||
m_strings.push_back(String::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(long long number)
|
||||
{
|
||||
m_strings.push_back(String::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(unsigned long long number)
|
||||
{
|
||||
m_strings.push_back(String::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(float number)
|
||||
{
|
||||
m_strings.push_back(String::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(double number)
|
||||
{
|
||||
m_strings.push_back(String::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(long double number)
|
||||
{
|
||||
m_strings.push_back(String::Number(number));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(char character)
|
||||
{
|
||||
m_strings.push_back(String(character));
|
||||
m_bufferSize++;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(unsigned char character)
|
||||
{
|
||||
m_strings.push_back(String(static_cast<char>(character)));
|
||||
m_bufferSize++;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(const char* string)
|
||||
{
|
||||
m_strings.push_back(string);
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(const std::string& string)
|
||||
{
|
||||
m_strings.push_back(string);
|
||||
m_bufferSize += string.size();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(const String& string)
|
||||
{
|
||||
m_strings.push_back(string);
|
||||
m_bufferSize += string.GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream& StringStream::operator<<(const void* ptr)
|
||||
{
|
||||
m_strings.push_back(String::Pointer(ptr));
|
||||
m_bufferSize += m_strings.back().GetSize();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
StringStream::operator String() const
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,74 +16,77 @@
|
||||
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace
|
||||
namespace Nz
|
||||
{
|
||||
std::vector<NzFunctor*> s_pendingWorks;
|
||||
unsigned int s_workerCount = 0;
|
||||
}
|
||||
|
||||
unsigned int NzTaskScheduler::GetWorkerCount()
|
||||
{
|
||||
return (s_workerCount > 0) ? s_workerCount : NzHardwareInfo::GetProcessorCount();
|
||||
}
|
||||
|
||||
bool NzTaskScheduler::Initialize()
|
||||
{
|
||||
return NzTaskSchedulerImpl::Initialize(GetWorkerCount());
|
||||
}
|
||||
|
||||
void NzTaskScheduler::Run()
|
||||
{
|
||||
if (!Initialize())
|
||||
namespace
|
||||
{
|
||||
NazaraError("Failed to initialize Task Scheduler");
|
||||
return;
|
||||
std::vector<Functor*> s_pendingWorks;
|
||||
unsigned int s_workerCount = 0;
|
||||
}
|
||||
|
||||
if (!s_pendingWorks.empty())
|
||||
unsigned int TaskScheduler::GetWorkerCount()
|
||||
{
|
||||
NzTaskSchedulerImpl::Run(&s_pendingWorks[0], s_pendingWorks.size());
|
||||
s_pendingWorks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void NzTaskScheduler::SetWorkerCount(unsigned int workerCount)
|
||||
{
|
||||
#ifdef NAZARA_CORE_SAFE
|
||||
if (NzTaskSchedulerImpl::IsInitialized())
|
||||
{
|
||||
NazaraError("Worker count cannot be set while initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
s_workerCount = workerCount;
|
||||
}
|
||||
|
||||
void NzTaskScheduler::Uninitialize()
|
||||
{
|
||||
if (NzTaskSchedulerImpl::IsInitialized())
|
||||
NzTaskSchedulerImpl::Uninitialize();
|
||||
}
|
||||
|
||||
void NzTaskScheduler::WaitForTasks()
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Task Scheduler");
|
||||
return;
|
||||
return (s_workerCount > 0) ? s_workerCount : HardwareInfo::GetProcessorCount();
|
||||
}
|
||||
|
||||
NzTaskSchedulerImpl::WaitForTasks();
|
||||
}
|
||||
|
||||
void NzTaskScheduler::AddTaskFunctor(NzFunctor* taskFunctor)
|
||||
{
|
||||
if (!Initialize())
|
||||
bool TaskScheduler::Initialize()
|
||||
{
|
||||
NazaraError("Failed to initialize Task Scheduler");
|
||||
return;
|
||||
return TaskSchedulerImpl::Initialize(GetWorkerCount());
|
||||
}
|
||||
|
||||
s_pendingWorks.push_back(taskFunctor);
|
||||
void TaskScheduler::Run()
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Task Scheduler");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!s_pendingWorks.empty())
|
||||
{
|
||||
TaskSchedulerImpl::Run(&s_pendingWorks[0], s_pendingWorks.size());
|
||||
s_pendingWorks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void TaskScheduler::SetWorkerCount(unsigned int workerCount)
|
||||
{
|
||||
#ifdef NAZARA_CORE_SAFE
|
||||
if (TaskSchedulerImpl::IsInitialized())
|
||||
{
|
||||
NazaraError("Worker count cannot be set while initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
s_workerCount = workerCount;
|
||||
}
|
||||
|
||||
void TaskScheduler::Uninitialize()
|
||||
{
|
||||
if (TaskSchedulerImpl::IsInitialized())
|
||||
TaskSchedulerImpl::Uninitialize();
|
||||
}
|
||||
|
||||
void TaskScheduler::WaitForTasks()
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Task Scheduler");
|
||||
return;
|
||||
}
|
||||
|
||||
TaskSchedulerImpl::WaitForTasks();
|
||||
}
|
||||
|
||||
void TaskScheduler::AddTaskFunctor(Functor* taskFunctor)
|
||||
{
|
||||
if (!Initialize())
|
||||
{
|
||||
NazaraError("Failed to initialize Task Scheduler");
|
||||
return;
|
||||
}
|
||||
|
||||
s_pendingWorks.push_back(taskFunctor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,130 +19,133 @@
|
||||
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzThread::NzThread() :
|
||||
m_impl(nullptr)
|
||||
namespace Nz
|
||||
{
|
||||
}
|
||||
|
||||
NzThread::NzThread(NzThread&& other) :
|
||||
m_impl(other.m_impl)
|
||||
{
|
||||
other.m_impl = nullptr;
|
||||
}
|
||||
|
||||
NzThread::~NzThread()
|
||||
{
|
||||
if (m_impl)
|
||||
Thread::Thread() :
|
||||
m_impl(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
Thread::Thread(Thread&& other) noexcept :
|
||||
m_impl(other.m_impl)
|
||||
{
|
||||
other.m_impl = nullptr;
|
||||
}
|
||||
|
||||
Thread::~Thread()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
m_impl->Join();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Thread::Detach()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
m_impl->Detach();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Thread::Id Thread::GetId() const
|
||||
{
|
||||
return Thread::Id(m_impl);
|
||||
}
|
||||
|
||||
bool Thread::IsJoinable() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
void Thread::Join()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("This thread is not joinable");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->Join();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void NzThread::Detach()
|
||||
{
|
||||
if (m_impl)
|
||||
Thread& Thread::operator=(Thread&& thread)
|
||||
{
|
||||
m_impl->Detach();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (m_impl)
|
||||
{
|
||||
NazaraError("This thread cannot be joined");
|
||||
std::terminate();
|
||||
}
|
||||
#endif
|
||||
|
||||
std::swap(m_impl, thread.m_impl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
unsigned int Thread::HardwareConcurrency()
|
||||
{
|
||||
return HardwareInfo::GetProcessorCount();
|
||||
}
|
||||
|
||||
void Thread::Sleep(UInt32 milliseconds)
|
||||
{
|
||||
ThreadImpl::Sleep(milliseconds);
|
||||
}
|
||||
|
||||
void Thread::CreateImpl(Functor* functor)
|
||||
{
|
||||
m_impl = new ThreadImpl(functor);
|
||||
}
|
||||
|
||||
/*********************************Thread::Id********************************/
|
||||
|
||||
Thread::Id::Id(ThreadImpl* thread) :
|
||||
m_id(thread)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const Thread::Id& lhs, const Thread::Id& rhs)
|
||||
{
|
||||
return lhs.m_id == rhs.m_id;
|
||||
}
|
||||
|
||||
bool operator!=(const Thread::Id& lhs, const Thread::Id& rhs)
|
||||
{
|
||||
return lhs.m_id != rhs.m_id;
|
||||
}
|
||||
|
||||
bool operator<(const Thread::Id& lhs, const Thread::Id& rhs)
|
||||
{
|
||||
return lhs.m_id < rhs.m_id;
|
||||
}
|
||||
|
||||
bool operator<=(const Thread::Id& lhs, const Thread::Id& rhs)
|
||||
{
|
||||
return lhs.m_id <= rhs.m_id;
|
||||
}
|
||||
|
||||
bool operator>(const Thread::Id& lhs, const Thread::Id& rhs)
|
||||
{
|
||||
return lhs.m_id > rhs.m_id;
|
||||
}
|
||||
|
||||
bool operator>=(const Thread::Id& lhs, const Thread::Id& rhs)
|
||||
{
|
||||
return lhs.m_id >= rhs.m_id;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, const Nz::Thread::Id& id)
|
||||
{
|
||||
o << id.m_id;
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
NzThread::Id NzThread::GetId() const
|
||||
{
|
||||
return NzThread::Id(m_impl);
|
||||
}
|
||||
|
||||
bool NzThread::IsJoinable() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
void NzThread::Join()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("This thread is not joinable");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->Join();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
|
||||
NzThread& NzThread::operator=(NzThread&& thread)
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (m_impl)
|
||||
{
|
||||
NazaraError("This thread cannot be joined");
|
||||
std::terminate();
|
||||
}
|
||||
#endif
|
||||
|
||||
std::swap(m_impl, thread.m_impl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
unsigned int NzThread::HardwareConcurrency()
|
||||
{
|
||||
return NzHardwareInfo::GetProcessorCount();
|
||||
}
|
||||
|
||||
void NzThread::Sleep(nzUInt32 milliseconds)
|
||||
{
|
||||
NzThreadImpl::Sleep(milliseconds);
|
||||
}
|
||||
|
||||
void NzThread::CreateImpl(NzFunctor* functor)
|
||||
{
|
||||
m_impl = new NzThreadImpl(functor);
|
||||
}
|
||||
|
||||
/*********************************NzThread::Id********************************/
|
||||
|
||||
bool operator==(const NzThread::Id& lhs, const NzThread::Id& rhs)
|
||||
{
|
||||
return lhs.m_id == rhs.m_id;
|
||||
}
|
||||
|
||||
bool operator!=(const NzThread::Id& lhs, const NzThread::Id& rhs)
|
||||
{
|
||||
return lhs.m_id != rhs.m_id;
|
||||
}
|
||||
|
||||
bool operator<(const NzThread::Id& lhs, const NzThread::Id& rhs)
|
||||
{
|
||||
return lhs.m_id < rhs.m_id;
|
||||
}
|
||||
|
||||
bool operator<=(const NzThread::Id& lhs, const NzThread::Id& rhs)
|
||||
{
|
||||
return lhs.m_id <= rhs.m_id;
|
||||
}
|
||||
|
||||
bool operator>(const NzThread::Id& lhs, const NzThread::Id& rhs)
|
||||
{
|
||||
return lhs.m_id > rhs.m_id;
|
||||
}
|
||||
|
||||
bool operator>=(const NzThread::Id& lhs, const NzThread::Id& rhs)
|
||||
{
|
||||
return lhs.m_id >= rhs.m_id;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& o, const NzThread::Id& id)
|
||||
{
|
||||
o << id.m_id;
|
||||
return o;
|
||||
}
|
||||
|
||||
NzThread::Id::Id(NzThreadImpl* thread) :
|
||||
m_id(thread)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -7,359 +7,366 @@
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
#if NAZARA_CORE_INCLUDE_UNICODEDATA
|
||||
struct Character
|
||||
namespace Nz
|
||||
{
|
||||
nzUInt16 category; // Le type du caractère
|
||||
nzUInt8 direction; // Le sens de lecure du caractère
|
||||
nzUInt32 lowerCase; // Le caractère correspondant en minuscule
|
||||
nzUInt32 titleCase; // Le caractère correspondant en titre
|
||||
nzUInt32 upperCase; // Le caractère correspondant en majuscule
|
||||
};
|
||||
struct Character
|
||||
{
|
||||
UInt16 category; // Le type du caractère
|
||||
UInt8 direction; // Le sens de lecure du caractère
|
||||
UInt32 lowerCase; // Le caractère correspondant en minuscule
|
||||
UInt32 titleCase; // Le caractère correspondant en titre
|
||||
UInt32 upperCase; // Le caractère correspondant en majuscule
|
||||
};
|
||||
}
|
||||
|
||||
#include <Nazara/Core/UnicodeData.hpp>
|
||||
|
||||
#else // Implémentation supportant la table ASCII
|
||||
|
||||
NzUnicode::Category NzUnicode::GetCategory(char32_t character)
|
||||
namespace Nz
|
||||
{
|
||||
switch (character)
|
||||
Unicode::Category Unicode::GetCategory(char32_t character)
|
||||
{
|
||||
case '\x00':
|
||||
case '\x01':
|
||||
case '\x02':
|
||||
case '\x03':
|
||||
case '\x04':
|
||||
case '\x05':
|
||||
case '\x06':
|
||||
case '\x07':
|
||||
case '\x08':
|
||||
case '\x09':
|
||||
case '\x0A':
|
||||
case '\x0B':
|
||||
case '\x0C':
|
||||
case '\x0D':
|
||||
case '\x0E':
|
||||
case '\x0F':
|
||||
case '\x10':
|
||||
case '\x11':
|
||||
case '\x12':
|
||||
case '\x13':
|
||||
case '\x14':
|
||||
case '\x15':
|
||||
case '\x16':
|
||||
case '\x17':
|
||||
case '\x18':
|
||||
case '\x19':
|
||||
case '\x1A':
|
||||
case '\x1B':
|
||||
case '\x1C':
|
||||
case '\x1D':
|
||||
case '\x1E':
|
||||
case '\x1F':
|
||||
case '\x7F':
|
||||
return Category_Other_Control;
|
||||
switch (character)
|
||||
{
|
||||
case '\x00':
|
||||
case '\x01':
|
||||
case '\x02':
|
||||
case '\x03':
|
||||
case '\x04':
|
||||
case '\x05':
|
||||
case '\x06':
|
||||
case '\x07':
|
||||
case '\x08':
|
||||
case '\x09':
|
||||
case '\x0A':
|
||||
case '\x0B':
|
||||
case '\x0C':
|
||||
case '\x0D':
|
||||
case '\x0E':
|
||||
case '\x0F':
|
||||
case '\x10':
|
||||
case '\x11':
|
||||
case '\x12':
|
||||
case '\x13':
|
||||
case '\x14':
|
||||
case '\x15':
|
||||
case '\x16':
|
||||
case '\x17':
|
||||
case '\x18':
|
||||
case '\x19':
|
||||
case '\x1A':
|
||||
case '\x1B':
|
||||
case '\x1C':
|
||||
case '\x1D':
|
||||
case '\x1E':
|
||||
case '\x1F':
|
||||
case '\x7F':
|
||||
return Category_Other_Control;
|
||||
|
||||
case ' ':
|
||||
return Category_Separator_Space;
|
||||
case ' ':
|
||||
return Category_Separator_Space;
|
||||
|
||||
case '!':
|
||||
case '"':
|
||||
case '#':
|
||||
case '$':
|
||||
case '%':
|
||||
case '&':
|
||||
case '\'':
|
||||
case '*':
|
||||
case ',':
|
||||
case '.':
|
||||
case '/':
|
||||
case ':':
|
||||
case ';':
|
||||
case '?':
|
||||
case '@':
|
||||
case '\\':
|
||||
return Category_Punctuation_Other;
|
||||
case '!':
|
||||
case '"':
|
||||
case '#':
|
||||
case '$':
|
||||
case '%':
|
||||
case '&':
|
||||
case '\'':
|
||||
case '*':
|
||||
case ',':
|
||||
case '.':
|
||||
case '/':
|
||||
case ':':
|
||||
case ';':
|
||||
case '?':
|
||||
case '@':
|
||||
case '\\':
|
||||
return Category_Punctuation_Other;
|
||||
|
||||
case '(':
|
||||
case '[':
|
||||
case '{':
|
||||
return Category_Punctuation_Open;
|
||||
case '(':
|
||||
case '[':
|
||||
case '{':
|
||||
return Category_Punctuation_Open;
|
||||
|
||||
case ')':
|
||||
case '}':
|
||||
case ']':
|
||||
return Category_Punctuation_Close;
|
||||
case ')':
|
||||
case '}':
|
||||
case ']':
|
||||
return Category_Punctuation_Close;
|
||||
|
||||
case '+':
|
||||
case '<':
|
||||
case '=':
|
||||
case '>':
|
||||
case '|':
|
||||
case '~':
|
||||
return Category_Symbol_Math;
|
||||
case '+':
|
||||
case '<':
|
||||
case '=':
|
||||
case '>':
|
||||
case '|':
|
||||
case '~':
|
||||
return Category_Symbol_Math;
|
||||
|
||||
case '-':
|
||||
return Category_Punctuation_Dash;
|
||||
case '-':
|
||||
return Category_Punctuation_Dash;
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return Category_Number_DecimalDigit;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return Category_Number_DecimalDigit;
|
||||
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'G':
|
||||
case 'H':
|
||||
case 'I':
|
||||
case 'J':
|
||||
case 'K':
|
||||
case 'L':
|
||||
case 'M':
|
||||
case 'N':
|
||||
case 'O':
|
||||
case 'P':
|
||||
case 'Q':
|
||||
case 'R':
|
||||
case 'S':
|
||||
case 'T':
|
||||
case 'U':
|
||||
case 'V':
|
||||
case 'W':
|
||||
case 'X':
|
||||
case 'Y':
|
||||
case 'Z':
|
||||
return Category_Number_DecimalDigit;
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'G':
|
||||
case 'H':
|
||||
case 'I':
|
||||
case 'J':
|
||||
case 'K':
|
||||
case 'L':
|
||||
case 'M':
|
||||
case 'N':
|
||||
case 'O':
|
||||
case 'P':
|
||||
case 'Q':
|
||||
case 'R':
|
||||
case 'S':
|
||||
case 'T':
|
||||
case 'U':
|
||||
case 'V':
|
||||
case 'W':
|
||||
case 'X':
|
||||
case 'Y':
|
||||
case 'Z':
|
||||
return Category_Number_DecimalDigit;
|
||||
|
||||
case '_':
|
||||
return Category_Punctuation_Connector;
|
||||
case '_':
|
||||
return Category_Punctuation_Connector;
|
||||
|
||||
case '^':
|
||||
case '`':
|
||||
return Category_Symbol_Modifier;
|
||||
case '^':
|
||||
case '`':
|
||||
return Category_Symbol_Modifier;
|
||||
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
return Category_Number_DecimalDigit;
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
return Category_Number_DecimalDigit;
|
||||
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return Category_NoCategory;
|
||||
}
|
||||
|
||||
return Category_NoCategory;
|
||||
}
|
||||
|
||||
NzUnicode::Direction NzUnicode::GetDirection(char32_t character)
|
||||
{
|
||||
switch (character)
|
||||
Unicode::Direction Unicode::GetDirection(char32_t character)
|
||||
{
|
||||
case '\x00':
|
||||
case '\x01':
|
||||
case '\x02':
|
||||
case '\x03':
|
||||
case '\x04':
|
||||
case '\x05':
|
||||
case '\x06':
|
||||
case '\x07':
|
||||
case '\x08':
|
||||
case '\x0E':
|
||||
case '\x0F':
|
||||
case '\x10':
|
||||
case '\x11':
|
||||
case '\x12':
|
||||
case '\x13':
|
||||
case '\x14':
|
||||
case '\x15':
|
||||
case '\x16':
|
||||
case '\x17':
|
||||
case '\x18':
|
||||
case '\x19':
|
||||
case '\x1A':
|
||||
case '\x1B':
|
||||
case '\x7F':
|
||||
return Direction_Boundary_Neutral;
|
||||
switch (character)
|
||||
{
|
||||
case '\x00':
|
||||
case '\x01':
|
||||
case '\x02':
|
||||
case '\x03':
|
||||
case '\x04':
|
||||
case '\x05':
|
||||
case '\x06':
|
||||
case '\x07':
|
||||
case '\x08':
|
||||
case '\x0E':
|
||||
case '\x0F':
|
||||
case '\x10':
|
||||
case '\x11':
|
||||
case '\x12':
|
||||
case '\x13':
|
||||
case '\x14':
|
||||
case '\x15':
|
||||
case '\x16':
|
||||
case '\x17':
|
||||
case '\x18':
|
||||
case '\x19':
|
||||
case '\x1A':
|
||||
case '\x1B':
|
||||
case '\x7F':
|
||||
return Direction_Boundary_Neutral;
|
||||
|
||||
case '\x09':
|
||||
case '\x0B':
|
||||
case '\x1F':
|
||||
return Direction_Segment_Separator;
|
||||
case '\x09':
|
||||
case '\x0B':
|
||||
case '\x1F':
|
||||
return Direction_Segment_Separator;
|
||||
|
||||
case '\x0A':
|
||||
case '\x0D':
|
||||
case '\x1C':
|
||||
case '\x1D':
|
||||
case '\x1E':
|
||||
return Direction_Paragraph_Separator;
|
||||
case '\x0A':
|
||||
case '\x0D':
|
||||
case '\x1C':
|
||||
case '\x1D':
|
||||
case '\x1E':
|
||||
return Direction_Paragraph_Separator;
|
||||
|
||||
case '\x0C':
|
||||
case ' ':
|
||||
return Direction_White_Space;
|
||||
case '\x0C':
|
||||
case ' ':
|
||||
return Direction_White_Space;
|
||||
|
||||
case '!':
|
||||
case '"':
|
||||
case '&':
|
||||
case '\'':
|
||||
case '(':
|
||||
case ')':
|
||||
case '*':
|
||||
case ';':
|
||||
case '<':
|
||||
case '=':
|
||||
case '>':
|
||||
case '?':
|
||||
case '@':
|
||||
case '[':
|
||||
case '\\':
|
||||
case ']':
|
||||
case '^':
|
||||
case '_':
|
||||
case '`':
|
||||
case '{':
|
||||
case '|':
|
||||
case '}':
|
||||
case '~':
|
||||
return Direction_Other_Neutral;
|
||||
case '!':
|
||||
case '"':
|
||||
case '&':
|
||||
case '\'':
|
||||
case '(':
|
||||
case ')':
|
||||
case '*':
|
||||
case ';':
|
||||
case '<':
|
||||
case '=':
|
||||
case '>':
|
||||
case '?':
|
||||
case '@':
|
||||
case '[':
|
||||
case '\\':
|
||||
case ']':
|
||||
case '^':
|
||||
case '_':
|
||||
case '`':
|
||||
case '{':
|
||||
case '|':
|
||||
case '}':
|
||||
case '~':
|
||||
return Direction_Other_Neutral;
|
||||
|
||||
case '#':
|
||||
case '$':
|
||||
case '%':
|
||||
return Direction_European_Terminator;
|
||||
case '#':
|
||||
case '$':
|
||||
case '%':
|
||||
return Direction_European_Terminator;
|
||||
|
||||
case '+':
|
||||
case '-':
|
||||
return Direction_European_Separator;
|
||||
case '+':
|
||||
case '-':
|
||||
return Direction_European_Separator;
|
||||
|
||||
case ',':
|
||||
case '.':
|
||||
case '/':
|
||||
case ':':
|
||||
return Direction_Common_Separator;
|
||||
case ',':
|
||||
case '.':
|
||||
case '/':
|
||||
case ':':
|
||||
return Direction_Common_Separator;
|
||||
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return Direction_European_Number;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return Direction_European_Number;
|
||||
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'G':
|
||||
case 'H':
|
||||
case 'I':
|
||||
case 'J':
|
||||
case 'K':
|
||||
case 'L':
|
||||
case 'M':
|
||||
case 'N':
|
||||
case 'O':
|
||||
case 'P':
|
||||
case 'Q':
|
||||
case 'R':
|
||||
case 'S':
|
||||
case 'T':
|
||||
case 'U':
|
||||
case 'V':
|
||||
case 'W':
|
||||
case 'X':
|
||||
case 'Y':
|
||||
case 'Z':
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
return Direction_Left_To_Right;
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'G':
|
||||
case 'H':
|
||||
case 'I':
|
||||
case 'J':
|
||||
case 'K':
|
||||
case 'L':
|
||||
case 'M':
|
||||
case 'N':
|
||||
case 'O':
|
||||
case 'P':
|
||||
case 'Q':
|
||||
case 'R':
|
||||
case 'S':
|
||||
case 'T':
|
||||
case 'U':
|
||||
case 'V':
|
||||
case 'W':
|
||||
case 'X':
|
||||
case 'Y':
|
||||
case 'Z':
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'h':
|
||||
case 'i':
|
||||
case 'j':
|
||||
case 'k':
|
||||
case 'l':
|
||||
case 'm':
|
||||
case 'n':
|
||||
case 'o':
|
||||
case 'p':
|
||||
case 'q':
|
||||
case 'r':
|
||||
case 's':
|
||||
case 't':
|
||||
case 'u':
|
||||
case 'v':
|
||||
case 'w':
|
||||
case 'x':
|
||||
case 'y':
|
||||
case 'z':
|
||||
return Direction_Left_To_Right;
|
||||
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return Direction_Boundary_Neutral;
|
||||
}
|
||||
|
||||
return Direction_Boundary_Neutral;
|
||||
char32_t Unicode::GetLowercase(char32_t character)
|
||||
{
|
||||
if (character >= 'A' && character <= 'Z')
|
||||
return character + ('a' - 'A');
|
||||
else
|
||||
return character;
|
||||
}
|
||||
|
||||
char32_t Unicode::GetTitlecase(char32_t character)
|
||||
{
|
||||
return GetUppercase(character);
|
||||
}
|
||||
|
||||
char32_t Unicode::GetUppercase(char32_t character)
|
||||
{
|
||||
if (character >= 'a' && character <= 'z')
|
||||
return character + ('A' - 'a');
|
||||
else
|
||||
return character;
|
||||
}
|
||||
}
|
||||
|
||||
char32_t NzUnicode::GetLowercase(char32_t character)
|
||||
{
|
||||
if (character >= 'A' && character <= 'Z')
|
||||
return character + ('a' - 'A');
|
||||
else
|
||||
return character;
|
||||
}
|
||||
|
||||
char32_t NzUnicode::GetTitlecase(char32_t character)
|
||||
{
|
||||
return GetUppercase(character);
|
||||
}
|
||||
|
||||
char32_t NzUnicode::GetUppercase(char32_t character)
|
||||
{
|
||||
if (character >= 'a' && character <= 'z')
|
||||
return character + ('A' - 'a');
|
||||
else
|
||||
return character;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -5,4 +5,7 @@
|
||||
#include <Nazara/Core/Updatable.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzUpdatable::~NzUpdatable() = default;
|
||||
namespace Nz
|
||||
{
|
||||
Updatable::~Updatable() = default;
|
||||
}
|
||||
|
||||
@@ -8,35 +8,38 @@
|
||||
#include <windows.h>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
namespace
|
||||
namespace Nz
|
||||
{
|
||||
LARGE_INTEGER frequency; // La fréquence ne varie pas pas au cours de l'exécution
|
||||
}
|
||||
|
||||
bool NzClockImplInitializeHighPrecision()
|
||||
{
|
||||
return QueryPerformanceFrequency(&frequency) != 0;
|
||||
}
|
||||
|
||||
nzUInt64 NzClockImplGetMicroseconds()
|
||||
{
|
||||
// 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 / frequency.QuadPart;
|
||||
}
|
||||
|
||||
nzUInt64 NzClockImplGetMilliseconds()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS_VISTA
|
||||
return GetTickCount64();
|
||||
#else
|
||||
return GetTickCount();
|
||||
#endif
|
||||
namespace
|
||||
{
|
||||
LARGE_INTEGER s_frequency; // La fréquence ne varie pas pas au cours de l'exécution
|
||||
}
|
||||
|
||||
bool ClockImplInitializeHighPrecision()
|
||||
{
|
||||
return QueryPerformanceFrequency(&s_frequency) != 0;
|
||||
}
|
||||
|
||||
UInt64 ClockImplGetElapsedMicroseconds()
|
||||
{
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
|
||||
bool NzClockImplInitializeHighPrecision();
|
||||
nzUInt64 NzClockImplGetMicroseconds();
|
||||
nzUInt64 NzClockImplGetMilliseconds();
|
||||
namespace Nz
|
||||
{
|
||||
bool ClockImplInitializeHighPrecision();
|
||||
UInt64 ClockImplGetElapsedMicroseconds();
|
||||
UInt64 ClockImplGetElapsedMilliseconds();
|
||||
}
|
||||
|
||||
#endif // NAZARA_CLOCKIMPL_WINDOWS_HPP
|
||||
|
||||
@@ -8,73 +8,77 @@
|
||||
#include <Nazara/Core/Win32/MutexImpl.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzConditionVariableImpl::NzConditionVariableImpl()
|
||||
namespace Nz
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
InitializeConditionVariable(&m_cv);
|
||||
#else
|
||||
m_count = 0;
|
||||
m_events[BROADCAST] = CreateEvent(nullptr, true, false, nullptr); // manual-reset event
|
||||
m_events[SIGNAL] = CreateEvent(nullptr, false, false, nullptr); // auto-reset event
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !NAZARA_CORE_WINDOWS_VISTA
|
||||
NzConditionVariableImpl::~NzConditionVariableImpl()
|
||||
{
|
||||
CloseHandle(m_events[BROADCAST]);
|
||||
CloseHandle(m_events[SIGNAL]);
|
||||
}
|
||||
#endif
|
||||
|
||||
void NzConditionVariableImpl::Signal()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
WakeConditionVariable(&m_cv);
|
||||
#else
|
||||
if (m_count > 0)
|
||||
SetEvent(m_events[SIGNAL]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NzConditionVariableImpl::SignalAll()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
WakeAllConditionVariable(&m_cv);
|
||||
#else
|
||||
if (m_count > 0)
|
||||
SetEvent(m_events[BROADCAST]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NzConditionVariableImpl::Wait(NzMutexImpl* mutex)
|
||||
{
|
||||
Wait(mutex, INFINITE);
|
||||
}
|
||||
|
||||
bool NzConditionVariableImpl::Wait(NzMutexImpl* mutex, nzUInt32 timeout)
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
return SleepConditionVariableCS(&m_cv, &mutex->m_criticalSection, timeout);
|
||||
#else
|
||||
m_count++;
|
||||
|
||||
// It's ok to release the mutex here since Win32
|
||||
// manual-reset events maintain state when used with SetEvent.
|
||||
// This avoids the "lost wakeup" bug...
|
||||
LeaveCriticalSection(&mutex->m_criticalSection);
|
||||
|
||||
// Wait for either event to become signaled due to Signal being called or SignalAll being called.
|
||||
int result = WaitForMultipleObjects(2, m_events, false, timeout);
|
||||
|
||||
// Some thread called SignalAll
|
||||
if (--m_count == 0 && result == WAIT_OBJECT_0 + BROADCAST)
|
||||
// We're the last waiter to be notified or to stop waiting, so reset the manual event.
|
||||
ResetEvent(m_events[BROADCAST]);
|
||||
|
||||
// Reacquire the mutex.
|
||||
EnterCriticalSection(&mutex->m_criticalSection);
|
||||
|
||||
return result != WAIT_TIMEOUT;
|
||||
ConditionVariableImpl::ConditionVariableImpl()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
InitializeConditionVariable(&m_cv);
|
||||
#else
|
||||
m_count = 0;
|
||||
m_events[BROADCAST] = CreateEvent(nullptr, true, false, nullptr); // manual-reset event
|
||||
m_events[SIGNAL] = CreateEvent(nullptr, false, false, nullptr); // auto-reset event
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !NAZARA_CORE_WINDOWS_VISTA
|
||||
ConditionVariableImpl::~ConditionVariableImpl()
|
||||
{
|
||||
CloseHandle(m_events[BROADCAST]);
|
||||
CloseHandle(m_events[SIGNAL]);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ConditionVariableImpl::Signal()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
WakeConditionVariable(&m_cv);
|
||||
#else
|
||||
if (m_count > 0)
|
||||
SetEvent(m_events[SIGNAL]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConditionVariableImpl::SignalAll()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
WakeAllConditionVariable(&m_cv);
|
||||
#else
|
||||
if (m_count > 0)
|
||||
SetEvent(m_events[BROADCAST]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ConditionVariableImpl::Wait(MutexImpl* mutex)
|
||||
{
|
||||
Wait(mutex, INFINITE);
|
||||
}
|
||||
|
||||
bool ConditionVariableImpl::Wait(MutexImpl* mutex, UInt32 timeout)
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
return SleepConditionVariableCS(&m_cv, &mutex->m_criticalSection, timeout);
|
||||
#else
|
||||
m_count++;
|
||||
|
||||
// It's ok to release the mutex here since Win32
|
||||
// manual-reset events maintain state when used with SetEvent.
|
||||
// This avoids the "lost wakeup" bug...
|
||||
LeaveCriticalSection(&mutex->m_criticalSection);
|
||||
|
||||
// Wait for either event to become signaled due to Signal being called or SignalAll being called.
|
||||
int result = WaitForMultipleObjects(2, m_events, false, timeout);
|
||||
|
||||
// Some thread called SignalAll
|
||||
if (--m_count == 0 && result == WAIT_OBJECT_0 + BROADCAST)
|
||||
// We're the last waiter to be notified or to stop waiting, so reset the manual event.
|
||||
ResetEvent(m_events[BROADCAST]);
|
||||
|
||||
// Reacquire the mutex.
|
||||
EnterCriticalSection(&mutex->m_criticalSection);
|
||||
|
||||
return result != WAIT_TIMEOUT;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,39 +13,41 @@
|
||||
#include <atomic>
|
||||
#include <windows.h>
|
||||
|
||||
class NzMutexImpl;
|
||||
|
||||
class NzConditionVariableImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzConditionVariableImpl();
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
~NzConditionVariableImpl() = default;
|
||||
#else
|
||||
~NzConditionVariableImpl();
|
||||
#endif
|
||||
class MutexImpl;
|
||||
|
||||
void Signal();
|
||||
void SignalAll();
|
||||
class ConditionVariableImpl
|
||||
{
|
||||
public:
|
||||
ConditionVariableImpl();
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
~ConditionVariableImpl() = default;
|
||||
#else
|
||||
~ConditionVariableImpl();
|
||||
#endif
|
||||
|
||||
void Wait(NzMutexImpl* mutex);
|
||||
bool Wait(NzMutexImpl* mutex, nzUInt32 timeout);
|
||||
void Signal();
|
||||
void SignalAll();
|
||||
|
||||
private:
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
CONDITION_VARIABLE m_cv;
|
||||
#else
|
||||
enum
|
||||
{
|
||||
SIGNAL,
|
||||
BROADCAST,
|
||||
MAX_EVENTS
|
||||
};
|
||||
void Wait(MutexImpl* mutex);
|
||||
bool Wait(MutexImpl* mutex, UInt32 timeout);
|
||||
|
||||
std::atomic_uint m_count;
|
||||
HANDLE m_events[MAX_EVENTS];
|
||||
#endif
|
||||
private:
|
||||
#if NAZARA_CORE_WINDOWS_VISTA
|
||||
CONDITION_VARIABLE m_cv;
|
||||
#else
|
||||
enum
|
||||
{
|
||||
SIGNAL,
|
||||
BROADCAST,
|
||||
MAX_EVENTS
|
||||
};
|
||||
|
||||
};
|
||||
std::atomic_uint m_count;
|
||||
HANDLE m_events[MAX_EVENTS];
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_CONDITIONVARIABLEIMPL_HPP
|
||||
|
||||
@@ -7,113 +7,116 @@
|
||||
#include <memory>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzDirectoryImpl::NzDirectoryImpl(const NzDirectory* parent)
|
||||
namespace Nz
|
||||
{
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
void NzDirectoryImpl::Close()
|
||||
{
|
||||
FindClose(m_handle);
|
||||
}
|
||||
|
||||
NzString NzDirectoryImpl::GetResultName() const
|
||||
{
|
||||
return NzString::Unicode(m_result.cFileName);
|
||||
}
|
||||
|
||||
nzUInt64 NzDirectoryImpl::GetResultSize() const
|
||||
{
|
||||
LARGE_INTEGER size;
|
||||
size.HighPart = m_result.nFileSizeHigh;
|
||||
size.LowPart = m_result.nFileSizeLow;
|
||||
|
||||
return size.QuadPart;
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::IsResultDirectory() const
|
||||
{
|
||||
if (m_result.dwFileAttributes != INVALID_FILE_ATTRIBUTES)
|
||||
return (m_result.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::NextResult()
|
||||
{
|
||||
if (m_firstCall) // Nous devons ignorer le premier appel car FindFirstFile nous a déjà renvoyé des résultats
|
||||
DirectoryImpl::DirectoryImpl(const Directory* parent)
|
||||
{
|
||||
m_firstCall = false;
|
||||
return true;
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
if (FindNextFileW(m_handle, &m_result))
|
||||
return true;
|
||||
else
|
||||
void DirectoryImpl::Close()
|
||||
{
|
||||
if (GetLastError() != ERROR_NO_MORE_FILES)
|
||||
NazaraError("Unable to get next result: " + NzError::GetLastSystemError());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::Open(const NzString& dirPath)
|
||||
{
|
||||
NzString searchPath = dirPath + "\\*";
|
||||
|
||||
m_handle = FindFirstFileW(searchPath.GetWideString().data(), &m_result);
|
||||
if (m_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
NazaraError("Unable to open directory: " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
FindClose(m_handle);
|
||||
}
|
||||
|
||||
m_firstCall = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::Create(const NzString& dirPath)
|
||||
{
|
||||
return (CreateDirectoryW(dirPath.GetWideString().data(), nullptr) != 0) || GetLastError() == ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::Exists(const NzString& dirPath)
|
||||
{
|
||||
DWORD attributes = GetFileAttributesW(dirPath.GetWideString().data());
|
||||
if (attributes != INVALID_FILE_ATTRIBUTES)
|
||||
return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
NzString NzDirectoryImpl::GetCurrent()
|
||||
{
|
||||
NzString currentPath;
|
||||
std::unique_ptr<wchar_t[]> path(new wchar_t[MAX_PATH]);
|
||||
|
||||
unsigned int size = GetCurrentDirectoryW(MAX_PATH, path.get());
|
||||
if (size > MAX_PATH) // La taille prends en compte le caractère nul
|
||||
String DirectoryImpl::GetResultName() const
|
||||
{
|
||||
path.reset(new wchar_t[size]);
|
||||
if (GetCurrentDirectoryW(size, path.get()) != 0)
|
||||
currentPath = NzString::Unicode(path.get());
|
||||
return String::Unicode(m_result.cFileName);
|
||||
}
|
||||
|
||||
UInt64 DirectoryImpl::GetResultSize() const
|
||||
{
|
||||
LARGE_INTEGER size;
|
||||
size.HighPart = m_result.nFileSizeHigh;
|
||||
size.LowPart = m_result.nFileSizeLow;
|
||||
|
||||
return size.QuadPart;
|
||||
}
|
||||
|
||||
bool DirectoryImpl::IsResultDirectory() const
|
||||
{
|
||||
if (m_result.dwFileAttributes != INVALID_FILE_ATTRIBUTES)
|
||||
return (m_result.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
else
|
||||
NazaraError("Unable to get current directory: " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
else if (size == 0)
|
||||
NazaraError("Unable to get current directory: " + NzError::GetLastSystemError());
|
||||
else
|
||||
currentPath = NzString::Unicode(path.get());
|
||||
|
||||
return currentPath;
|
||||
}
|
||||
|
||||
bool NzDirectoryImpl::Remove(const NzString& dirPath)
|
||||
{
|
||||
bool success = RemoveDirectoryW(dirPath.GetWideString().data()) != 0;
|
||||
|
||||
DWORD error = GetLastError();
|
||||
return success || error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND;
|
||||
bool DirectoryImpl::NextResult()
|
||||
{
|
||||
if (m_firstCall) // Nous devons ignorer le premier appel car FindFirstFile nous a déjà renvoyé des résultats
|
||||
{
|
||||
m_firstCall = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (FindNextFileW(m_handle, &m_result))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
if (GetLastError() != ERROR_NO_MORE_FILES)
|
||||
NazaraError("Unable to get next result: " + Error::GetLastSystemError());
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DirectoryImpl::Open(const String& dirPath)
|
||||
{
|
||||
String searchPath = dirPath + "\\*";
|
||||
|
||||
m_handle = FindFirstFileW(searchPath.GetWideString().data(), &m_result);
|
||||
if (m_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
NazaraError("Unable to open directory: " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_firstCall = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DirectoryImpl::Create(const String& dirPath)
|
||||
{
|
||||
return (CreateDirectoryW(dirPath.GetWideString().data(), nullptr) != 0) || GetLastError() == ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
bool DirectoryImpl::Exists(const String& dirPath)
|
||||
{
|
||||
DWORD attributes = GetFileAttributesW(dirPath.GetWideString().data());
|
||||
if (attributes != INVALID_FILE_ATTRIBUTES)
|
||||
return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
String DirectoryImpl::GetCurrent()
|
||||
{
|
||||
String currentPath;
|
||||
std::unique_ptr<wchar_t[]> path(new wchar_t[MAX_PATH]);
|
||||
|
||||
unsigned int size = GetCurrentDirectoryW(MAX_PATH, path.get());
|
||||
if (size > MAX_PATH) // La taille prends en compte le caractère nul
|
||||
{
|
||||
path.reset(new wchar_t[size]);
|
||||
if (GetCurrentDirectoryW(size, path.get()) != 0)
|
||||
currentPath = String::Unicode(path.get());
|
||||
else
|
||||
NazaraError("Unable to get current directory: " + Error::GetLastSystemError());
|
||||
}
|
||||
else if (size == 0)
|
||||
NazaraError("Unable to get current directory: " + Error::GetLastSystemError());
|
||||
else
|
||||
currentPath = String::Unicode(path.get());
|
||||
|
||||
return currentPath;
|
||||
}
|
||||
|
||||
bool DirectoryImpl::Remove(const String& dirPath)
|
||||
{
|
||||
bool success = RemoveDirectoryW(dirPath.GetWideString().data()) != 0;
|
||||
|
||||
DWORD error = GetLastError();
|
||||
return success || error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,38 +8,45 @@
|
||||
#define NAZARA_DIRECTORYIMPL_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Core/NonCopyable.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
class NzDirectory;
|
||||
class NzString;
|
||||
|
||||
class NzDirectoryImpl : NzNonCopyable
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzDirectoryImpl(const NzDirectory* parent);
|
||||
~NzDirectoryImpl() = default;
|
||||
class Directory;
|
||||
class String;
|
||||
|
||||
void Close();
|
||||
class DirectoryImpl
|
||||
{
|
||||
public:
|
||||
DirectoryImpl(const Directory* parent);
|
||||
DirectoryImpl(const DirectoryImpl&) = delete;
|
||||
DirectoryImpl(DirectoryImpl&&) = delete; ///TODO
|
||||
~DirectoryImpl() = default;
|
||||
|
||||
NzString GetResultName() const;
|
||||
nzUInt64 GetResultSize() const;
|
||||
void Close();
|
||||
|
||||
bool IsResultDirectory() const;
|
||||
String GetResultName() const;
|
||||
UInt64 GetResultSize() const;
|
||||
|
||||
bool NextResult();
|
||||
bool IsResultDirectory() const;
|
||||
|
||||
bool Open(const NzString& dirPath);
|
||||
bool NextResult();
|
||||
|
||||
static bool Create(const NzString& dirPath);
|
||||
static bool Exists(const NzString& dirPath);
|
||||
static NzString GetCurrent();
|
||||
static bool Remove(const NzString& dirPath);
|
||||
bool Open(const String& dirPath);
|
||||
|
||||
private:
|
||||
HANDLE m_handle;
|
||||
WIN32_FIND_DATAW m_result;
|
||||
bool m_firstCall;
|
||||
};
|
||||
DirectoryImpl& operator=(const DirectoryImpl&) = delete;
|
||||
DirectoryImpl& operator=(DirectoryImpl&&) = delete; ///TODO
|
||||
|
||||
static bool Create(const String& dirPath);
|
||||
static bool Exists(const String& dirPath);
|
||||
static String GetCurrent();
|
||||
static bool Remove(const String& dirPath);
|
||||
|
||||
private:
|
||||
HANDLE m_handle;
|
||||
WIN32_FIND_DATAW m_result;
|
||||
bool m_firstCall;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_DIRECTORYIMPL_HPP
|
||||
|
||||
@@ -10,37 +10,41 @@
|
||||
#include <memory>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzDynLibImpl::NzDynLibImpl(NzDynLib* parent)
|
||||
namespace Nz
|
||||
{
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
NzDynLibFunc NzDynLibImpl::GetSymbol(const NzString& symbol, NzString* errorMessage) const
|
||||
{
|
||||
NzDynLibFunc sym = reinterpret_cast<NzDynLibFunc>(GetProcAddress(m_handle, symbol.GetConstBuffer()));
|
||||
if (!sym)
|
||||
*errorMessage = NzError::GetLastSystemError();
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
bool NzDynLibImpl::Load(const NzString& libraryPath, NzString* errorMessage)
|
||||
{
|
||||
NzString path = libraryPath;
|
||||
if (!path.EndsWith(".dll"))
|
||||
path += ".dll";
|
||||
|
||||
m_handle = LoadLibraryExW(path.GetWideString().data(), nullptr, (NzFile::IsAbsolute(path)) ? LOAD_WITH_ALTERED_SEARCH_PATH : 0);
|
||||
if (m_handle)
|
||||
return true;
|
||||
else
|
||||
DynLibImpl::DynLibImpl(DynLib* parent)
|
||||
{
|
||||
*errorMessage = NzError::GetLastSystemError();
|
||||
return false;
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
DynLibFunc DynLibImpl::GetSymbol(const String& symbol, String* errorMessage) const
|
||||
{
|
||||
DynLibFunc sym = reinterpret_cast<DynLibFunc>(GetProcAddress(m_handle, symbol.GetConstBuffer()));
|
||||
if (!sym)
|
||||
*errorMessage = Error::GetLastSystemError();
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
bool DynLibImpl::Load(const String& libraryPath, String* errorMessage)
|
||||
{
|
||||
String path = libraryPath;
|
||||
if (!path.EndsWith(".dll"))
|
||||
path += ".dll";
|
||||
|
||||
m_handle = LoadLibraryExW(path.GetWideString().data(), nullptr, (File::IsAbsolute(path)) ? LOAD_WITH_ALTERED_SEARCH_PATH : 0);
|
||||
if (m_handle)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
*errorMessage = Error::GetLastSystemError();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void DynLibImpl::Unload()
|
||||
{
|
||||
FreeLibrary(m_handle);
|
||||
}
|
||||
}
|
||||
|
||||
void NzDynLibImpl::Unload()
|
||||
{
|
||||
FreeLibrary(m_handle);
|
||||
}
|
||||
|
||||
@@ -9,23 +9,30 @@
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Core/DynLib.hpp>
|
||||
#include <Nazara/Core/NonCopyable.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
class NzString;
|
||||
|
||||
class NzDynLibImpl : NzNonCopyable
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzDynLibImpl(NzDynLib* m_parent);
|
||||
~NzDynLibImpl() = default;
|
||||
class String;
|
||||
|
||||
NzDynLibFunc GetSymbol(const NzString& symbol, NzString* errorMessage) const;
|
||||
bool Load(const NzString& libraryPath, NzString* errorMessage);
|
||||
void Unload();
|
||||
class DynLibImpl
|
||||
{
|
||||
public:
|
||||
DynLibImpl(DynLib* m_parent);
|
||||
DynLibImpl(const DynLibImpl&) = delete;
|
||||
DynLibImpl(DynLibImpl&&) = delete; ///TODO?
|
||||
~DynLibImpl() = default;
|
||||
|
||||
private:
|
||||
HMODULE m_handle;
|
||||
};
|
||||
DynLibFunc GetSymbol(const String& symbol, String* errorMessage) const;
|
||||
bool Load(const String& libraryPath, String* errorMessage);
|
||||
void Unload();
|
||||
|
||||
DynLibImpl& operator=(const DynLibImpl&) = delete;
|
||||
DynLibImpl& operator=(DynLibImpl&&) = delete; ///TODO?
|
||||
|
||||
private:
|
||||
HMODULE m_handle;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_DYNLIBIMPL_HPP
|
||||
|
||||
@@ -8,288 +8,281 @@
|
||||
#include <memory>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzFileImpl::NzFileImpl(const NzFile* parent) :
|
||||
m_endOfFile(false),
|
||||
m_endOfFileUpdated(true)
|
||||
namespace Nz
|
||||
{
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
void NzFileImpl::Close()
|
||||
{
|
||||
CloseHandle(m_handle);
|
||||
}
|
||||
|
||||
bool NzFileImpl::EndOfFile() const
|
||||
{
|
||||
if (!m_endOfFileUpdated)
|
||||
FileImpl::FileImpl(const File* parent) :
|
||||
m_endOfFile(false),
|
||||
m_endOfFileUpdated(true)
|
||||
{
|
||||
LARGE_INTEGER fileSize;
|
||||
if (!GetFileSizeEx(m_handle, &fileSize))
|
||||
fileSize.QuadPart = 0;
|
||||
|
||||
m_endOfFile = (GetCursorPos() >= static_cast<nzUInt64>(fileSize.QuadPart));
|
||||
m_endOfFileUpdated = true;
|
||||
NazaraUnused(parent);
|
||||
}
|
||||
|
||||
return m_endOfFile;
|
||||
}
|
||||
|
||||
void NzFileImpl::Flush()
|
||||
{
|
||||
if (!FlushFileBuffers(m_handle))
|
||||
NazaraError("Unable to flush file: " + NzError::GetLastSystemError());
|
||||
}
|
||||
|
||||
nzUInt64 NzFileImpl::GetCursorPos() const
|
||||
{
|
||||
LARGE_INTEGER zero;
|
||||
zero.QuadPart = 0;
|
||||
|
||||
LARGE_INTEGER position;
|
||||
SetFilePointerEx(m_handle, zero, &position, FILE_CURRENT);
|
||||
|
||||
return position.QuadPart;
|
||||
}
|
||||
|
||||
bool NzFileImpl::Open(const NzString& filePath, unsigned int mode)
|
||||
{
|
||||
DWORD access;
|
||||
DWORD shareMode = FILE_SHARE_READ;
|
||||
DWORD openMode;
|
||||
if (mode & nzOpenMode_ReadOnly)
|
||||
void FileImpl::Close()
|
||||
{
|
||||
access = GENERIC_READ;
|
||||
openMode = OPEN_EXISTING;
|
||||
CloseHandle(m_handle);
|
||||
}
|
||||
else if (mode & nzOpenMode_ReadWrite)
|
||||
|
||||
bool FileImpl::EndOfFile() const
|
||||
{
|
||||
if (mode & nzOpenMode_Append)
|
||||
access = FILE_APPEND_DATA;
|
||||
else
|
||||
access = GENERIC_READ | GENERIC_WRITE;
|
||||
|
||||
if (mode & nzOpenMode_Truncate)
|
||||
openMode = CREATE_ALWAYS;
|
||||
else
|
||||
openMode = OPEN_ALWAYS;
|
||||
}
|
||||
else if (mode & nzOpenMode_WriteOnly)
|
||||
{
|
||||
if (mode & nzOpenMode_Append)
|
||||
access = FILE_APPEND_DATA;
|
||||
else
|
||||
access = GENERIC_WRITE;
|
||||
|
||||
if (mode & nzOpenMode_Truncate)
|
||||
openMode = CREATE_ALWAYS;
|
||||
else
|
||||
openMode = OPEN_ALWAYS;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
if ((mode & nzOpenMode_Lock) == 0)
|
||||
shareMode |= FILE_SHARE_WRITE;
|
||||
|
||||
m_handle = CreateFileW(filePath.GetWideString().data(), access, shareMode, nullptr, openMode, 0, nullptr);
|
||||
return m_handle != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
std::size_t NzFileImpl::Read(void* buffer, std::size_t size)
|
||||
{
|
||||
//nzUInt64 oldCursorPos = GetCursorPos();
|
||||
|
||||
DWORD read = 0;
|
||||
if (ReadFile(m_handle, buffer, size, &read, nullptr))
|
||||
{
|
||||
m_endOfFile = (read != size);
|
||||
m_endOfFileUpdated = true;
|
||||
|
||||
return read;
|
||||
///FIXME: D'après la documentation, read vaut 0 si ReadFile atteint la fin du fichier
|
||||
/// D'après les tests, ce n'est pas le cas, la taille lue est inférieure à la taille en argument, mais pas nulle
|
||||
/// Peut-être ais-je mal compris la documentation
|
||||
/// Le correctif (dans le cas où la doc serait vraie) est commenté en début de fonction et après ce commentaire
|
||||
/// Il est cependant plus lourd, et ne fonctionne pas avec le comportement observé de la fonction
|
||||
/*
|
||||
if (read == 0)
|
||||
if (!m_endOfFileUpdated)
|
||||
{
|
||||
// Si nous atteignons la fin du fichier, la taille lue vaut 0
|
||||
// pour renvoyer le nombre d'octets lus nous comparons la position du curseur
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365690(v=vs.85).aspx
|
||||
m_endOfFile = true;
|
||||
LARGE_INTEGER fileSize;
|
||||
if (!GetFileSizeEx(m_handle, &fileSize))
|
||||
fileSize.QuadPart = 0;
|
||||
|
||||
m_endOfFile = (GetCursorPos() >= static_cast<UInt64>(fileSize.QuadPart));
|
||||
m_endOfFileUpdated = true;
|
||||
}
|
||||
|
||||
return m_endOfFile;
|
||||
}
|
||||
|
||||
void FileImpl::Flush()
|
||||
{
|
||||
if (!FlushFileBuffers(m_handle))
|
||||
NazaraError("Unable to flush file: " + Error::GetLastSystemError());
|
||||
}
|
||||
|
||||
UInt64 FileImpl::GetCursorPos() const
|
||||
{
|
||||
LARGE_INTEGER zero;
|
||||
zero.QuadPart = 0;
|
||||
|
||||
LARGE_INTEGER position;
|
||||
SetFilePointerEx(m_handle, zero, &position, FILE_CURRENT);
|
||||
|
||||
return position.QuadPart;
|
||||
}
|
||||
|
||||
bool FileImpl::Open(const String& filePath, UInt32 mode)
|
||||
{
|
||||
DWORD access = 0;
|
||||
DWORD shareMode = FILE_SHARE_READ;
|
||||
DWORD openMode = 0;
|
||||
|
||||
if (mode & OpenMode_ReadOnly)
|
||||
{
|
||||
access |= GENERIC_READ;
|
||||
|
||||
if ((mode & OpenMode_WriteOnly) == 0)
|
||||
openMode |= OPEN_EXISTING;
|
||||
}
|
||||
|
||||
if (mode & OpenMode_WriteOnly)
|
||||
{
|
||||
if (mode & OpenMode_Append)
|
||||
access |= FILE_APPEND_DATA;
|
||||
else
|
||||
access |= GENERIC_WRITE;
|
||||
|
||||
if (mode & OpenMode_Truncate)
|
||||
openMode |= CREATE_ALWAYS;
|
||||
else
|
||||
openMode |= OPEN_ALWAYS;
|
||||
}
|
||||
|
||||
if ((mode & OpenMode_Lock) == 0)
|
||||
shareMode |= FILE_SHARE_WRITE;
|
||||
|
||||
m_handle = CreateFileW(filePath.GetWideString().data(), access, shareMode, nullptr, openMode, 0, nullptr);
|
||||
return m_handle != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
std::size_t FileImpl::Read(void* buffer, std::size_t size)
|
||||
{
|
||||
//UInt64 oldCursorPos = GetCursorPos();
|
||||
|
||||
DWORD read = 0;
|
||||
if (ReadFile(m_handle, buffer, size, &read, nullptr))
|
||||
{
|
||||
m_endOfFile = (read != size);
|
||||
m_endOfFileUpdated = true;
|
||||
|
||||
return GetCursorPos()-oldCursorPos;
|
||||
return read;
|
||||
///FIXME: D'après la documentation, read vaut 0 si ReadFile atteint la fin du fichier
|
||||
/// D'après les tests, ce n'est pas le cas, la taille lue est inférieure à la taille en argument, mais pas nulle
|
||||
/// Peut-être ais-je mal compris la documentation
|
||||
/// Le correctif (dans le cas où la doc serait vraie) est commenté en début de fonction et après ce commentaire
|
||||
/// Il est cependant plus lourd, et ne fonctionne pas avec le comportement observé de la fonction
|
||||
/*
|
||||
if (read == 0)
|
||||
{
|
||||
// Si nous atteignons la fin du fichier, la taille lue vaut 0
|
||||
// pour renvoyer le nombre d'octets lus nous comparons la position du curseur
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa365690(v=vs.85).aspx
|
||||
m_endOfFile = true;
|
||||
m_endOfFileUpdated = true;
|
||||
|
||||
return GetCursorPos()-oldCursorPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_endOfFileUpdated = false;
|
||||
return read;
|
||||
}
|
||||
*/
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool FileImpl::SetCursorPos(CursorPosition pos, Int64 offset)
|
||||
{
|
||||
DWORD moveMethod;
|
||||
switch (pos)
|
||||
{
|
||||
m_endOfFileUpdated = false;
|
||||
return read;
|
||||
case CursorPosition_AtBegin:
|
||||
moveMethod = FILE_BEGIN;
|
||||
break;
|
||||
|
||||
case CursorPosition_AtCurrent:
|
||||
moveMethod = FILE_CURRENT;
|
||||
break;
|
||||
|
||||
case CursorPosition_AtEnd:
|
||||
moveMethod = FILE_END;
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Cursor position not handled (0x" + String::Number(pos, 16) + ')');
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
LARGE_INTEGER distance;
|
||||
distance.QuadPart = offset;
|
||||
|
||||
m_endOfFileUpdated = false;
|
||||
|
||||
return SetFilePointerEx(m_handle, distance, nullptr, moveMethod) != 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool NzFileImpl::SetCursorPos(nzCursorPosition pos, nzInt64 offset)
|
||||
{
|
||||
DWORD moveMethod;
|
||||
switch (pos)
|
||||
std::size_t FileImpl::Write(const void* buffer, std::size_t size)
|
||||
{
|
||||
case nzCursorPosition_AtBegin:
|
||||
moveMethod = FILE_BEGIN;
|
||||
break;
|
||||
DWORD written = 0;
|
||||
|
||||
case nzCursorPosition_AtCurrent:
|
||||
moveMethod = FILE_CURRENT;
|
||||
break;
|
||||
LARGE_INTEGER cursorPos;
|
||||
cursorPos.QuadPart = GetCursorPos();
|
||||
|
||||
case nzCursorPosition_AtEnd:
|
||||
moveMethod = FILE_END;
|
||||
break;
|
||||
LockFile(m_handle, cursorPos.LowPart, cursorPos.HighPart, size, 0);
|
||||
WriteFile(m_handle, buffer, size, &written, nullptr);
|
||||
UnlockFile(m_handle, cursorPos.LowPart, cursorPos.HighPart, size, 0);
|
||||
|
||||
default:
|
||||
NazaraInternalError("Cursor position not handled (0x" + NzString::Number(pos, 16) + ')');
|
||||
m_endOfFileUpdated = false;
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
bool FileImpl::Copy(const String& sourcePath, const String& targetPath)
|
||||
{
|
||||
if (CopyFileW(sourcePath.GetWideString().data(), targetPath.GetWideString().data(), false))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
NazaraError("Failed to copy file: " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LARGE_INTEGER distance;
|
||||
distance.QuadPart = offset;
|
||||
|
||||
m_endOfFileUpdated = false;
|
||||
|
||||
return SetFilePointerEx(m_handle, distance, nullptr, moveMethod) != 0;
|
||||
}
|
||||
|
||||
std::size_t NzFileImpl::Write(const void* buffer, std::size_t size)
|
||||
{
|
||||
DWORD written = 0;
|
||||
|
||||
LARGE_INTEGER cursorPos;
|
||||
cursorPos.QuadPart = GetCursorPos();
|
||||
|
||||
LockFile(m_handle, cursorPos.LowPart, cursorPos.HighPart, size, 0);
|
||||
WriteFile(m_handle, buffer, size, &written, nullptr);
|
||||
UnlockFile(m_handle, cursorPos.LowPart, cursorPos.HighPart, size, 0);
|
||||
|
||||
m_endOfFileUpdated = false;
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
bool NzFileImpl::Copy(const NzString& sourcePath, const NzString& targetPath)
|
||||
{
|
||||
if (CopyFileW(sourcePath.GetWideString().data(), targetPath.GetWideString().data(), false))
|
||||
return true;
|
||||
else
|
||||
bool FileImpl::Delete(const String& filePath)
|
||||
{
|
||||
NazaraError("Failed to copy file: " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
if (DeleteFileW(filePath.GetWideString().data()))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
NazaraError("Failed to delete file (" + filePath + "): " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NzFileImpl::Delete(const NzString& filePath)
|
||||
{
|
||||
if (DeleteFileW(filePath.GetWideString().data()))
|
||||
return true;
|
||||
else
|
||||
bool FileImpl::Exists(const String& filePath)
|
||||
{
|
||||
NazaraError("Failed to delete file (" + filePath + "): " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
bool NzFileImpl::Exists(const NzString& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
CloseHandle(handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
time_t NzFileImpl::GetCreationTime(const NzString& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
FILETIME creationTime;
|
||||
if (!GetFileTime(handle, &creationTime, nullptr, nullptr))
|
||||
{
|
||||
CloseHandle(handle);
|
||||
|
||||
NazaraError("Unable to get creation time: " + NzError::GetLastSystemError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return NzFileTimeToTime(&creationTime);
|
||||
}
|
||||
|
||||
time_t NzFileImpl::GetLastAccessTime(const NzString& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
FILETIME accessTime;
|
||||
if (!GetFileTime(handle, nullptr, &accessTime, nullptr))
|
||||
{
|
||||
CloseHandle(handle);
|
||||
|
||||
NazaraError("Unable to get last access time: " + NzError::GetLastSystemError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return NzFileTimeToTime(&accessTime);
|
||||
}
|
||||
|
||||
time_t NzFileImpl::GetLastWriteTime(const NzString& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
FILETIME writeTime;
|
||||
if (!GetFileTime(handle, nullptr, nullptr, &writeTime))
|
||||
{
|
||||
CloseHandle(handle);
|
||||
|
||||
NazaraError("Unable to get last write time: " + NzError::GetLastSystemError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return NzFileTimeToTime(&writeTime);
|
||||
}
|
||||
|
||||
nzUInt64 NzFileImpl::GetSize(const NzString& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
LARGE_INTEGER fileSize;
|
||||
if (!GetFileSizeEx(handle, &fileSize))
|
||||
fileSize.QuadPart = 0;
|
||||
|
||||
CloseHandle(handle);
|
||||
return fileSize.QuadPart;
|
||||
}
|
||||
|
||||
bool NzFileImpl::Rename(const NzString& sourcePath, const NzString& targetPath)
|
||||
{
|
||||
if (MoveFileExW(sourcePath.GetWideString().data(), targetPath.GetWideString().data(), MOVEFILE_COPY_ALLOWED))
|
||||
return true;
|
||||
else
|
||||
}
|
||||
|
||||
time_t FileImpl::GetCreationTime(const String& filePath)
|
||||
{
|
||||
NazaraError("Unable to rename file: " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
FILETIME creationTime;
|
||||
if (!GetFileTime(handle, &creationTime, nullptr, nullptr))
|
||||
{
|
||||
CloseHandle(handle);
|
||||
|
||||
NazaraError("Unable to get creation time: " + Error::GetLastSystemError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return FileTimeToTime(&creationTime);
|
||||
}
|
||||
|
||||
time_t FileImpl::GetLastAccessTime(const String& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
FILETIME accessTime;
|
||||
if (!GetFileTime(handle, nullptr, &accessTime, nullptr))
|
||||
{
|
||||
CloseHandle(handle);
|
||||
|
||||
NazaraError("Unable to get last access time: " + Error::GetLastSystemError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return FileTimeToTime(&accessTime);
|
||||
}
|
||||
|
||||
time_t FileImpl::GetLastWriteTime(const String& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
FILETIME writeTime;
|
||||
if (!GetFileTime(handle, nullptr, nullptr, &writeTime))
|
||||
{
|
||||
CloseHandle(handle);
|
||||
|
||||
NazaraError("Unable to get last write time: " + Error::GetLastSystemError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
return FileTimeToTime(&writeTime);
|
||||
}
|
||||
|
||||
UInt64 FileImpl::GetSize(const String& filePath)
|
||||
{
|
||||
HANDLE handle = CreateFileW(filePath.GetWideString().data(), 0, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
LARGE_INTEGER fileSize;
|
||||
if (!GetFileSizeEx(handle, &fileSize))
|
||||
fileSize.QuadPart = 0;
|
||||
|
||||
CloseHandle(handle);
|
||||
return fileSize.QuadPart;
|
||||
}
|
||||
|
||||
bool FileImpl::Rename(const String& sourcePath, const String& targetPath)
|
||||
{
|
||||
if (MoveFileExW(sourcePath.GetWideString().data(), targetPath.GetWideString().data(), MOVEFILE_COPY_ALLOWED))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
NazaraError("Unable to rename file: " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,41 +9,48 @@
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Core/NonCopyable.hpp>
|
||||
#include <ctime>
|
||||
#include <windows.h>
|
||||
|
||||
class NzFile;
|
||||
class NzString;
|
||||
|
||||
class NzFileImpl : NzNonCopyable
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzFileImpl(const NzFile* parent);
|
||||
~NzFileImpl() = default;
|
||||
class File;
|
||||
class String;
|
||||
|
||||
void Close();
|
||||
bool EndOfFile() const;
|
||||
void Flush();
|
||||
nzUInt64 GetCursorPos() const;
|
||||
bool Open(const NzString& filePath, unsigned int mode);
|
||||
std::size_t Read(void* buffer, std::size_t size);
|
||||
bool SetCursorPos(nzCursorPosition pos, nzInt64 offset);
|
||||
std::size_t Write(const void* buffer, std::size_t size);
|
||||
class FileImpl
|
||||
{
|
||||
public:
|
||||
FileImpl(const File* parent);
|
||||
FileImpl(const FileImpl&) = delete;
|
||||
FileImpl(FileImpl&&) = delete; ///TODO
|
||||
~FileImpl() = default;
|
||||
|
||||
static bool Copy(const NzString& sourcePath, const NzString& targetPath);
|
||||
static bool Delete(const NzString& filePath);
|
||||
static bool Exists(const NzString& filePath);
|
||||
static time_t GetCreationTime(const NzString& filePath);
|
||||
static time_t GetLastAccessTime(const NzString& filePath);
|
||||
static time_t GetLastWriteTime(const NzString& filePath);
|
||||
static nzUInt64 GetSize(const NzString& filePath);
|
||||
static bool Rename(const NzString& sourcePath, const NzString& targetPath);
|
||||
void Close();
|
||||
bool EndOfFile() const;
|
||||
void Flush();
|
||||
UInt64 GetCursorPos() const;
|
||||
bool Open(const String& filePath, UInt32 mode);
|
||||
std::size_t Read(void* buffer, std::size_t size);
|
||||
bool SetCursorPos(CursorPosition pos, Int64 offset);
|
||||
std::size_t Write(const void* buffer, std::size_t size);
|
||||
|
||||
private:
|
||||
HANDLE m_handle;
|
||||
mutable bool m_endOfFile;
|
||||
mutable bool m_endOfFileUpdated;
|
||||
};
|
||||
FileImpl& operator=(const FileImpl&) = delete;
|
||||
FileImpl& operator=(FileImpl&&) = delete; ///TODO
|
||||
|
||||
static bool Copy(const String& sourcePath, const String& targetPath);
|
||||
static bool Delete(const String& filePath);
|
||||
static bool Exists(const String& filePath);
|
||||
static time_t GetCreationTime(const String& filePath);
|
||||
static time_t GetLastAccessTime(const String& filePath);
|
||||
static time_t GetLastWriteTime(const String& filePath);
|
||||
static UInt64 GetSize(const String& filePath);
|
||||
static bool Rename(const String& sourcePath, const String& targetPath);
|
||||
|
||||
private:
|
||||
HANDLE m_handle;
|
||||
mutable bool m_endOfFile;
|
||||
mutable bool m_endOfFileUpdated;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_FILEIMPL_HPP
|
||||
|
||||
@@ -12,86 +12,89 @@
|
||||
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
void NzHardwareInfoImpl::Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 registers[4])
|
||||
namespace Nz
|
||||
{
|
||||
#if defined(NAZARA_COMPILER_MSVC)
|
||||
static_assert(sizeof(nzUInt32) == sizeof(int), "Assertion failed");
|
||||
|
||||
// Visual propose une fonction intrinsèque pour le cpuid
|
||||
__cpuidex(reinterpret_cast<int*>(registers), static_cast<int>(functionId), static_cast<int>(subFunctionId));
|
||||
#elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
|
||||
// Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c
|
||||
asm volatile ("cpuid" // Besoin d'être volatile ?
|
||||
: "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) // output
|
||||
: "a" (functionId), "c" (subFunctionId)); // input
|
||||
#else
|
||||
NazaraInternalError("Cpuid has been called although it is not supported");
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int NzHardwareInfoImpl::GetProcessorCount()
|
||||
{
|
||||
// Plus simple (et plus portable) que de passer par le CPUID
|
||||
SYSTEM_INFO infos;
|
||||
GetNativeSystemInfo(&infos);
|
||||
|
||||
return infos.dwNumberOfProcessors;
|
||||
}
|
||||
|
||||
nzUInt64 NzHardwareInfoImpl::GetTotalMemory()
|
||||
{
|
||||
MEMORYSTATUSEX memStatus;
|
||||
memStatus.dwLength = sizeof(memStatus);
|
||||
GlobalMemoryStatusEx(&memStatus);
|
||||
|
||||
return memStatus.ullTotalPhys;
|
||||
}
|
||||
|
||||
bool NzHardwareInfoImpl::IsCpuidSupported()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_x64
|
||||
return true; // Toujours supporté sur un processeur 64 bits
|
||||
#else
|
||||
#if defined(NAZARA_COMPILER_MSVC)
|
||||
int supported;
|
||||
__asm
|
||||
void HardwareInfoImpl::Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 registers[4])
|
||||
{
|
||||
pushfd
|
||||
pop eax
|
||||
mov ecx, eax
|
||||
xor eax, 0x200000
|
||||
push eax
|
||||
popfd
|
||||
pushfd
|
||||
pop eax
|
||||
xor eax, ecx
|
||||
mov supported, eax
|
||||
push ecx
|
||||
popfd
|
||||
};
|
||||
#if defined(NAZARA_COMPILER_MSVC)
|
||||
static_assert(sizeof(UInt32) == sizeof(int), "Assertion failed");
|
||||
|
||||
return supported != 0;
|
||||
// Visual propose une fonction intrinsèque pour le cpuid
|
||||
__cpuidex(reinterpret_cast<int*>(registers), static_cast<int>(functionId), static_cast<int>(subFunctionId));
|
||||
#elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
|
||||
int supported;
|
||||
asm volatile (" pushfl\n"
|
||||
" pop %%eax\n"
|
||||
" mov %%eax, %%ecx\n"
|
||||
" xor $0x200000, %%eax\n"
|
||||
" push %%eax\n"
|
||||
" popfl\n"
|
||||
" pushfl\n"
|
||||
" pop %%eax\n"
|
||||
" xor %%ecx, %%eax\n"
|
||||
" mov %%eax, %0\n"
|
||||
" push %%ecx\n"
|
||||
" popfl"
|
||||
: "=m" (supported) // output
|
||||
: // input
|
||||
: "eax", "ecx", "memory"); // clobbered register
|
||||
|
||||
return supported != 0;
|
||||
// Source: http://stackoverflow.com/questions/1666093/cpuid-implementations-in-c
|
||||
asm volatile ("cpuid" // Besoin d'être volatile ?
|
||||
: "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]) // output
|
||||
: "a" (functionId), "c" (subFunctionId)); // input
|
||||
#else
|
||||
return false;
|
||||
NazaraInternalError("Cpuid has been called although it is not supported");
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int HardwareInfoImpl::GetProcessorCount()
|
||||
{
|
||||
// Plus simple (et plus portable) que de passer par le CPUID
|
||||
SYSTEM_INFO infos;
|
||||
GetNativeSystemInfo(&infos);
|
||||
|
||||
return infos.dwNumberOfProcessors;
|
||||
}
|
||||
|
||||
UInt64 HardwareInfoImpl::GetTotalMemory()
|
||||
{
|
||||
MEMORYSTATUSEX memStatus;
|
||||
memStatus.dwLength = sizeof(memStatus);
|
||||
GlobalMemoryStatusEx(&memStatus);
|
||||
|
||||
return memStatus.ullTotalPhys;
|
||||
}
|
||||
|
||||
bool HardwareInfoImpl::IsCpuidSupported()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_x64
|
||||
return true; // Toujours supporté sur un processeur 64 bits
|
||||
#else
|
||||
#if defined(NAZARA_COMPILER_MSVC)
|
||||
int supported;
|
||||
__asm
|
||||
{
|
||||
pushfd
|
||||
pop eax
|
||||
mov ecx, eax
|
||||
xor eax, 0x200000
|
||||
push eax
|
||||
popfd
|
||||
pushfd
|
||||
pop eax
|
||||
xor eax, ecx
|
||||
mov supported, eax
|
||||
push ecx
|
||||
popfd
|
||||
};
|
||||
|
||||
return supported != 0;
|
||||
#elif defined(NAZARA_COMPILER_CLANG) || defined(NAZARA_COMPILER_GCC) || defined(NAZARA_COMPILER_INTEL)
|
||||
int supported;
|
||||
asm volatile (" pushfl\n"
|
||||
" pop %%eax\n"
|
||||
" mov %%eax, %%ecx\n"
|
||||
" xor $0x200000, %%eax\n"
|
||||
" push %%eax\n"
|
||||
" popfl\n"
|
||||
" pushfl\n"
|
||||
" pop %%eax\n"
|
||||
" xor %%ecx, %%eax\n"
|
||||
" mov %%eax, %0\n"
|
||||
" push %%ecx\n"
|
||||
" popfl"
|
||||
: "=m" (supported) // output
|
||||
: // input
|
||||
: "eax", "ecx", "memory"); // clobbered register
|
||||
|
||||
return supported != 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,13 +9,16 @@
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
|
||||
class NzHardwareInfoImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
static void Cpuid(nzUInt32 functionId, nzUInt32 subFunctionId, nzUInt32 registers[4]);
|
||||
static unsigned int GetProcessorCount();
|
||||
static nzUInt64 GetTotalMemory();
|
||||
static bool IsCpuidSupported();
|
||||
};
|
||||
class HardwareInfoImpl
|
||||
{
|
||||
public:
|
||||
static void Cpuid(UInt32 functionId, UInt32 subFunctionId, UInt32 registers[4]);
|
||||
static unsigned int GetProcessorCount();
|
||||
static UInt64 GetTotalMemory();
|
||||
static bool IsCpuidSupported();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_HARDWAREINFOIMPL_WINDOWS_HPP
|
||||
|
||||
@@ -5,31 +5,34 @@
|
||||
#include <Nazara/Core/Win32/MutexImpl.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzMutexImpl::NzMutexImpl()
|
||||
namespace Nz
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_CS_SPINLOCKS > 0
|
||||
InitializeCriticalSectionAndSpinCount(&m_criticalSection, NAZARA_CORE_WINDOWS_CS_SPINLOCKS);
|
||||
#else
|
||||
InitializeCriticalSection(&m_criticalSection);
|
||||
#endif
|
||||
}
|
||||
MutexImpl::MutexImpl()
|
||||
{
|
||||
#if NAZARA_CORE_WINDOWS_CS_SPINLOCKS > 0
|
||||
InitializeCriticalSectionAndSpinCount(&m_criticalSection, NAZARA_CORE_WINDOWS_CS_SPINLOCKS);
|
||||
#else
|
||||
InitializeCriticalSection(&m_criticalSection);
|
||||
#endif
|
||||
}
|
||||
|
||||
NzMutexImpl::~NzMutexImpl()
|
||||
{
|
||||
DeleteCriticalSection(&m_criticalSection);
|
||||
}
|
||||
MutexImpl::~MutexImpl()
|
||||
{
|
||||
DeleteCriticalSection(&m_criticalSection);
|
||||
}
|
||||
|
||||
void NzMutexImpl::Lock()
|
||||
{
|
||||
EnterCriticalSection(&m_criticalSection);
|
||||
}
|
||||
void MutexImpl::Lock()
|
||||
{
|
||||
EnterCriticalSection(&m_criticalSection);
|
||||
}
|
||||
|
||||
bool NzMutexImpl::TryLock()
|
||||
{
|
||||
return TryEnterCriticalSection(&m_criticalSection) != 0;
|
||||
}
|
||||
bool MutexImpl::TryLock()
|
||||
{
|
||||
return TryEnterCriticalSection(&m_criticalSection) != 0;
|
||||
}
|
||||
|
||||
void NzMutexImpl::Unlock()
|
||||
{
|
||||
LeaveCriticalSection(&m_criticalSection);
|
||||
void MutexImpl::Unlock()
|
||||
{
|
||||
LeaveCriticalSection(&m_criticalSection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,20 +10,23 @@
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
class NzMutexImpl
|
||||
namespace Nz
|
||||
{
|
||||
friend class NzConditionVariableImpl;
|
||||
class MutexImpl
|
||||
{
|
||||
friend class ConditionVariableImpl;
|
||||
|
||||
public:
|
||||
NzMutexImpl();
|
||||
~NzMutexImpl();
|
||||
public:
|
||||
MutexImpl();
|
||||
~MutexImpl();
|
||||
|
||||
void Lock();
|
||||
bool TryLock();
|
||||
void Unlock();
|
||||
void Lock();
|
||||
bool TryLock();
|
||||
void Unlock();
|
||||
|
||||
private:
|
||||
CRITICAL_SECTION m_criticalSection;
|
||||
};
|
||||
private:
|
||||
CRITICAL_SECTION m_criticalSection;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_MUTEXIMPL_HPP
|
||||
|
||||
@@ -8,57 +8,60 @@
|
||||
#include <limits>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzSemaphoreImpl::NzSemaphoreImpl(unsigned int count)
|
||||
namespace Nz
|
||||
{
|
||||
m_semaphore = CreateSemaphoreW(nullptr, count, std::numeric_limits<LONG>::max(), nullptr);
|
||||
if (!m_semaphore)
|
||||
NazaraError("Failed to create semaphore: " + NzError::GetLastSystemError());
|
||||
}
|
||||
|
||||
NzSemaphoreImpl::~NzSemaphoreImpl()
|
||||
{
|
||||
CloseHandle(m_semaphore);
|
||||
}
|
||||
|
||||
unsigned int NzSemaphoreImpl::GetCount() const
|
||||
{
|
||||
LONG count;
|
||||
ReleaseSemaphore(m_semaphore, 0, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
void NzSemaphoreImpl::Post()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!ReleaseSemaphore(m_semaphore, 1, nullptr))
|
||||
NazaraError("Failed to release semaphore: " + NzError::GetLastSystemError());
|
||||
#else
|
||||
ReleaseSemaphore(m_semaphore, 1, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NzSemaphoreImpl::Wait()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (WaitForSingleObject(m_semaphore, INFINITE) == WAIT_FAILED)
|
||||
NazaraError("Failed to wait for semaphore: " + NzError::GetLastSystemError());
|
||||
#else
|
||||
WaitForSingleObject(m_semaphore, INFINITE);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool NzSemaphoreImpl::Wait(nzUInt32 timeout)
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
DWORD result = WaitForSingleObject(m_semaphore, timeout);
|
||||
if (result == WAIT_FAILED)
|
||||
SemaphoreImpl::SemaphoreImpl(unsigned int count)
|
||||
{
|
||||
NazaraError("Failed to wait for semaphore: " + NzError::GetLastSystemError());
|
||||
return false;
|
||||
m_semaphore = CreateSemaphoreW(nullptr, count, std::numeric_limits<LONG>::max(), nullptr);
|
||||
if (!m_semaphore)
|
||||
NazaraError("Failed to create semaphore: " + Error::GetLastSystemError());
|
||||
}
|
||||
|
||||
SemaphoreImpl::~SemaphoreImpl()
|
||||
{
|
||||
CloseHandle(m_semaphore);
|
||||
}
|
||||
|
||||
unsigned int SemaphoreImpl::GetCount() const
|
||||
{
|
||||
LONG count;
|
||||
ReleaseSemaphore(m_semaphore, 0, &count);
|
||||
return count;
|
||||
}
|
||||
|
||||
void SemaphoreImpl::Post()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (!ReleaseSemaphore(m_semaphore, 1, nullptr))
|
||||
NazaraError("Failed to release semaphore: " + Error::GetLastSystemError());
|
||||
#else
|
||||
ReleaseSemaphore(m_semaphore, 1, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SemaphoreImpl::Wait()
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (WaitForSingleObject(m_semaphore, INFINITE) == WAIT_FAILED)
|
||||
NazaraError("Failed to wait for semaphore: " + Error::GetLastSystemError());
|
||||
#else
|
||||
WaitForSingleObject(m_semaphore, INFINITE);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SemaphoreImpl::Wait(UInt32 timeout)
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
DWORD result = WaitForSingleObject(m_semaphore, timeout);
|
||||
if (result == WAIT_FAILED)
|
||||
{
|
||||
NazaraError("Failed to wait for semaphore: " + Error::GetLastSystemError());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return result == WAIT_OBJECT_0;
|
||||
#else
|
||||
return WaitForSingleObject(m_semaphore, timeout) == WAIT_OBJECT_0;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
return result == WAIT_OBJECT_0;
|
||||
#else
|
||||
return WaitForSingleObject(m_semaphore, timeout) == WAIT_OBJECT_0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -10,19 +10,22 @@
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <windows.h>
|
||||
|
||||
class NzSemaphoreImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzSemaphoreImpl(unsigned int count);
|
||||
~NzSemaphoreImpl();
|
||||
class SemaphoreImpl
|
||||
{
|
||||
public:
|
||||
SemaphoreImpl(unsigned int count);
|
||||
~SemaphoreImpl();
|
||||
|
||||
unsigned int GetCount() const;
|
||||
void Post();
|
||||
void Wait();
|
||||
bool Wait(nzUInt32 timeout);
|
||||
unsigned int GetCount() const;
|
||||
void Post();
|
||||
void Wait();
|
||||
bool Wait(UInt32 timeout);
|
||||
|
||||
private:
|
||||
HANDLE m_semaphore;
|
||||
};
|
||||
private:
|
||||
HANDLE m_semaphore;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_SEMAPHOREIMPL_HPP
|
||||
|
||||
@@ -9,237 +9,240 @@
|
||||
#include <process.h>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
bool NzTaskSchedulerImpl::Initialize(unsigned int workerCount)
|
||||
namespace Nz
|
||||
{
|
||||
if (IsInitialized())
|
||||
return true; // Déjà initialisé
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (workerCount == 0)
|
||||
bool TaskSchedulerImpl::Initialize(std::size_t workerCount)
|
||||
{
|
||||
NazaraError("Invalid worker count ! (0)");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
if (IsInitialized())
|
||||
return true; // Déjà initialisé
|
||||
|
||||
s_workerCount = workerCount;
|
||||
s_doneEvents.reset(new HANDLE[workerCount]);
|
||||
s_workers.reset(new Worker[workerCount]);
|
||||
s_workerThreads.reset(new HANDLE[workerCount]);
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (workerCount == 0)
|
||||
{
|
||||
NazaraError("Invalid worker count ! (0)");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// L'identifiant de chaque worker doit rester en vie jusqu'à ce que chaque thread soit correctement lancé
|
||||
std::unique_ptr<unsigned int[]> workerIDs(new unsigned int[workerCount]);
|
||||
s_workerCount = workerCount;
|
||||
s_doneEvents.reset(new HANDLE[workerCount]);
|
||||
s_workers.reset(new Worker[workerCount]);
|
||||
s_workerThreads.reset(new HANDLE[workerCount]);
|
||||
|
||||
for (unsigned int i = 0; i < workerCount; ++i)
|
||||
{
|
||||
// On initialise les évènements, mutex et threads de chaque worker
|
||||
Worker& worker = s_workers[i];
|
||||
InitializeCriticalSection(&worker.queueMutex);
|
||||
worker.wakeEvent = CreateEventW(nullptr, false, false, nullptr);
|
||||
worker.running = true;
|
||||
worker.workCount = 0;
|
||||
// L'identifiant de chaque worker doit rester en vie jusqu'à ce que chaque thread soit correctement lancé
|
||||
std::unique_ptr<std::size_t[]> workerIDs(new std::size_t[workerCount]);
|
||||
|
||||
s_doneEvents[i] = CreateEventW(nullptr, true, false, nullptr);
|
||||
for (std::size_t i = 0; i < workerCount; ++i)
|
||||
{
|
||||
// On initialise les évènements, mutex et threads de chaque worker
|
||||
Worker& worker = s_workers[i];
|
||||
InitializeCriticalSection(&worker.queueMutex);
|
||||
worker.wakeEvent = CreateEventW(nullptr, false, false, nullptr);
|
||||
worker.running = true;
|
||||
worker.workCount = 0;
|
||||
|
||||
// Le thread va se lancer, signaler qu'il est prêt à travailler (s_doneEvents) et attendre d'être réveillé
|
||||
workerIDs[i] = i;
|
||||
s_workerThreads[i] = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &WorkerProc, &workerIDs[i], 0, nullptr));
|
||||
s_doneEvents[i] = CreateEventW(nullptr, true, false, nullptr);
|
||||
|
||||
// Le thread va se lancer, signaler qu'il est prêt à travailler (s_doneEvents) et attendre d'être réveillé
|
||||
workerIDs[i] = i;
|
||||
s_workerThreads[i] = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &WorkerProc, &workerIDs[i], 0, nullptr));
|
||||
}
|
||||
|
||||
// On attend que les workers se mettent en attente
|
||||
WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// On attend que les workers se mettent en attente
|
||||
WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzTaskSchedulerImpl::IsInitialized()
|
||||
{
|
||||
return s_workerCount > 0;
|
||||
}
|
||||
|
||||
void NzTaskSchedulerImpl::Run(NzFunctor** tasks, unsigned int count)
|
||||
{
|
||||
// On s'assure que des tâches ne sont pas déjà en cours
|
||||
WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);
|
||||
|
||||
std::ldiv_t div = std::ldiv(count, s_workerCount); // Division et modulo en une opération, y'a pas de petit profit
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
bool TaskSchedulerImpl::IsInitialized()
|
||||
{
|
||||
// On va maintenant répartir les tâches entre chaque worker et les envoyer dans la queue de chacun
|
||||
Worker& worker = s_workers[i];
|
||||
unsigned int taskCount = (i == 0) ? div.quot + div.rem : div.quot;
|
||||
for (unsigned int j = 0; j < taskCount; ++j)
|
||||
worker.queue.push(*tasks++);
|
||||
|
||||
// On stocke le nombre de tâches à côté dans un entier atomique pour éviter d'entrer inutilement dans une section critique
|
||||
worker.workCount = taskCount;
|
||||
return s_workerCount > 0;
|
||||
}
|
||||
|
||||
// On les lance une fois qu'ils sont tous initialisés (pour éviter qu'un worker ne passe en pause détectant une absence de travaux)
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
void TaskSchedulerImpl::Run(Functor** tasks, std::size_t count)
|
||||
{
|
||||
ResetEvent(s_doneEvents[i]);
|
||||
SetEvent(s_workers[i].wakeEvent);
|
||||
}
|
||||
}
|
||||
// On s'assure que des tâches ne sont pas déjà en cours
|
||||
WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);
|
||||
|
||||
void NzTaskSchedulerImpl::Uninitialize()
|
||||
{
|
||||
#ifdef NAZARA_CORE_SAFE
|
||||
if (s_workerCount == 0)
|
||||
{
|
||||
NazaraError("Task scheduler is not initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
std::ldiv_t div = std::ldiv(count, s_workerCount); // Division et modulo en une opération, y'a pas de petit profit
|
||||
for (std::size_t i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
// On va maintenant répartir les tâches entre chaque worker et les envoyer dans la queue de chacun
|
||||
Worker& worker = s_workers[i];
|
||||
std::size_t taskCount = (i == 0) ? div.quot + div.rem : div.quot;
|
||||
for (std::size_t j = 0; j < taskCount; ++j)
|
||||
worker.queue.push(*tasks++);
|
||||
|
||||
// On commence par vider la queue de chaque worker pour s'assurer qu'ils s'arrêtent
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
Worker& worker = s_workers[i];
|
||||
worker.running = false;
|
||||
worker.workCount = 0;
|
||||
// On stocke le nombre de tâches à côté dans un entier atomique pour éviter d'entrer inutilement dans une section critique
|
||||
worker.workCount = taskCount;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&worker.queueMutex);
|
||||
|
||||
std::queue<NzFunctor*> emptyQueue;
|
||||
std::swap(worker.queue, emptyQueue); // Et on vide la queue (merci std::swap)
|
||||
|
||||
LeaveCriticalSection(&worker.queueMutex);
|
||||
|
||||
// On réveille le worker pour qu'il sorte de la boucle et termine le thread
|
||||
SetEvent(worker.wakeEvent);
|
||||
}
|
||||
|
||||
// On attend que chaque thread se termine
|
||||
WaitForMultipleObjects(s_workerCount, &s_workerThreads[0], true, INFINITE);
|
||||
|
||||
// Et on libère les ressources
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
Worker& worker = s_workers[i];
|
||||
CloseHandle(s_doneEvents[i]);
|
||||
CloseHandle(s_workerThreads[i]);
|
||||
CloseHandle(worker.wakeEvent);
|
||||
DeleteCriticalSection(&worker.queueMutex);
|
||||
}
|
||||
|
||||
s_doneEvents.reset();
|
||||
s_workers.reset();
|
||||
s_workerThreads.reset();
|
||||
s_workerCount = 0;
|
||||
}
|
||||
|
||||
void NzTaskSchedulerImpl::WaitForTasks()
|
||||
{
|
||||
#ifdef NAZARA_CORE_SAFE
|
||||
if (s_workerCount == 0)
|
||||
{
|
||||
NazaraError("Task scheduler is not initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);
|
||||
}
|
||||
|
||||
NzFunctor* NzTaskSchedulerImpl::StealTask(unsigned int workerID)
|
||||
{
|
||||
bool shouldRetry;
|
||||
do
|
||||
{
|
||||
shouldRetry = false;
|
||||
// On les lance une fois qu'ils sont tous initialisés (pour éviter qu'un worker ne passe en pause détectant une absence de travaux)
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
// On ne vole pas la famille, ni soi-même.
|
||||
if (i == workerID)
|
||||
continue;
|
||||
|
||||
Worker& worker = s_workers[i];
|
||||
|
||||
// Ce worker a-t-il encore des tâches dans sa file d'attente ?
|
||||
if (worker.workCount > 0)
|
||||
{
|
||||
NzFunctor* task = nullptr;
|
||||
|
||||
// Est-ce qu'il utilise la queue maintenant ?
|
||||
if (TryEnterCriticalSection(&worker.queueMutex))
|
||||
{
|
||||
// Non, super ! Profitons-en pour essayer de lui voler un job
|
||||
if (!worker.queue.empty()) // On vérifie que la queue n'est pas vide (peut avoir changé avant le verrouillage)
|
||||
{
|
||||
// Et hop, on vole la tâche
|
||||
task = worker.queue.front();
|
||||
worker.queue.pop();
|
||||
worker.workCount = worker.queue.size();
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&worker.queueMutex);
|
||||
}
|
||||
else
|
||||
shouldRetry = true; // Il est encore possible d'avoir un job
|
||||
|
||||
// Avons-nous notre tâche ?
|
||||
if (task)
|
||||
return task; // Parfait, sortons de là !
|
||||
}
|
||||
ResetEvent(s_doneEvents[i]);
|
||||
SetEvent(s_workers[i].wakeEvent);
|
||||
}
|
||||
}
|
||||
while (shouldRetry);
|
||||
|
||||
// Bon à priori plus aucun worker n'a de tâche
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned int __stdcall NzTaskSchedulerImpl::WorkerProc(void* userdata)
|
||||
{
|
||||
unsigned int workerID = *reinterpret_cast<unsigned int*>(userdata);
|
||||
SetEvent(s_doneEvents[workerID]);
|
||||
|
||||
Worker& worker = s_workers[workerID];
|
||||
WaitForSingleObject(worker.wakeEvent, INFINITE);
|
||||
|
||||
while (worker.running)
|
||||
void TaskSchedulerImpl::Uninitialize()
|
||||
{
|
||||
NzFunctor* task = nullptr;
|
||||
|
||||
if (worker.workCount > 0) // Permet d'éviter d'entrer inutilement dans une section critique
|
||||
#ifdef NAZARA_CORE_SAFE
|
||||
if (s_workerCount == 0)
|
||||
{
|
||||
NazaraError("Task scheduler is not initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// On commence par vider la queue de chaque worker pour s'assurer qu'ils s'arrêtent
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
Worker& worker = s_workers[i];
|
||||
worker.running = false;
|
||||
worker.workCount = 0;
|
||||
|
||||
EnterCriticalSection(&worker.queueMutex);
|
||||
if (!worker.queue.empty()) // Nécessaire car le workCount peut être tombé à zéro juste avant l'entrée dans la section critique
|
||||
{
|
||||
task = worker.queue.front();
|
||||
worker.queue.pop();
|
||||
worker.workCount = worker.queue.size();
|
||||
}
|
||||
|
||||
std::queue<Functor*> emptyQueue;
|
||||
std::swap(worker.queue, emptyQueue); // Et on vide la queue (merci std::swap)
|
||||
|
||||
LeaveCriticalSection(&worker.queueMutex);
|
||||
|
||||
// On réveille le worker pour qu'il sorte de la boucle et termine le thread
|
||||
SetEvent(worker.wakeEvent);
|
||||
}
|
||||
|
||||
// Que faire quand vous n'avez plus de travail ?
|
||||
if (!task)
|
||||
task = StealTask(workerID); // Voler le travail des autres !
|
||||
// On attend que chaque thread se termine
|
||||
WaitForMultipleObjects(s_workerCount, &s_workerThreads[0], true, INFINITE);
|
||||
|
||||
if (task)
|
||||
// Et on libère les ressources
|
||||
for (unsigned int i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
// On exécute la tâche avant de la supprimer
|
||||
task->Run();
|
||||
delete task;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetEvent(s_doneEvents[workerID]);
|
||||
WaitForSingleObject(worker.wakeEvent, INFINITE);
|
||||
Worker& worker = s_workers[i];
|
||||
CloseHandle(s_doneEvents[i]);
|
||||
CloseHandle(s_workerThreads[i]);
|
||||
CloseHandle(worker.wakeEvent);
|
||||
DeleteCriticalSection(&worker.queueMutex);
|
||||
}
|
||||
|
||||
s_doneEvents.reset();
|
||||
s_workers.reset();
|
||||
s_workerThreads.reset();
|
||||
s_workerCount = 0;
|
||||
}
|
||||
|
||||
// Au cas où un thread attendrait sur WaitForTasks() pendant qu'un autre appellerait Uninitialize()
|
||||
// Ça ne devrait pas arriver, mais comme ça ne coûte pas grand chose..
|
||||
SetEvent(s_doneEvents[workerID]);
|
||||
void TaskSchedulerImpl::WaitForTasks()
|
||||
{
|
||||
#ifdef NAZARA_CORE_SAFE
|
||||
if (s_workerCount == 0)
|
||||
{
|
||||
NazaraError("Task scheduler is not initialized");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
WaitForMultipleObjects(s_workerCount, &s_doneEvents[0], true, INFINITE);
|
||||
}
|
||||
|
||||
Functor* TaskSchedulerImpl::StealTask(std::size_t workerID)
|
||||
{
|
||||
bool shouldRetry;
|
||||
do
|
||||
{
|
||||
shouldRetry = false;
|
||||
for (std::size_t i = 0; i < s_workerCount; ++i)
|
||||
{
|
||||
// On ne vole pas la famille, ni soi-même.
|
||||
if (i == workerID)
|
||||
continue;
|
||||
|
||||
Worker& worker = s_workers[i];
|
||||
|
||||
// Ce worker a-t-il encore des tâches dans sa file d'attente ?
|
||||
if (worker.workCount > 0)
|
||||
{
|
||||
Functor* task = nullptr;
|
||||
|
||||
// Est-ce qu'il utilise la queue maintenant ?
|
||||
if (TryEnterCriticalSection(&worker.queueMutex))
|
||||
{
|
||||
// Non, super ! Profitons-en pour essayer de lui voler un job
|
||||
if (!worker.queue.empty()) // On vérifie que la queue n'est pas vide (peut avoir changé avant le verrouillage)
|
||||
{
|
||||
// Et hop, on vole la tâche
|
||||
task = worker.queue.front();
|
||||
worker.queue.pop();
|
||||
worker.workCount = worker.queue.size();
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&worker.queueMutex);
|
||||
}
|
||||
else
|
||||
shouldRetry = true; // Il est encore possible d'avoir un job
|
||||
|
||||
// Avons-nous notre tâche ?
|
||||
if (task)
|
||||
return task; // Parfait, sortons de là !
|
||||
}
|
||||
}
|
||||
}
|
||||
while (shouldRetry);
|
||||
|
||||
// Bon à priori plus aucun worker n'a de tâche
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned int __stdcall TaskSchedulerImpl::WorkerProc(void* userdata)
|
||||
{
|
||||
unsigned int workerID = *reinterpret_cast<unsigned int*>(userdata);
|
||||
SetEvent(s_doneEvents[workerID]);
|
||||
|
||||
Worker& worker = s_workers[workerID];
|
||||
WaitForSingleObject(worker.wakeEvent, INFINITE);
|
||||
|
||||
while (worker.running)
|
||||
{
|
||||
Functor* task = nullptr;
|
||||
|
||||
if (worker.workCount > 0) // Permet d'éviter d'entrer inutilement dans une section critique
|
||||
{
|
||||
EnterCriticalSection(&worker.queueMutex);
|
||||
if (!worker.queue.empty()) // Nécessaire car le workCount peut être tombé à zéro juste avant l'entrée dans la section critique
|
||||
{
|
||||
task = worker.queue.front();
|
||||
worker.queue.pop();
|
||||
worker.workCount = worker.queue.size();
|
||||
}
|
||||
LeaveCriticalSection(&worker.queueMutex);
|
||||
}
|
||||
|
||||
// Que faire quand vous n'avez plus de travail ?
|
||||
if (!task)
|
||||
task = StealTask(workerID); // Voler le travail des autres !
|
||||
|
||||
if (task)
|
||||
{
|
||||
// On exécute la tâche avant de la supprimer
|
||||
task->Run();
|
||||
delete task;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetEvent(s_doneEvents[workerID]);
|
||||
WaitForSingleObject(worker.wakeEvent, INFINITE);
|
||||
}
|
||||
}
|
||||
|
||||
// Au cas où un thread attendrait sur WaitForTasks() pendant qu'un autre appellerait Uninitialize()
|
||||
// Ça ne devrait pas arriver, mais comme ça ne coûte pas grand chose..
|
||||
SetEvent(s_doneEvents[workerID]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::unique_ptr<HANDLE[]> TaskSchedulerImpl::s_doneEvents; // Doivent être contigus
|
||||
std::unique_ptr<TaskSchedulerImpl::Worker[]> TaskSchedulerImpl::s_workers;
|
||||
std::unique_ptr<HANDLE[]> TaskSchedulerImpl::s_workerThreads; // Doivent être contigus
|
||||
std::size_t TaskSchedulerImpl::s_workerCount;
|
||||
}
|
||||
|
||||
std::unique_ptr<HANDLE[]> NzTaskSchedulerImpl::s_doneEvents; // Doivent être contigus
|
||||
std::unique_ptr<NzTaskSchedulerImpl::Worker[]> NzTaskSchedulerImpl::s_workers;
|
||||
std::unique_ptr<HANDLE[]> NzTaskSchedulerImpl::s_workerThreads; // Doivent être contigus
|
||||
unsigned int NzTaskSchedulerImpl::s_workerCount;
|
||||
|
||||
@@ -14,35 +14,38 @@
|
||||
#include <queue>
|
||||
#include <windows.h>
|
||||
|
||||
class NzTaskSchedulerImpl
|
||||
namespace Nz
|
||||
{
|
||||
public:
|
||||
NzTaskSchedulerImpl() = delete;
|
||||
~NzTaskSchedulerImpl() = delete;
|
||||
class TaskSchedulerImpl
|
||||
{
|
||||
public:
|
||||
TaskSchedulerImpl() = delete;
|
||||
~TaskSchedulerImpl() = delete;
|
||||
|
||||
static bool Initialize(unsigned int workerCount);
|
||||
static bool IsInitialized();
|
||||
static void Run(NzFunctor** tasks, unsigned int count);
|
||||
static void Uninitialize();
|
||||
static void WaitForTasks();
|
||||
static bool Initialize(std::size_t workerCount);
|
||||
static bool IsInitialized();
|
||||
static void Run(Functor** tasks, std::size_t count);
|
||||
static void Uninitialize();
|
||||
static void WaitForTasks();
|
||||
|
||||
private:
|
||||
static NzFunctor* StealTask(unsigned int workerID);
|
||||
static unsigned int __stdcall WorkerProc(void* userdata);
|
||||
private:
|
||||
static Functor* StealTask(std::size_t workerID);
|
||||
static unsigned int __stdcall WorkerProc(void* userdata);
|
||||
|
||||
struct Worker
|
||||
{
|
||||
std::atomic_uint workCount;
|
||||
std::queue<NzFunctor*> queue;
|
||||
CRITICAL_SECTION queueMutex;
|
||||
HANDLE wakeEvent;
|
||||
volatile bool running;
|
||||
};
|
||||
struct Worker
|
||||
{
|
||||
std::atomic_size_t workCount;
|
||||
std::queue<Functor*> queue;
|
||||
CRITICAL_SECTION queueMutex;
|
||||
HANDLE wakeEvent;
|
||||
volatile bool running;
|
||||
};
|
||||
|
||||
static std::unique_ptr<HANDLE[]> s_doneEvents; // Doivent être contigus
|
||||
static std::unique_ptr<Worker[]> s_workers;
|
||||
static std::unique_ptr<HANDLE[]> s_workerThreads; // Doivent être contigus
|
||||
static unsigned int s_workerCount;
|
||||
static std::unique_ptr<HANDLE[]> s_doneEvents; // Doivent être contigus
|
||||
static std::unique_ptr<Worker[]> s_workers;
|
||||
static std::unique_ptr<HANDLE[]> s_workerThreads; // Doivent être contigus
|
||||
static std::size_t s_workerCount;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NAZARA_TASKSCHEDULERIMPL_HPP
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user