Merge branch 'master' into NDK-ShadowMapping

Former-commit-id: 83435ab51753299b30a102871fbcd5558d2ac4f1
This commit is contained in:
Lynix
2015-12-09 00:59:07 +01:00
751 changed files with 79400 additions and 71735 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -4,4 +4,7 @@
#include <Nazara/Audio/SoundStream.hpp>
NzSoundStream::~NzSoundStream() = default;
namespace Nz
{
SoundStream::~SoundStream() = default;
}

View File

@@ -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>();
}
}

View 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 << ')';
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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 &currentFile[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;
}
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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

View 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(&currentTime));
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();
}
}

View File

@@ -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();
}
}

View File

@@ -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, &registers[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, &registers[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;
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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 */

View File

@@ -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";
}
}

View File

@@ -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";
}
}

View File

@@ -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";
}
}

View File

@@ -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";
}
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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();
}
}

View File

@@ -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(&currentTime));
}
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;
}

View File

@@ -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(&currentTime));
}
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(&currentTime));
}
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);
}
}

View File

@@ -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;
}

View 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;
}
}

View File

@@ -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();
}
}

View File

@@ -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>(&parameter.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>(&parameter.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(&parameter, &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>(&parameter.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>(&parameter.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>(&parameter.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(&parameter, &it->second, sizeof(Parameter));
break;
case ParameterType_String:
parameter.type = ParameterType_String;
PlacementNew<String>(&parameter.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;
}
}
}

View File

@@ -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;
}

View File

@@ -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));
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View 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);
}
}

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -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);
}
}

View File

@@ -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)
{
}

View File

@@ -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

View File

@@ -5,4 +5,7 @@
#include <Nazara/Core/Updatable.hpp>
#include <Nazara/Core/Debug.hpp>
NzUpdatable::~NzUpdatable() = default;
namespace Nz
{
Updatable::~Updatable() = default;
}

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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