Merge branch 'NDK-Refactor' into NDK

Conflicts:
	examples/HardwareInfo/main.cpp
	include/Nazara/Renderer/Enums.hpp
	include/Nazara/Renderer/GpuQuery.hpp
	include/Nazara/Renderer/OpenGL.hpp
	include/Nazara/Renderer/RenderBuffer.hpp
	include/Nazara/Renderer/RenderTexture.hpp
	include/Nazara/Renderer/Texture.hpp
	src/Nazara/Graphics/AbstractRenderTechnique.cpp
	src/Nazara/Graphics/DeferredRenderTechnique.cpp
	src/Nazara/Graphics/Material.cpp
	src/Nazara/Graphics/SkyboxBackground.cpp
	src/Nazara/Renderer/GpuQuery.cpp
	src/Nazara/Renderer/OpenGL.cpp
	src/Nazara/Renderer/RenderBuffer.cpp
	src/Nazara/Renderer/RenderTexture.cpp
	src/Nazara/Renderer/Renderer.cpp
	src/Nazara/Renderer/Shader.cpp
	src/Nazara/Renderer/ShaderStage.cpp
	src/Nazara/Renderer/Texture.cpp

Former-commit-id: 2f1c7e9f9766f59ab83d9405856a1898ac4ab48f
This commit is contained in:
Lynix
2015-09-25 23:16:58 +02:00
613 changed files with 68051 additions and 66125 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

@@ -21,373 +21,379 @@
#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)
{
InputStream* stream = static_cast<InputStream*>(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)
{
InputStream* stream = static_cast<InputStream*>(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)
{
InputStream* stream = static_cast<InputStream*>(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)
{
InputStream* stream = static_cast<InputStream*>(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 MemoryStream(data, size));
return Open(*m_ownedStream, forceMono);
}
bool Open(InputStream& 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<InputStream> 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(InputStream& 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, InputStream& 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(InputStream& 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, InputStream& 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(InputStream& 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(InputStream& 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(InputStream& 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

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

View File

@@ -7,15 +7,18 @@
#include <ostream>
#include <Nazara/Core/Debug.hpp>
std::ostream& operator<<(std::ostream& out, const NzByteArray& byteArray)
namespace Nz
{
out << byteArray.ToString();
return out;
}
std::ostream& operator<<(std::ostream& out, const ByteArray& byteArray)
{
out << byteArray.ToString();
return out;
}
bool NzByteArray::FillHash(NzAbstractHash* hash) const
{
hash->Append(GetConstBuffer(), GetSize());
bool ByteArray::FillHash(AbstractHash* hash) const
{
hash->Append(GetConstBuffer(), GetSize());
return true;
return true;
}
}

View File

@@ -21,93 +21,96 @@
#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()
Clock::Clock(UInt64 startingValue, bool paused) :
m_elapsedTime(startingValue),
m_refTime(GetElapsedMicroseconds()),
m_paused(paused)
{
if (NzClockImplInitializeHighPrecision())
NzGetMicroseconds = NzClockImplGetMicroseconds;
}
float Clock::GetSeconds() const
{
return GetMicroseconds()/1000000.f;
}
UInt64 Clock::GetMicroseconds() const
{
NazaraLock(m_mutex);
UInt64 elapsedMicroseconds = m_elapsedTime;
if (!m_paused)
elapsedMicroseconds += (GetElapsedMicroseconds() - m_refTime);
return elapsedMicroseconds;
}
UInt64 Clock::GetMilliseconds() const
{
return GetMicroseconds()/1000;
}
bool Clock::IsPaused() const
{
NazaraLock(m_mutex);
return m_paused;
}
void Clock::Pause()
{
NazaraLock(m_mutex);
if (!m_paused)
{
m_elapsedTime += GetElapsedMicroseconds() - m_refTime;
m_paused = true;
}
else
NzGetMicroseconds = NzGetMicrosecondsLowPrecision;
return NzGetMicroseconds();
NazaraWarning("Clock is already paused, ignoring...");
}
}
NzClock::NzClock(nzUInt64 startingValue, bool paused) :
m_elapsedTime(startingValue),
m_refTime(NzGetMicroseconds()),
m_paused(paused)
{
}
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)
void Clock::Restart()
{
m_elapsedTime += NzGetMicroseconds()-m_refTime;
m_paused = true;
}
else
NazaraWarning("Clock is already paused, ignoring...");
}
NazaraLock(m_mutex);
void NzClock::Restart()
{
NazaraLock(m_mutex);
m_elapsedTime = 0;
m_refTime = NzGetMicroseconds();
m_paused = false;
}
void NzClock::Unpause()
{
NazaraLock(m_mutex);
if (m_paused)
{
m_refTime = NzGetMicroseconds();
m_elapsedTime = 0;
m_refTime = GetElapsedMicroseconds();
m_paused = false;
}
else
NazaraWarning("Clock is not paused, ignoring...");
}
NzClockFunction NzGetMicroseconds = NzGetMicrosecondsFirstRun;
NzClockFunction NzGetMilliseconds = NzClockImplGetMilliseconds;
void Clock::Unpause()
{
NazaraLock(m_mutex);
if (m_paused)
{
m_refTime = GetElapsedMicroseconds();
m_paused = false;
}
else
NazaraWarning("Clock is not paused, ignoring...");
}
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,47 @@
#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é
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();
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

@@ -24,364 +24,367 @@
#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;
thread_local 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
return m_impl->GetResultName();
}
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;
do
{
NzString p = path.SubString(0, foundPos);
if (p.EndsWith(NAZARA_DIRECTORY_SEPARATOR))
p = p.SubString(0, -2);
if (!NzDirectoryImpl::Exists(p) && !NzDirectoryImpl::Create(p))
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);
unsigned int 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
do
{
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);
}
while (true);
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 ?
static int offset = -1;
if (offset < 0)
{
const char* directoryFile = __FILE__;
const char* ptr = std::strstr(directoryFile, "NazaraEngine/src/Nazara/Core/Directory.cpp");
if (ptr)
offset = ptr - directoryFile;
else
{
ptr = std::strstr(directoryFile, "NazaraEngine\\src\\Nazara\\Core\\Directory.cpp");
if (ptr)
offset = ptr - directoryFile;
else
offset = 0;
}
}
return &currentFile[offset];
}
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)
NazaraLog->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)
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 == 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

@@ -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;
int bestFreeRect;
int 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)
{
unsigned int position = rect - rects;
inserted[position] = false;
}
}
return false;
}
// Otherwise, we're good to go and do the actual packing.
unsigned int 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

@@ -14,67 +14,70 @@
#include <Nazara/Core/Hash/Whirlpool.hpp>
#include <Nazara/Core/Debug.hpp>
NzHash::NzHash(nzHash hash)
namespace Nz
{
switch (hash)
Hash::Hash(HashType hash)
{
case nzHash_Fletcher16:
m_impl = new NzHashFletcher16;
break;
switch (hash)
{
case HashType_Fletcher16:
m_impl = new HashFletcher16;
break;
case nzHash_CRC32:
m_impl = new NzHashCRC32;
break;
case HashType_CRC32:
m_impl = new HashCRC32;
break;
case nzHash_MD5:
m_impl = new NzHashMD5;
break;
case HashType_MD5:
m_impl = new HashMD5;
break;
case nzHash_SHA1:
m_impl = new NzHashSHA1;
break;
case HashType_SHA1:
m_impl = new HashSHA1;
break;
case nzHash_SHA224:
m_impl = new NzHashSHA224;
break;
case HashType_SHA224:
m_impl = new HashSHA224;
break;
case nzHash_SHA256:
m_impl = new NzHashSHA256;
break;
case HashType_SHA256:
m_impl = new HashSHA256;
break;
case nzHash_SHA384:
m_impl = new NzHashSHA384;
break;
case HashType_SHA384:
m_impl = new HashSHA384;
break;
case nzHash_SHA512:
m_impl = new NzHashSHA512;
break;
case HashType_SHA512:
m_impl = new HashSHA512;
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();
case HashType_Whirlpool:
m_impl = new HashWhirlpool;
break;
}
}
Hash::Hash(AbstractHash* hashImpl) :
m_impl(hashImpl)
{
}
Hash::~Hash()
{
delete m_impl;
}
HashDigest Hash::Process(const Hashable& hashable)
{
m_impl->Begin();
if (hashable.FillHash(m_impl))
return m_impl->End();
else // Erreur
{
m_impl->End();
return HashDigest();
}
}
}

View File

@@ -6,125 +6,128 @@
#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, unsigned int 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;
}
HashDigest HashCRC32::End()
{
m_state->crc ^= 0xFFFFFFFF;
#ifdef NAZARA_LITTLE_ENDIAN
SwapBytes(&m_state->crc, sizeof(UInt32));
#endif
return HashDigest(GetHashName(), reinterpret_cast<UInt8*>(&m_state->crc), 4);
}
unsigned int HashCRC32::GetDigestLength()
{
return 4;
}
String HashCRC32::GetHashName()
{
static String hashName = "CRC32";
return hashName;
}
}
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,70 @@
#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, unsigned int len)
{
while (len)
{
unsigned int tlen = std::min(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;
}
HashDigest 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 HashDigest(GetHashName(), reinterpret_cast<UInt8*>(&fletcher), 2);
}
unsigned int HashFletcher16::GetDigestLength()
{
return 2;
}
String HashFletcher16::GetHashName()
{
static String hashName = "Fletcher16";
return hashName;
}
}
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,269 @@
#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, unsigned int 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;
}
HashDigest 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 HashDigest(GetHashName(), &digest[0], 16);
}
unsigned int HashMD5::GetDigestLength()
{
return 16;
}
String HashMD5::GetHashName()
{
static String hashName = "MD5";
return hashName;
}
}
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,45 @@
#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, unsigned int len)
{
SHA1_Update(m_state, data, len);
}
void HashSHA1::Begin()
{
SHA1_Init(m_state);
}
HashDigest HashSHA1::End()
{
UInt8 digest[SHA1_DIGEST_LENGTH];
SHA1_End(m_state, digest);
return HashDigest(GetHashName(), digest, SHA1_DIGEST_LENGTH);
}
unsigned int HashSHA1::GetDigestLength()
{
return SHA1_DIGEST_LENGTH;
}
String HashSHA1::GetHashName()
{
static String hashName = "SHA1";
return hashName;
}
}

View File

@@ -6,42 +6,45 @@
#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, unsigned int len)
{
SHA224_Update(m_state, data, len);
}
void HashSHA224::Begin()
{
SHA224_Init(m_state);
}
HashDigest HashSHA224::End()
{
UInt8 digest[SHA224_DIGEST_LENGTH];
SHA224_End(m_state, digest);
return HashDigest(GetHashName(), digest, SHA224_DIGEST_LENGTH);
}
unsigned int HashSHA224::GetDigestLength()
{
return SHA224_DIGEST_LENGTH;
}
String HashSHA224::GetHashName()
{
static String hashName = "SHA224";
return hashName;
}
}

View File

@@ -6,42 +6,45 @@
#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, unsigned int len)
{
SHA256_Update(m_state, data, len);
}
void HashSHA256::Begin()
{
SHA256_Init(m_state);
}
HashDigest HashSHA256::End()
{
UInt8 digest[SHA256_DIGEST_LENGTH];
SHA256_End(m_state, digest);
return HashDigest(GetHashName(), digest, SHA256_DIGEST_LENGTH);
}
unsigned int HashSHA256::GetDigestLength()
{
return SHA256_DIGEST_LENGTH;
}
String HashSHA256::GetHashName()
{
static String hashName = "SHA256";
return hashName;
}
}

View File

@@ -6,42 +6,45 @@
#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, unsigned int len)
{
SHA384_Update(m_state, data, len);
}
void HashSHA384::Begin()
{
SHA384_Init(m_state);
}
HashDigest HashSHA384::End()
{
UInt8 digest[SHA384_DIGEST_LENGTH];
SHA384_End(m_state, digest);
return HashDigest(GetHashName(), digest, SHA384_DIGEST_LENGTH);
}
unsigned int HashSHA384::GetDigestLength()
{
return SHA384_DIGEST_LENGTH;
}
String HashSHA384::GetHashName()
{
static String hashName = "SHA384";
return hashName;
}
}

View File

@@ -6,42 +6,45 @@
#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, unsigned int len)
{
SHA512_Update(m_state, data, len);
}
void HashSHA512::Begin()
{
SHA512_Init(m_state);
}
HashDigest HashSHA512::End()
{
UInt8 digest[SHA512_DIGEST_LENGTH];
SHA512_End(m_state, digest);
return HashDigest(GetHashName(), digest, SHA512_DIGEST_LENGTH);
}
unsigned int HashSHA512::GetDigestLength()
{
return SHA512_DIGEST_LENGTH;
}
String HashSHA512::GetHashName()
{
static String hashName = "SHA512";
return hashName;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -10,181 +10,184 @@
#include <cstring>
#include <Nazara/Core/Debug.hpp>
NzHashDigest::NzHashDigest() :
m_digest(nullptr),
m_digestLength(0)
namespace Nz
{
}
NzHashDigest::NzHashDigest(const NzString& hashName, const nzUInt8* digest, unsigned int length) :
m_hashName(hashName),
m_digestLength(length)
{
if (m_digestLength > 0)
HashDigest::HashDigest() :
m_digest(nullptr),
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)
HashDigest::HashDigest(const String& hashName, const UInt8* digest, unsigned int length) :
m_hashName(hashName),
m_digestLength(length)
{
m_digest = new nzUInt8[m_digestLength];
std::memcpy(m_digest, rhs.m_digest, m_digestLength);
if (m_digestLength > 0)
{
m_digest = new UInt8[length];
std::memcpy(m_digest, digest, length);
}
else
m_digest = nullptr;
}
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)
HashDigest::HashDigest(const HashDigest& rhs) :
m_hashName(rhs.m_hashName),
m_digestLength(rhs.m_digestLength)
{
NazaraError("Position out of range");
return 0;
if (m_digestLength > 0)
{
m_digest = new UInt8[m_digestLength];
std::memcpy(m_digest, rhs.m_digest, m_digestLength);
}
else
m_digest = nullptr;
}
#endif
return m_digest[pos];
}
HashDigest::HashDigest(HashDigest&& 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;
}
HashDigest::~HashDigest()
{
delete[] m_digest;
}
bool HashDigest::IsValid() const
{
return m_digestLength > 0;
}
const UInt8* HashDigest::GetDigest() const
{
return m_digest;
}
unsigned int HashDigest::GetDigestLength() const
{
return m_digestLength;
}
String HashDigest::GetHashName() const
{
return m_hashName;
}
String HashDigest::ToHex() const
{
if (m_digestLength == 0)
return String();
unsigned int length = m_digestLength*2;
String hexOutput(length);
for (unsigned int i = 0; i < m_digestLength; ++i)
std::sprintf(&hexOutput[i*2], "%02x", m_digest[i]);
return hexOutput;
}
UInt8 HashDigest::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];
}
HashDigest& HashDigest::operator=(const HashDigest& rhs)
{
if (this == &rhs)
return *this;
m_hashName = rhs.m_hashName;
m_digestLength = rhs.m_digestLength;
if (m_digestLength > 0)
{
m_digest = new UInt8[m_digestLength];
std::memcpy(m_digest, rhs.m_digest, m_digestLength);
}
else
m_digest = nullptr;
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)
HashDigest& HashDigest::operator=(HashDigest&& rhs) noexcept
{
cmp = std::memcmp(m_digest, rhs.m_digest, std::min(m_digestLength, rhs.m_digestLength));
std::swap(m_hashName, rhs.m_hashName);
std::swap(m_digest, rhs.m_digest);
std::swap(m_digestLength, rhs.m_digestLength);
return *this;
}
bool HashDigest::operator==(const HashDigest& 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 HashDigest::operator!=(const HashDigest& rhs) const
{
return !operator==(rhs);
}
bool HashDigest::operator<(const HashDigest& rhs) const
{
if (rhs.m_digest == nullptr)
return false;
if (m_digest == nullptr)
return true;
int cmp = String::Compare(m_hashName, rhs.m_hashName);
if (cmp == 0)
return m_digestLength < rhs.m_digestLength;
{
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;
}
else
return cmp < 0;
bool HashDigest::operator<=(const HashDigest& rhs) const
{
return !rhs.operator<(*this);
}
bool HashDigest::operator>(const HashDigest& rhs) const
{
return rhs.operator<(*this);
}
bool HashDigest::operator>=(const HashDigest& rhs) const
{
return !operator<(rhs);
}
}
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)
std::ostream& operator<<(std::ostream& out, const Nz::HashDigest& hashstring)
{
out << hashstring.ToHex();
return out;

View File

@@ -6,16 +6,19 @@
#include <Nazara/Core/Hash.hpp>
#include <Nazara/Core/Debug.hpp>
NzHashable::~NzHashable() = default;
NzHashDigest NzHashable::GetHash(nzHash hash) const
namespace Nz
{
NzHash h(hash);
return h.Hash(*this);
}
Hashable::~Hashable() = default;
NzHashDigest NzHashable::GetHash(NzAbstractHash* impl) const
{
NzHash h(impl);
return h.Hash(*this);
HashDigest Hashable::GetHash(HashType hash) const
{
Hash h(hash);
return h.Process(*this);
}
HashDigest Hashable::GetHash(AbstractHash* impl) const
{
Hash h(impl);
return h.Process(*this);
}
}

View File

@@ -8,61 +8,64 @@
#include <cstring>
#include <Nazara/Core/Debug.hpp>
NzInputStream::~NzInputStream() = default;
NzString NzInputStream::ReadLine(unsigned int lineSize)
namespace Nz
{
NzString line;
if (lineSize == 0) // Taille maximale indéterminée
InputStream::~InputStream() = default;
String InputStream::ReadLine(unsigned int lineSize)
{
const unsigned int bufferSize = 64;
char buffer[bufferSize+1];
buffer[bufferSize] = '\0';
unsigned int readSize;
do
String line;
if (lineSize == 0) // Taille maximale indéterminée
{
readSize = Read(buffer, bufferSize);
const unsigned int bufferSize = 64;
const char* ptr = std::strchr(buffer, '\n');
if (ptr)
char buffer[bufferSize+1];
buffer[bufferSize] = '\0';
unsigned int readSize;
do
{
unsigned int pos = ptr-buffer;
readSize = Read(buffer, bufferSize);
if (m_streamOptions & nzStreamOption_Text && pos > 0 && buffer[pos-1] == '\r')
line.Append(buffer, pos-1);
const char* ptr = std::strchr(buffer, '\n');
if (ptr)
{
unsigned int 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, pos);
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 & 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");
break;
}
else
line.Append(buffer, readSize);
line.Resize(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;
}
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

@@ -21,142 +21,145 @@
#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
};
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*) == nzErrorType_Max+1, "Error type array is incomplete");
}
static_assert(sizeof(errorType)/sizeof(const char*) == ErrorType_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)
{
}
Log::Log() :
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)
Log::~Log()
{
delete m_file;
m_file = nullptr;
}
}
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;
}
}
NazaraLock(m_mutex)
void NzLog::EnableDateTime(bool enable)
{
NazaraLock(m_mutex)
if (m_enabled == enable)
return;
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)
{
if (!m_file)
m_file = new NzFile(m_filePath, nzOpenMode_Text | nzOpenMode_WriteOnly | ((m_append) ? nzOpenMode_Append : nzOpenMode_Truncate));
NzString line;
if (m_writeTime)
m_enabled = enable;
if (!m_enabled && m_file)
{
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));
delete m_file;
m_file = nullptr;
}
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
}
}
void NzLog::WriteError(nzErrorType type, const NzString& error)
{
NzStringStream stream;
stream << errorType[type] << error;
Write(stream);
}
void Log::EnableAppend(bool enable)
{
NazaraLock(m_mutex)
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);
}
m_append = enable;
if (!m_append && m_file)
{
m_file->Delete();
m_file = nullptr;
}
}
NzLog* NzLog::Instance()
{
static NzLog log;
return &log;
void Log::EnableDateTime(bool enable)
{
NazaraLock(m_mutex)
m_writeTime = enable;
}
String Log::GetFile() const
{
NazaraLock(m_mutex)
if (m_file)
return m_file->GetPath();
else
return String();
}
bool Log::IsEnabled() const
{
NazaraLock(m_mutex)
return m_enabled;
}
void Log::SetFile(const String& filePath)
{
NazaraLock(m_mutex)
m_filePath = filePath;
if (m_file)
m_file->SetFile(filePath);
}
void Log::Write(const String& string)
{
NazaraLock(m_mutex)
if (m_enabled)
{
if (!m_file)
m_file = new File(m_filePath, OpenMode_Text | OpenMode_WriteOnly | ((m_append) ? OpenMode_Append : OpenMode_Truncate));
String 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
}
}
void Log::WriteError(ErrorType type, const String& error)
{
StringStream stream;
stream << errorType[type] << error;
Write(stream);
}
void Log::WriteError(ErrorType type, const String& error, unsigned int line, const String& file, const String& func)
{
StringStream stream;
stream << errorType[type] << error << " (" << file << ':' << line << ": " << func << ')';
Write(stream);
}
Log* Log::Instance()
{
static Log log;
return &log;
}
}

View File

@@ -17,320 +17,323 @@
// 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();
return nullptr; // Ça me rassure d'avoir un return, aussi inutile soit-il
}
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

@@ -7,47 +7,50 @@
#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)
namespace Nz
{
}
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;
MemoryStream::MemoryStream(const void* ptr, UInt64 size) :
m_ptr(reinterpret_cast<const UInt8*>(ptr)),
m_pos(0),
m_size(size)
{
}
MemoryStream::~MemoryStream()
{
}
bool MemoryStream::EndOfStream() const
{
return m_pos == m_size;
}
UInt64 MemoryStream::GetCursorPos() const
{
return m_pos;
}
UInt64 MemoryStream::GetSize() const
{
return m_size;
}
std::size_t MemoryStream::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 MemoryStream::SetCursorPos(UInt64 offset)
{
m_pos = std::min(offset, m_size);
return true;
}
}

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

@@ -6,112 +6,115 @@
#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(unsigned int i)
{
#if NAZARA_CORE_SAFE
if (i >= m_primitives.size())
{
NazaraError("Primitive index out of range (" + String::Number(i) + " >= " + String::Number(m_primitives.size()) + ')');
static Primitive dummy;
return dummy;
}
#endif
return m_primitives[i];
}
const Primitive& PrimitiveList::GetPrimitive(unsigned int i) const
{
#if NAZARA_CORE_SAFE
if (i >= m_primitives.size())
{
NazaraError("Primitive index out of range (" + String::Number(i) + " >= " + String::Number(m_primitives.size()) + ')');
static Primitive dummy;
return dummy;
}
#endif
return m_primitives[i];
}
unsigned int 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

@@ -5,24 +5,27 @@
#include <Nazara/Core/Stream.hpp>
#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;
unsigned int Stream::GetStreamOptions() const
{
return m_streamOptions;
}
void Stream::SetStreamOptions(unsigned int options)
{
m_streamOptions = options;
}
}

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,291 @@
#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, unsigned int mode)
{
DWORD access;
DWORD shareMode = FILE_SHARE_READ;
DWORD openMode;
if (mode & OpenMode_ReadOnly)
{
access = GENERIC_READ;
openMode = OPEN_EXISTING;
}
else if (mode & OpenMode_ReadWrite)
{
if (mode & OpenMode_Append)
access = FILE_APPEND_DATA;
else
access = GENERIC_READ | GENERIC_WRITE;
if (mode & OpenMode_Truncate)
openMode = CREATE_ALWAYS;
else
openMode = OPEN_ALWAYS;
}
else 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;
}
else
return false;
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, unsigned int 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(unsigned int 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<unsigned int[]> workerIDs(new unsigned int[workerCount]);
s_doneEvents[i] = CreateEventW(nullptr, true, false, nullptr);
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;
// 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, unsigned int 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
// 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);
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;
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)
{
// On ne vole pas la famille, ni soi-même.
if (i == workerID)
continue;
// 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++);
// Ce worker a-t-il encore des tâches dans sa file d'attente ?
if (worker.workCount > 0)
{
NzFunctor* task = nullptr;
// 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;
}
// 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à !
}
// 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)
{
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(unsigned int workerID)
{
bool shouldRetry;
do
{
shouldRetry = false;
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)
{
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
unsigned int 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(unsigned int workerCount);
static bool IsInitialized();
static void Run(Functor** tasks, unsigned int 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(unsigned int 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_uint 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 unsigned int s_workerCount;
};
}
#endif // NAZARA_TASKSCHEDULERIMPL_HPP

View File

@@ -8,40 +8,43 @@
#include <process.h>
#include <Nazara/Core/Debug.hpp>
NzThreadImpl::NzThreadImpl(NzFunctor* functor)
namespace Nz
{
m_handle = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &NzThreadImpl::ThreadProc, functor, 0, nullptr));
if (!m_handle)
NazaraInternalError("Failed to create thread: " + NzError::GetLastSystemError());
}
void NzThreadImpl::Detach()
{
// http://stackoverflow.com/questions/418742/is-it-reasonable-to-call-closehandle-on-a-thread-before-it-terminates
CloseHandle(m_handle);
}
void NzThreadImpl::Join()
{
WaitForSingleObject(m_handle, INFINITE);
CloseHandle(m_handle);
}
unsigned int __stdcall NzThreadImpl::ThreadProc(void* userdata)
{
NzFunctor* func = static_cast<NzFunctor*>(userdata);
func->Run();
delete func;
/*
En C++, il vaut mieux retourner depuis la fonction que de quitter le thread explicitement
Source : http://msdn.microsoft.com/en-us/library/windows/desktop/ms682659(v=vs.85).aspx
*/
return 0;
}
void NzThreadImpl::Sleep(nzUInt32 time)
{
::Sleep(time);
ThreadImpl::ThreadImpl(Functor* functor)
{
m_handle = reinterpret_cast<HANDLE>(_beginthreadex(nullptr, 0, &ThreadImpl::ThreadProc, functor, 0, nullptr));
if (!m_handle)
NazaraInternalError("Failed to create thread: " + Error::GetLastSystemError());
}
void ThreadImpl::Detach()
{
// http://stackoverflow.com/questions/418742/is-it-reasonable-to-call-closehandle-on-a-thread-before-it-terminates
CloseHandle(m_handle);
}
void ThreadImpl::Join()
{
WaitForSingleObject(m_handle, INFINITE);
CloseHandle(m_handle);
}
unsigned int __stdcall ThreadImpl::ThreadProc(void* userdata)
{
Functor* func = static_cast<Functor*>(userdata);
func->Run();
delete func;
/*
En C++, il vaut mieux retourner depuis la fonction que de quitter le thread explicitement
Source : http://msdn.microsoft.com/en-us/library/windows/desktop/ms682659(v=vs.85).aspx
*/
return 0;
}
void ThreadImpl::Sleep(UInt32 time)
{
::Sleep(time);
}
}

View File

@@ -12,22 +12,25 @@
#include <Nazara/Prerequesites.hpp>
#include <windows.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 unsigned int __stdcall ThreadProc(void* userdata);
static void Sleep(UInt32 time);
HANDLE m_handle;
};
private:
static unsigned int __stdcall ThreadProc(void* userdata);
HANDLE m_handle;
};
}
#endif // NAZARA_THREADIMPL_HPP

View File

@@ -5,21 +5,24 @@
#include <Nazara/Core/Win32/Time.hpp>
#include <Nazara/Core/Debug.hpp>
time_t NzFileTimeToTime(FILETIME* time)
namespace Nz
{
SYSTEMTIME stUTC, stLocal;
time_t FileTimeToTime(FILETIME* time)
{
SYSTEMTIME stUTC, stLocal;
FileTimeToSystemTime(time, &stUTC);
SystemTimeToTzSpecificLocalTime(nullptr, &stUTC, &stLocal);
FileTimeToSystemTime(time, &stUTC);
SystemTimeToTzSpecificLocalTime(nullptr, &stUTC, &stLocal);
std::tm timeinfo;
timeinfo.tm_sec = stLocal.wSecond;
timeinfo.tm_min = stLocal.wMinute;
timeinfo.tm_hour = stLocal.wHour;
timeinfo.tm_mday = stLocal.wDay;
timeinfo.tm_mon = stLocal.wMonth-1;
timeinfo.tm_year = stLocal.wYear-1900;
timeinfo.tm_isdst = -1;
std::tm timeinfo;
timeinfo.tm_sec = stLocal.wSecond;
timeinfo.tm_min = stLocal.wMinute;
timeinfo.tm_hour = stLocal.wHour;
timeinfo.tm_mday = stLocal.wDay;
timeinfo.tm_mon = stLocal.wMonth-1;
timeinfo.tm_year = stLocal.wYear-1900;
timeinfo.tm_isdst = -1;
return std::mktime(&timeinfo);
return std::mktime(&timeinfo);
}
}

View File

@@ -11,6 +11,9 @@
#include <ctime>
#include <windows.h>
time_t NzFileTimeToTime(FILETIME* time);
namespace Nz
{
time_t FileTimeToTime(FILETIME* time);
}
#endif // NAZARA_WINDOWS_TIME_HPP

View File

@@ -5,6 +5,9 @@
#include <Nazara/Graphics/AbstractBackground.hpp>
#include <Nazara/Graphics/Debug.hpp>
NzAbstractBackground::~NzAbstractBackground() = default;
namespace Nz
{
AbstractBackground::~AbstractBackground() = default;
NzBackgroundLibrary::LibraryMap NzAbstractBackground::s_library;
BackgroundLibrary::LibraryMap AbstractBackground::s_library;
}

View File

@@ -5,28 +5,31 @@
#include <Nazara/Graphics/AbstractRenderQueue.hpp>
#include <Nazara/Graphics/Debug.hpp>
NzAbstractRenderQueue::~NzAbstractRenderQueue() = default;
void NzAbstractRenderQueue::AddDirectionalLight(const DirectionalLight& light)
namespace Nz
{
directionalLights.push_back(light);
}
AbstractRenderQueue::~AbstractRenderQueue() = default;
void NzAbstractRenderQueue::AddPointLight(const PointLight& light)
{
pointLights.push_back(light);
}
void AbstractRenderQueue::AddDirectionalLight(const DirectionalLight& light)
{
directionalLights.push_back(light);
}
void NzAbstractRenderQueue::AddSpotLight(const SpotLight& light)
{
spotLights.push_back(light);
}
void AbstractRenderQueue::AddPointLight(const PointLight& light)
{
pointLights.push_back(light);
}
void NzAbstractRenderQueue::Clear(bool fully)
{
NazaraUnused(fully);
void AbstractRenderQueue::AddSpotLight(const SpotLight& light)
{
spotLights.push_back(light);
}
directionalLights.clear();
pointLights.clear();
spotLights.clear();
void AbstractRenderQueue::Clear(bool fully)
{
NazaraUnused(fully);
directionalLights.clear();
pointLights.clear();
spotLights.clear();
}
}

View File

@@ -8,24 +8,27 @@
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Graphics/Debug.hpp>
NzAbstractRenderTechnique::NzAbstractRenderTechnique() :
m_instancingEnabled(true)
namespace Nz
{
}
AbstractRenderTechnique::AbstractRenderTechnique() :
m_instancingEnabled(true)
{
}
NzAbstractRenderTechnique::~NzAbstractRenderTechnique() = default;
AbstractRenderTechnique::~AbstractRenderTechnique() = default;
void NzAbstractRenderTechnique::EnableInstancing(bool instancing)
{
m_instancingEnabled = instancing;
}
void AbstractRenderTechnique::EnableInstancing(bool instancing)
{
m_instancingEnabled = instancing;
}
NzString NzAbstractRenderTechnique::GetName() const
{
return NzRenderTechniques::ToString(GetType());
}
String AbstractRenderTechnique::GetName() const
{
return RenderTechniques::ToString(GetType());
}
bool NzAbstractRenderTechnique::IsInstancingEnabled() const
{
return m_instancingEnabled;
bool AbstractRenderTechnique::IsInstancingEnabled() const
{
return m_instancingEnabled;
}
}

View File

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

View File

@@ -10,19 +10,22 @@
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
void NzBillboard::AddToRenderQueue(NzAbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
namespace Nz
{
if (!m_material)
return;
void Billboard::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const
{
if (!m_material)
return;
renderQueue->AddBillboard(m_material, instanceData.transformMatrix.GetTranslation(), m_size, m_sinCos, m_color);
renderQueue->AddBillboard(m_material, instanceData.transformMatrix.GetTranslation(), m_size, m_sinCos, m_color);
}
void Billboard::MakeBoundingVolume() const
{
constexpr float sqrt2 = float(M_SQRT2);
m_boundingVolume.Set(Vector3f(0.f), sqrt2*m_size.x*Vector3f::Right() + sqrt2*m_size.y*Vector3f::Down());
}
BillboardLibrary::LibraryMap Billboard::s_library;
}
void NzBillboard::MakeBoundingVolume() const
{
constexpr float sqrt2 = float(M_SQRT2);
m_boundingVolume.Set(NzVector3f(0.f), sqrt2*m_size.x*NzVector3f::Right() + sqrt2*m_size.y*NzVector3f::Down());
}
NzBillboardLibrary::LibraryMap NzBillboard::s_library;

View File

@@ -7,64 +7,66 @@
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
namespace
namespace Nz
{
NzRenderStates BuildRenderStates()
namespace
{
NzRenderStates states;
states.depthFunc = nzRendererComparison_Equal;
states.faceCulling = nzFaceSide_Back;
states.parameters[nzRendererParameter_DepthBuffer] = true;
states.parameters[nzRendererParameter_DepthWrite] = false;
states.parameters[nzRendererParameter_FaceCulling] = true;
RenderStates BuildRenderStates()
{
RenderStates states;
states.depthFunc = RendererComparison_Equal;
states.faceCulling = FaceSide_Back;
states.parameters[RendererParameter_DepthBuffer] = true;
states.parameters[RendererParameter_DepthWrite] = false;
states.parameters[RendererParameter_FaceCulling] = true;
return states;
return states;
}
}
ColorBackground::ColorBackground(const Color& color) :
m_color(color)
{
m_uberShader = UberShaderLibrary::Get("Basic");
ParameterList list;
list.SetParameter("UNIFORM_VERTEX_DEPTH", true);
m_uberShaderInstance = m_uberShader->Get(list);
const Shader* shader = m_uberShaderInstance->GetShader();
m_materialDiffuseUniform = shader->GetUniformLocation("MaterialDiffuse");
m_vertexDepthUniform = shader->GetUniformLocation("VertexDepth");
}
void ColorBackground::Draw(const AbstractViewer* viewer) const
{
NazaraUnused(viewer);
static RenderStates states(BuildRenderStates());
Renderer::SetRenderStates(states);
m_uberShaderInstance->Activate();
const Shader* shader = m_uberShaderInstance->GetShader();
shader->SendColor(m_materialDiffuseUniform, m_color);
shader->SendFloat(m_vertexDepthUniform, 1.f);
Renderer::DrawFullscreenQuad();
}
BackgroundType ColorBackground::GetBackgroundType() const
{
return BackgroundType_Color;
}
Color ColorBackground::GetColor() const
{
return m_color;
}
void ColorBackground::SetColor(const Color& color)
{
m_color = color;
}
}
NzColorBackground::NzColorBackground(const NzColor& color) :
m_color(color)
{
m_uberShader = NzUberShaderLibrary::Get("Basic");
NzParameterList list;
list.SetParameter("UNIFORM_VERTEX_DEPTH", true);
m_uberShaderInstance = m_uberShader->Get(list);
const NzShader* shader = m_uberShaderInstance->GetShader();
m_materialDiffuseUniform = shader->GetUniformLocation("MaterialDiffuse");
m_vertexDepthUniform = shader->GetUniformLocation("VertexDepth");
}
void NzColorBackground::Draw(const NzAbstractViewer* viewer) const
{
NazaraUnused(viewer);
static NzRenderStates states(BuildRenderStates());
NzRenderer::SetRenderStates(states);
m_uberShaderInstance->Activate();
const NzShader* shader = m_uberShaderInstance->GetShader();
shader->SendColor(m_materialDiffuseUniform, m_color);
shader->SendFloat(m_vertexDepthUniform, 1.f);
NzRenderer::DrawFullscreenQuad();
}
nzBackgroundType NzColorBackground::GetBackgroundType() const
{
return nzBackgroundType_Color;
}
NzColor NzColorBackground::GetColor() const
{
return m_color;
}
void NzColorBackground::SetColor(const NzColor& color)
{
m_color = color;
}

View File

@@ -7,161 +7,164 @@
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
NzDeferredBloomPass::NzDeferredBloomPass() :
m_uniformUpdated(false),
m_brightLuminance(0.8f),
m_brightMiddleGrey(0.5f),
m_brightThreshold(0.8f),
m_blurPassCount(5)
namespace Nz
{
m_bilinearSampler.SetAnisotropyLevel(1);
m_bilinearSampler.SetFilterMode(nzSamplerFilter_Bilinear);
m_bilinearSampler.SetWrapMode(nzSamplerWrap_Clamp);
m_bloomBrightShader = NzShaderLibrary::Get("DeferredBloomBright");
m_bloomFinalShader = NzShaderLibrary::Get("DeferredBloomFinal");
m_bloomStates.parameters[nzRendererParameter_DepthBuffer] = false;
m_gaussianBlurShader = NzShaderLibrary::Get("DeferredGaussianBlur");
m_gaussianBlurShaderFilterLocation = m_gaussianBlurShader->GetUniformLocation("Filter");
for (unsigned int i = 0; i < 2; ++i)
m_bloomTextures[i] = NzTexture::New();
}
NzDeferredBloomPass::~NzDeferredBloomPass() = default;
unsigned int NzDeferredBloomPass::GetBlurPassCount() const
{
return m_blurPassCount;
}
float NzDeferredBloomPass::GetBrightLuminance() const
{
return m_brightLuminance;
}
float NzDeferredBloomPass::GetBrightMiddleGrey() const
{
return m_brightMiddleGrey;
}
float NzDeferredBloomPass::GetBrightThreshold() const
{
return m_brightThreshold;
}
NzTexture* NzDeferredBloomPass::GetTexture(unsigned int i) const
{
#if NAZARA_GRAPHICS_SAFE
if (i >= 2)
DeferredBloomPass::DeferredBloomPass() :
m_uniformUpdated(false),
m_brightLuminance(0.8f),
m_brightMiddleGrey(0.5f),
m_brightThreshold(0.8f),
m_blurPassCount(5)
{
NazaraError("Texture index out of range (" + NzString::Number(i) + " >= 2)");
return nullptr;
}
#endif
m_bilinearSampler.SetAnisotropyLevel(1);
m_bilinearSampler.SetFilterMode(SamplerFilter_Bilinear);
m_bilinearSampler.SetWrapMode(SamplerWrap_Clamp);
return m_bloomTextures[i];
}
m_bloomBrightShader = ShaderLibrary::Get("DeferredBloomBright");
m_bloomFinalShader = ShaderLibrary::Get("DeferredBloomFinal");
m_bloomStates.parameters[RendererParameter_DepthBuffer] = false;
m_gaussianBlurShader = ShaderLibrary::Get("DeferredGaussianBlur");
m_gaussianBlurShaderFilterLocation = m_gaussianBlurShader->GetUniformLocation("Filter");
bool NzDeferredBloomPass::Process(const NzSceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{
NazaraUnused(sceneData);
NzRenderer::SetRenderStates(m_bloomStates);
NzRenderer::SetTextureSampler(0, m_bilinearSampler);
NzRenderer::SetTextureSampler(1, m_bilinearSampler);
m_workRTT->SetColorTarget(firstWorkTexture);
NzRenderer::SetTarget(m_workRTT);
NzRenderer::SetViewport(NzRecti(0, 0, m_dimensions.x, m_dimensions.y));
NzRenderer::SetShader(m_bloomBrightShader);
if (!m_uniformUpdated)
{
m_bloomBrightShader->SendFloat(m_bloomBrightShader->GetUniformLocation("BrightLuminance"), m_brightLuminance);
m_bloomBrightShader->SendFloat(m_bloomBrightShader->GetUniformLocation("BrightMiddleGrey"), m_brightMiddleGrey);
m_bloomBrightShader->SendFloat(m_bloomBrightShader->GetUniformLocation("BrightThreshold"), m_brightThreshold);
m_uniformUpdated = true;
for (unsigned int i = 0; i < 2; ++i)
m_bloomTextures[i] = Texture::New();
}
NzRenderer::SetTexture(0, m_workTextures[secondWorkTexture]);
NzRenderer::DrawFullscreenQuad();
DeferredBloomPass::~DeferredBloomPass() = default;
NzRenderer::SetTarget(&m_bloomRTT);
NzRenderer::SetViewport(NzRecti(0, 0, m_dimensions.x/8, m_dimensions.y/8));
NzRenderer::SetShader(m_gaussianBlurShader);
for (unsigned int i = 0; i < m_blurPassCount; ++i)
unsigned int DeferredBloomPass::GetBlurPassCount() const
{
m_bloomRTT.SetColorTarget(0); // bloomTextureA
m_gaussianBlurShader->SendVector(m_gaussianBlurShaderFilterLocation, NzVector2f(1.f, 0.f));
NzRenderer::SetTexture(0, (i == 0) ? m_workTextures[firstWorkTexture] : static_cast<const NzTexture*>(m_bloomTextures[1]));
NzRenderer::DrawFullscreenQuad();
m_bloomRTT.SetColorTarget(1); // bloomTextureB
m_gaussianBlurShader->SendVector(m_gaussianBlurShaderFilterLocation, NzVector2f(0.f, 1.f));
NzRenderer::SetTexture(0, m_bloomTextures[0]);
NzRenderer::DrawFullscreenQuad();
return m_blurPassCount;
}
m_workRTT->SetColorTarget(firstWorkTexture);
NzRenderer::SetTarget(m_workRTT);
NzRenderer::SetViewport(NzRecti(0, 0, m_dimensions.x, m_dimensions.y));
NzRenderer::SetShader(m_bloomFinalShader);
NzRenderer::SetTexture(0, m_bloomTextures[1]);
NzRenderer::SetTexture(1, m_workTextures[secondWorkTexture]);
NzRenderer::DrawFullscreenQuad();
return true;
}
bool NzDeferredBloomPass::Resize(const NzVector2ui& dimensions)
{
NzDeferredRenderPass::Resize(dimensions);
m_bloomRTT.Create(true);
for (unsigned int i = 0; i < 2; ++i)
float DeferredBloomPass::GetBrightLuminance() const
{
m_bloomTextures[i]->Create(nzImageType_2D, nzPixelFormat_RGBA8, dimensions.x/8, dimensions.y/8);
m_bloomRTT.AttachTexture(nzAttachmentPoint_Color, i, m_bloomTextures[i]);
}
m_bloomRTT.Unlock();
if (!m_bloomRTT.IsComplete())
{
NazaraError("Incomplete RTT");
return false;
return m_brightLuminance;
}
return true;
}
float DeferredBloomPass::GetBrightMiddleGrey() const
{
return m_brightMiddleGrey;
}
void NzDeferredBloomPass::SetBlurPassCount(unsigned int passCount)
{
m_blurPassCount = passCount; // N'est pas une uniforme
}
float DeferredBloomPass::GetBrightThreshold() const
{
return m_brightThreshold;
}
void NzDeferredBloomPass::SetBrightLuminance(float luminance)
{
m_brightLuminance = luminance;
m_uniformUpdated = false;
}
Texture* DeferredBloomPass::GetTexture(unsigned int i) const
{
#if NAZARA_GRAPHICS_SAFE
if (i >= 2)
{
NazaraError("Texture index out of range (" + String::Number(i) + " >= 2)");
return nullptr;
}
#endif
void NzDeferredBloomPass::SetBrightMiddleGrey(float middleGrey)
{
m_brightMiddleGrey = middleGrey;
m_uniformUpdated = false;
}
return m_bloomTextures[i];
}
void NzDeferredBloomPass::SetBrightThreshold(float threshold)
{
m_brightThreshold = threshold;
m_uniformUpdated = false;
bool DeferredBloomPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{
NazaraUnused(sceneData);
Renderer::SetRenderStates(m_bloomStates);
Renderer::SetTextureSampler(0, m_bilinearSampler);
Renderer::SetTextureSampler(1, m_bilinearSampler);
m_workRTT->SetColorTarget(firstWorkTexture);
Renderer::SetTarget(m_workRTT);
Renderer::SetViewport(Recti(0, 0, m_dimensions.x, m_dimensions.y));
Renderer::SetShader(m_bloomBrightShader);
if (!m_uniformUpdated)
{
m_bloomBrightShader->SendFloat(m_bloomBrightShader->GetUniformLocation("BrightLuminance"), m_brightLuminance);
m_bloomBrightShader->SendFloat(m_bloomBrightShader->GetUniformLocation("BrightMiddleGrey"), m_brightMiddleGrey);
m_bloomBrightShader->SendFloat(m_bloomBrightShader->GetUniformLocation("BrightThreshold"), m_brightThreshold);
m_uniformUpdated = true;
}
Renderer::SetTexture(0, m_workTextures[secondWorkTexture]);
Renderer::DrawFullscreenQuad();
Renderer::SetTarget(&m_bloomRTT);
Renderer::SetViewport(Recti(0, 0, m_dimensions.x/8, m_dimensions.y/8));
Renderer::SetShader(m_gaussianBlurShader);
for (unsigned int i = 0; i < m_blurPassCount; ++i)
{
m_bloomRTT.SetColorTarget(0); // bloomTextureA
m_gaussianBlurShader->SendVector(m_gaussianBlurShaderFilterLocation, Vector2f(1.f, 0.f));
Renderer::SetTexture(0, (i == 0) ? m_workTextures[firstWorkTexture] : static_cast<const Texture*>(m_bloomTextures[1]));
Renderer::DrawFullscreenQuad();
m_bloomRTT.SetColorTarget(1); // bloomTextureB
m_gaussianBlurShader->SendVector(m_gaussianBlurShaderFilterLocation, Vector2f(0.f, 1.f));
Renderer::SetTexture(0, m_bloomTextures[0]);
Renderer::DrawFullscreenQuad();
}
m_workRTT->SetColorTarget(firstWorkTexture);
Renderer::SetTarget(m_workRTT);
Renderer::SetViewport(Recti(0, 0, m_dimensions.x, m_dimensions.y));
Renderer::SetShader(m_bloomFinalShader);
Renderer::SetTexture(0, m_bloomTextures[1]);
Renderer::SetTexture(1, m_workTextures[secondWorkTexture]);
Renderer::DrawFullscreenQuad();
return true;
}
bool DeferredBloomPass::Resize(const Vector2ui& dimensions)
{
DeferredRenderPass::Resize(dimensions);
m_bloomRTT.Create(true);
for (unsigned int i = 0; i < 2; ++i)
{
m_bloomTextures[i]->Create(ImageType_2D, PixelFormatType_RGBA8, dimensions.x/8, dimensions.y/8);
m_bloomRTT.AttachTexture(AttachmentPoint_Color, i, m_bloomTextures[i]);
}
m_bloomRTT.Unlock();
if (!m_bloomRTT.IsComplete())
{
NazaraError("Incomplete RTT");
return false;
}
return true;
}
void DeferredBloomPass::SetBlurPassCount(unsigned int passCount)
{
m_blurPassCount = passCount; // N'est pas une uniforme
}
void DeferredBloomPass::SetBrightLuminance(float luminance)
{
m_brightLuminance = luminance;
m_uniformUpdated = false;
}
void DeferredBloomPass::SetBrightMiddleGrey(float middleGrey)
{
m_brightMiddleGrey = middleGrey;
m_uniformUpdated = false;
}
void DeferredBloomPass::SetBrightThreshold(float threshold)
{
m_brightThreshold = threshold;
m_uniformUpdated = false;
}
}

View File

@@ -9,174 +9,177 @@
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
namespace
namespace Nz
{
// http://digitalerr0r.wordpress.com/2009/05/16/xna-shader-programming-tutorial-20-depth-of-field/
NzShaderRef BuildDepthOfFieldShader()
namespace
{
const char* fragmentSource =
"#version 140\n"
"out vec4 RenderTarget0;\n"
"uniform sampler2D BlurTexture;\n"
"uniform sampler2D ColorTexture;\n"
"uniform sampler2D GBuffer1;\n"
"uniform vec2 InvTargetSize;" "\n"
"float Distance = 30.0;\n"
"float Range = 10.0;\n"
"float Near = 0.1;\n"
"float Far = (1000.0) / (1000.0 - 0.1);\n"
//"float Far = 50.0;\n"
"void main()\n"
"{\n"
"vec2 texCoord = gl_FragCoord.xy * InvTargetSize;\n"
"// Get our original pixel from ColorMap\n"
"vec3 color = textureLod(ColorTexture, texCoord, 0.0).rgb;\n"
"// Get our bloom pixel from bloom texture\n"
"vec3 blur = textureLod(BlurTexture, texCoord, 0.0).rgb;\n"
"float depth = textureLod(GBuffer1, texCoord, 0.0).w;\n"
"depth = (2.0 * 0.1) / (1000.0 + 0.1 - depth * (1000.0 - 0.1));"
"depth = 1.0 - depth;\n"
"float fSceneZ = ( -Near * Far ) / ( depth - Far);\n"
"float blurFactor = clamp(abs(fSceneZ - Distance)/Range, 0.0, 1.0);\n"
"RenderTarget0 = vec4(mix(color, blur, blurFactor), 1.0);\n"
"}\n";
const char* vertexSource =
"#version 140\n"
"in vec3 VertexPosition;\n"
"void main()\n"
"{\n"
"\t" "gl_Position = vec4(VertexPosition, 1.0);" "\n"
"}\n";
///TODO: Remplacer ça par des ShaderNode
NzShaderRef shader = NzShader::New();
if (!shader->Create())
// http://digitalerr0r.wordpress.com/2009/05/16/xna-shader-programming-tutorial-20-depth-of-field/
ShaderRef BuildDepthOfFieldShader()
{
NazaraError("Failed to load create shader");
return nullptr;
const char* fragmentSource =
"#version 140\n"
"out vec4 RenderTarget0;\n"
"uniform sampler2D BlurTexture;\n"
"uniform sampler2D ColorTexture;\n"
"uniform sampler2D GBuffer1;\n"
"uniform vec2 InvTargetSize;" "\n"
"float Distance = 30.0;\n"
"float Range = 10.0;\n"
"float Near = 0.1;\n"
"float Far = (1000.0) / (1000.0 - 0.1);\n"
//"float Far = 50.0;\n"
"void main()\n"
"{\n"
"vec2 texCoord = gl_FragCoord.xy * InvTargetSize;\n"
"// Get our original pixel from ColorMap\n"
"vec3 color = textureLod(ColorTexture, texCoord, 0.0).rgb;\n"
"// Get our bloom pixel from bloom texture\n"
"vec3 blur = textureLod(BlurTexture, texCoord, 0.0).rgb;\n"
"float depth = textureLod(GBuffer1, texCoord, 0.0).w;\n"
"depth = (2.0 * 0.1) / (1000.0 + 0.1 - depth * (1000.0 - 0.1));"
"depth = 1.0 - depth;\n"
"float fSceneZ = ( -Near * Far ) / ( depth - Far);\n"
"float blurFactor = clamp(abs(fSceneZ - Distance)/Range, 0.0, 1.0);\n"
"RenderTarget0 = vec4(mix(color, blur, blurFactor), 1.0);\n"
"}\n";
const char* vertexSource =
"#version 140\n"
"in vec3 VertexPosition;\n"
"void main()\n"
"{\n"
"\t" "gl_Position = vec4(VertexPosition, 1.0);" "\n"
"}\n";
///TODO: Remplacer ça par des ShaderNode
ShaderRef shader = Shader::New();
if (!shader->Create())
{
NazaraError("Failed to load create shader");
return nullptr;
}
if (!shader->AttachStageFromSource(ShaderStageType_Fragment, fragmentSource))
{
NazaraError("Failed to load fragment shader");
return nullptr;
}
if (!shader->AttachStageFromSource(ShaderStageType_Vertex, vertexSource))
{
NazaraError("Failed to load vertex shader");
return nullptr;
}
if (!shader->Link())
{
NazaraError("Failed to link shader");
return nullptr;
}
return shader;
}
if (!shader->AttachStageFromSource(nzShaderStage_Fragment, fragmentSource))
{
NazaraError("Failed to load fragment shader");
return nullptr;
}
if (!shader->AttachStageFromSource(nzShaderStage_Vertex, vertexSource))
{
NazaraError("Failed to load vertex shader");
return nullptr;
}
if (!shader->Link())
{
NazaraError("Failed to link shader");
return nullptr;
}
return shader;
}
}
NzDeferredDOFPass::NzDeferredDOFPass()
{
m_dofShader = BuildDepthOfFieldShader();
m_dofShader->SendInteger(m_dofShader->GetUniformLocation("ColorTexture"), 0);
m_dofShader->SendInteger(m_dofShader->GetUniformLocation("BlurTexture"), 1);
m_dofShader->SendInteger(m_dofShader->GetUniformLocation("GBuffer1"), 2);
m_gaussianBlurShader = NzShaderLibrary::Get("DeferredGaussianBlur");
m_gaussianBlurShaderFilterLocation = m_gaussianBlurShader->GetUniformLocation("Filter");
for (unsigned int i = 0; i < 2; ++i)
m_dofTextures[i] = NzTexture::New();
m_bilinearSampler.SetAnisotropyLevel(1);
m_bilinearSampler.SetFilterMode(nzSamplerFilter_Bilinear);
m_bilinearSampler.SetWrapMode(nzSamplerWrap_Clamp);
m_pointSampler.SetAnisotropyLevel(1);
m_pointSampler.SetFilterMode(nzSamplerFilter_Nearest);
m_pointSampler.SetWrapMode(nzSamplerWrap_Clamp);
m_states.parameters[nzRendererParameter_DepthBuffer] = false;
}
NzDeferredDOFPass::~NzDeferredDOFPass() = default;
bool NzDeferredDOFPass::Process(const NzSceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{
NazaraUnused(sceneData);
NzRenderer::SetTextureSampler(0, m_pointSampler);
NzRenderer::SetTextureSampler(1, m_bilinearSampler);
NzRenderer::SetTextureSampler(2, m_pointSampler);
NzRenderer::SetTarget(&m_dofRTT);
NzRenderer::SetViewport(NzRecti(0, 0, m_dimensions.x/4, m_dimensions.y/4));
NzRenderer::SetShader(m_gaussianBlurShader);
const unsigned int dofBlurPass = 2;
for (unsigned int i = 0; i < dofBlurPass; ++i)
{
m_dofRTT.SetColorTarget(0); // dofTextureA
m_gaussianBlurShader->SendVector(m_gaussianBlurShaderFilterLocation, NzVector2f(1.f, 0.f));
NzRenderer::SetTexture(0, (i == 0) ? m_workTextures[secondWorkTexture] : static_cast<const NzTexture*>(m_dofTextures[1]));
NzRenderer::DrawFullscreenQuad();
m_dofRTT.SetColorTarget(1); // dofTextureB
m_gaussianBlurShader->SendVector(m_gaussianBlurShaderFilterLocation, NzVector2f(0.f, 1.f));
NzRenderer::SetTexture(0, m_dofTextures[0]);
NzRenderer::DrawFullscreenQuad();
}
m_workRTT->SetColorTarget(firstWorkTexture);
NzRenderer::SetTarget(m_workRTT);
NzRenderer::SetViewport(NzRecti(0, 0, m_dimensions.x, m_dimensions.y));
NzRenderer::SetShader(m_dofShader);
NzRenderer::SetTexture(0, m_workTextures[secondWorkTexture]);
NzRenderer::SetTexture(1, m_dofTextures[1]);
NzRenderer::SetTexture(2, m_GBuffer[1]);
NzRenderer::DrawFullscreenQuad();
return true;
}
bool NzDeferredDOFPass::Resize(const NzVector2ui& dimensions)
{
NzDeferredRenderPass::Resize(dimensions);
m_dofRTT.Create(true);
for (unsigned int i = 0; i < 2; ++i)
DeferredDOFPass::DeferredDOFPass()
{
m_dofTextures[i]->Create(nzImageType_2D, nzPixelFormat_RGBA8, dimensions.x/4, dimensions.y/4);
m_dofRTT.AttachTexture(nzAttachmentPoint_Color, i, m_dofTextures[i]);
}
m_dofRTT.Unlock();
m_dofShader = BuildDepthOfFieldShader();
m_dofShader->SendInteger(m_dofShader->GetUniformLocation("ColorTexture"), 0);
m_dofShader->SendInteger(m_dofShader->GetUniformLocation("BlurTexture"), 1);
m_dofShader->SendInteger(m_dofShader->GetUniformLocation("GBuffer1"), 2);
if (!m_dofRTT.IsComplete())
{
NazaraError("Incomplete RTT");
return false;
m_gaussianBlurShader = ShaderLibrary::Get("DeferredGaussianBlur");
m_gaussianBlurShaderFilterLocation = m_gaussianBlurShader->GetUniformLocation("Filter");
for (unsigned int i = 0; i < 2; ++i)
m_dofTextures[i] = Texture::New();
m_bilinearSampler.SetAnisotropyLevel(1);
m_bilinearSampler.SetFilterMode(SamplerFilter_Bilinear);
m_bilinearSampler.SetWrapMode(SamplerWrap_Clamp);
m_pointSampler.SetAnisotropyLevel(1);
m_pointSampler.SetFilterMode(SamplerFilter_Nearest);
m_pointSampler.SetWrapMode(SamplerWrap_Clamp);
m_states.parameters[RendererParameter_DepthBuffer] = false;
}
return true;
DeferredDOFPass::~DeferredDOFPass() = default;
bool DeferredDOFPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{
NazaraUnused(sceneData);
Renderer::SetTextureSampler(0, m_pointSampler);
Renderer::SetTextureSampler(1, m_bilinearSampler);
Renderer::SetTextureSampler(2, m_pointSampler);
Renderer::SetTarget(&m_dofRTT);
Renderer::SetViewport(Recti(0, 0, m_dimensions.x/4, m_dimensions.y/4));
Renderer::SetShader(m_gaussianBlurShader);
const unsigned int dofBlurPass = 2;
for (unsigned int i = 0; i < dofBlurPass; ++i)
{
m_dofRTT.SetColorTarget(0); // dofTextureA
m_gaussianBlurShader->SendVector(m_gaussianBlurShaderFilterLocation, Vector2f(1.f, 0.f));
Renderer::SetTexture(0, (i == 0) ? m_workTextures[secondWorkTexture] : static_cast<const Texture*>(m_dofTextures[1]));
Renderer::DrawFullscreenQuad();
m_dofRTT.SetColorTarget(1); // dofTextureB
m_gaussianBlurShader->SendVector(m_gaussianBlurShaderFilterLocation, Vector2f(0.f, 1.f));
Renderer::SetTexture(0, m_dofTextures[0]);
Renderer::DrawFullscreenQuad();
}
m_workRTT->SetColorTarget(firstWorkTexture);
Renderer::SetTarget(m_workRTT);
Renderer::SetViewport(Recti(0, 0, m_dimensions.x, m_dimensions.y));
Renderer::SetShader(m_dofShader);
Renderer::SetTexture(0, m_workTextures[secondWorkTexture]);
Renderer::SetTexture(1, m_dofTextures[1]);
Renderer::SetTexture(2, m_GBuffer[1]);
Renderer::DrawFullscreenQuad();
return true;
}
bool DeferredDOFPass::Resize(const Vector2ui& dimensions)
{
DeferredRenderPass::Resize(dimensions);
m_dofRTT.Create(true);
for (unsigned int i = 0; i < 2; ++i)
{
m_dofTextures[i]->Create(ImageType_2D, PixelFormatType_RGBA8, dimensions.x/4, dimensions.y/4);
m_dofRTT.AttachTexture(AttachmentPoint_Color, i, m_dofTextures[i]);
}
m_dofRTT.Unlock();
if (!m_dofRTT.IsComplete())
{
NazaraError("Incomplete RTT");
return false;
}
return true;
}
}

View File

@@ -8,32 +8,35 @@
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
NzDeferredFXAAPass::NzDeferredFXAAPass()
namespace Nz
{
m_fxaaShader = NzShaderLibrary::Get("DeferredFXAA");
DeferredFXAAPass::DeferredFXAAPass()
{
m_fxaaShader = ShaderLibrary::Get("DeferredFXAA");
m_pointSampler.SetAnisotropyLevel(1);
m_pointSampler.SetFilterMode(nzSamplerFilter_Nearest);
m_pointSampler.SetWrapMode(nzSamplerWrap_Clamp);
m_pointSampler.SetAnisotropyLevel(1);
m_pointSampler.SetFilterMode(SamplerFilter_Nearest);
m_pointSampler.SetWrapMode(SamplerWrap_Clamp);
m_states.parameters[nzRendererParameter_DepthBuffer] = false;
}
NzDeferredFXAAPass::~NzDeferredFXAAPass() = default;
bool NzDeferredFXAAPass::Process(const NzSceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{
NazaraUnused(sceneData);
m_workRTT->SetColorTarget(firstWorkTexture);
NzRenderer::SetTarget(m_workRTT);
NzRenderer::SetViewport(NzRecti(0, 0, m_dimensions.x, m_dimensions.y));
NzRenderer::SetRenderStates(m_states);
NzRenderer::SetShader(m_fxaaShader);
NzRenderer::SetTexture(0, m_workTextures[secondWorkTexture]);
NzRenderer::SetTextureSampler(0, m_pointSampler);
NzRenderer::DrawFullscreenQuad();
return true;
m_states.parameters[RendererParameter_DepthBuffer] = false;
}
DeferredFXAAPass::~DeferredFXAAPass() = default;
bool DeferredFXAAPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{
NazaraUnused(sceneData);
m_workRTT->SetColorTarget(firstWorkTexture);
Renderer::SetTarget(m_workRTT);
Renderer::SetViewport(Recti(0, 0, m_dimensions.x, m_dimensions.y));
Renderer::SetRenderStates(m_states);
Renderer::SetShader(m_fxaaShader);
Renderer::SetTexture(0, m_workTextures[secondWorkTexture]);
Renderer::SetTextureSampler(0, m_pointSampler);
Renderer::DrawFullscreenQuad();
return true;
}
}

View File

@@ -8,49 +8,52 @@
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
NzDeferredFinalPass::NzDeferredFinalPass()
namespace Nz
{
m_pointSampler.SetAnisotropyLevel(1);
m_pointSampler.SetFilterMode(nzSamplerFilter_Nearest);
m_pointSampler.SetWrapMode(nzSamplerWrap_Clamp);
DeferredFinalPass::DeferredFinalPass()
{
m_pointSampler.SetAnisotropyLevel(1);
m_pointSampler.SetFilterMode(SamplerFilter_Nearest);
m_pointSampler.SetWrapMode(SamplerWrap_Clamp);
m_states.parameters[nzRendererParameter_DepthBuffer] = false;
m_states.parameters[RendererParameter_DepthBuffer] = false;
m_uberShader = NzUberShaderLibrary::Get("Basic");
m_uberShader = UberShaderLibrary::Get("Basic");
NzParameterList list;
list.SetParameter("AUTO_TEXCOORDS", true);
list.SetParameter("DIFFUSE_MAPPING", true);
list.SetParameter("TEXTURE_MAPPING", false);
ParameterList list;
list.SetParameter("AUTO_TEXCOORDS", true);
list.SetParameter("DIFFUSE_MAPPING", true);
list.SetParameter("TEXTURE_MAPPING", false);
m_uberShaderInstance = m_uberShader->Get(list);
m_uberShaderInstance = m_uberShader->Get(list);
const NzShader* shader = m_uberShaderInstance->GetShader();
m_materialDiffuseUniform = shader->GetUniformLocation("MaterialDiffuse");
m_materialDiffuseMapUniform = shader->GetUniformLocation("MaterialDiffuseMap");
}
NzDeferredFinalPass::~NzDeferredFinalPass() = default;
bool NzDeferredFinalPass::Process(const NzSceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{
NazaraAssert(sceneData.viewer, "Invalid viewer");
NazaraUnused(firstWorkTexture);
sceneData.viewer->ApplyView();
NzRenderer::SetRenderStates(m_states);
NzRenderer::SetTexture(0, m_workTextures[secondWorkTexture]);
NzRenderer::SetTextureSampler(0, m_pointSampler);
m_uberShaderInstance->Activate();
const NzShader* shader = m_uberShaderInstance->GetShader();
shader->SendColor(m_materialDiffuseUniform, NzColor::White);
shader->SendInteger(m_materialDiffuseMapUniform, 0);
NzRenderer::DrawFullscreenQuad();
return false;
const Shader* shader = m_uberShaderInstance->GetShader();
m_materialDiffuseUniform = shader->GetUniformLocation("MaterialDiffuse");
m_materialDiffuseMapUniform = shader->GetUniformLocation("MaterialDiffuseMap");
}
DeferredFinalPass::~DeferredFinalPass() = default;
bool DeferredFinalPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{
NazaraAssert(sceneData.viewer, "Invalid viewer");
NazaraUnused(firstWorkTexture);
sceneData.viewer->ApplyView();
Renderer::SetRenderStates(m_states);
Renderer::SetTexture(0, m_workTextures[secondWorkTexture]);
Renderer::SetTextureSampler(0, m_pointSampler);
m_uberShaderInstance->Activate();
const Shader* shader = m_uberShaderInstance->GetShader();
shader->SendColor(m_materialDiffuseUniform, Color::White);
shader->SendInteger(m_materialDiffuseMapUniform, 0);
Renderer::DrawFullscreenQuad();
return false;
}
}

View File

@@ -9,143 +9,146 @@
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
namespace
namespace Nz
{
NzShaderRef BuildFogShader()
namespace
{
/*const nzUInt8 fragmentSource[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/FXAA.frag.h>
};*/
const char* fragmentSource =
"#version 140\n"
"out vec4 RenderTarget0;\n"
"uniform sampler2D ColorTexture;\n"
"uniform sampler2D GBuffer2;\n"
"uniform mat4 InvViewProjMatrix;\n"
"uniform vec2 InvTargetSize;\n"
"uniform vec3 EyePosition;\n"
"float n = 0.1;"
"float f = 1000.0;"
"float color_to_float(vec3 color)\n"
"{\n"
"const vec3 byte_to_float = vec3(1.0, 1.0/256, 1.0/(256*256));\n"
"return dot(color, byte_to_float);\n"
"}\n"
"void main()\n"
"{"
"vec2 texCoord = gl_FragCoord.xy * InvTargetSize;\n"
"\t" "vec3 color = texture(ColorTexture, texCoord).xyz;\n"
"vec4 gVec2 = textureLod(GBuffer2, texCoord, 0.0);\n"
"float depth = color_to_float(gVec2.xyz)*2.0 - 1.0;\n"
"float linearDepth = (2 * n) / (f + n - depth * (f - n));"
"vec3 viewSpace = vec3(texCoord*2.0 - 1.0, depth);\n"
"vec4 worldPos = InvViewProjMatrix * vec4(viewSpace, 1.0);\n"
"worldPos.xyz /= worldPos.w;\n"
/*"float lumThreshold = 0.1;"
"float lumMultipler = 2.0;"
//"float lumFactor = max(dot(color, vec3(0.299, 0.587, 0.114)) - lumThreshold, 0.0) / (1.0-lumThreshold);"
"float fogFactor = (1.0 - clamp(worldPos.y-2.0, 0.0, 1.0)) - lumFactor*lumMultipler;"
"fogFactor += (1.0 - clamp(EyePosition.y-2.5, 0.0, 1.0));"
"fogFactor = clamp(fogFactor, 0.0, 1.0);"*/
"float lumThreshold = 0.8;"
"float lumMultipler = 2.0;"
"float luminosity = dot(color, vec3(0.299, 0.587, 0.114));"
"float lumFactor = max(luminosity - lumThreshold, 0.0) / (1.0-lumThreshold);"
"vec4 fogColor = vec4(0.5, 0.5, 0.5, 1.0);\n"
"vec2 fogrange = vec2(0, 50);\n"
"float fogeffect = clamp( 1.0 - (fogrange.y - linearDepth*0.5*f) / (fogrange.y - fogrange.x) , 0.0, 1.0 ) * fogColor.w;\n"
"fogeffect = max(fogeffect-lumFactor, 0.0);"
//fogeffect*=(1.0 - int(depth));
"\t" "vec3 fragmentColor = color*(1.0-fogeffect) + fogColor.rgb * fogeffect;\n"
"\t" "RenderTarget0 = vec4(fragmentColor, 1.0);\n"
"}";
const char* vertexSource =
"#version 140\n"
"in vec3 VertexPosition;\n"
"void main()\n"
"{\n"
"\t" "gl_Position = vec4(VertexPosition, 1.0);" "\n"
"}\n";
///TODO: Remplacer ça par des ShaderNode
NzShaderRef shader = NzShader::New();
if (!shader->Create())
ShaderRef BuildFogShader()
{
NazaraError("Failed to load create shader");
return nullptr;
/*const UInt8 fragmentSource[] = {
#include <Nazara/Graphics/Resources/DeferredShading/Shaders/FXAA.frag.h>
};*/
const char* fragmentSource =
"#version 140\n"
"out vec4 RenderTarget0;\n"
"uniform sampler2D ColorTexture;\n"
"uniform sampler2D GBuffer2;\n"
"uniform mat4 InvViewProjMatrix;\n"
"uniform vec2 InvTargetSize;\n"
"uniform vec3 EyePosition;\n"
"float n = 0.1;"
"float f = 1000.0;"
"float color_to_float(vec3 color)\n"
"{\n"
"const vec3 byte_to_float = vec3(1.0, 1.0/256, 1.0/(256*256));\n"
"return dot(color, byte_to_float);\n"
"}\n"
"void main()\n"
"{"
"vec2 texCoord = gl_FragCoord.xy * InvTargetSize;\n"
"\t" "vec3 color = texture(ColorTexture, texCoord).xyz;\n"
"vec4 gVec2 = textureLod(GBuffer2, texCoord, 0.0);\n"
"float depth = color_to_float(gVec2.xyz)*2.0 - 1.0;\n"
"float linearDepth = (2 * n) / (f + n - depth * (f - n));"
"vec3 viewSpace = vec3(texCoord*2.0 - 1.0, depth);\n"
"vec4 worldPos = InvViewProjMatrix * vec4(viewSpace, 1.0);\n"
"worldPos.xyz /= worldPos.w;\n"
/*"float lumThreshold = 0.1;"
"float lumMultipler = 2.0;"
//"float lumFactor = max(dot(color, vec3(0.299, 0.587, 0.114)) - lumThreshold, 0.0) / (1.0-lumThreshold);"
"float fogFactor = (1.0 - clamp(worldPos.y-2.0, 0.0, 1.0)) - lumFactor*lumMultipler;"
"fogFactor += (1.0 - clamp(EyePosition.y-2.5, 0.0, 1.0));"
"fogFactor = clamp(fogFactor, 0.0, 1.0);"*/
"float lumThreshold = 0.8;"
"float lumMultipler = 2.0;"
"float luminosity = dot(color, vec3(0.299, 0.587, 0.114));"
"float lumFactor = max(luminosity - lumThreshold, 0.0) / (1.0-lumThreshold);"
"vec4 fogColor = vec4(0.5, 0.5, 0.5, 1.0);\n"
"vec2 fogrange = vec2(0, 50);\n"
"float fogeffect = clamp( 1.0 - (fogrange.y - linearDepth*0.5*f) / (fogrange.y - fogrange.x) , 0.0, 1.0 ) * fogColor.w;\n"
"fogeffect = max(fogeffect-lumFactor, 0.0);"
//fogeffect*=(1.0 - int(depth));
"\t" "vec3 fragmentColor = color*(1.0-fogeffect) + fogColor.rgb * fogeffect;\n"
"\t" "RenderTarget0 = vec4(fragmentColor, 1.0);\n"
"}";
const char* vertexSource =
"#version 140\n"
"in vec3 VertexPosition;\n"
"void main()\n"
"{\n"
"\t" "gl_Position = vec4(VertexPosition, 1.0);" "\n"
"}\n";
///TODO: Remplacer ça par des ShaderNode
ShaderRef shader = Shader::New();
if (!shader->Create())
{
NazaraError("Failed to load create shader");
return nullptr;
}
if (!shader->AttachStageFromSource(ShaderStageType_Fragment, fragmentSource/*String(reinterpret_cast<const char*>(fragmentSource), sizeof(fragmentSource))*/))
{
NazaraError("Failed to load fragment shader");
return nullptr;
}
if (!shader->AttachStageFromSource(ShaderStageType_Vertex, vertexSource))
{
NazaraError("Failed to load vertex shader");
return nullptr;
}
if (!shader->Link())
{
NazaraError("Failed to link shader");
return nullptr;
}
shader->SendInteger(shader->GetUniformLocation("ColorTexture"), 0);
shader->SendInteger(shader->GetUniformLocation("GBuffer2"), 1);
return shader;
}
if (!shader->AttachStageFromSource(nzShaderStage_Fragment, fragmentSource/*NzString(reinterpret_cast<const char*>(fragmentSource), sizeof(fragmentSource))*/))
{
NazaraError("Failed to load fragment shader");
return nullptr;
}
if (!shader->AttachStageFromSource(nzShaderStage_Vertex, vertexSource))
{
NazaraError("Failed to load vertex shader");
return nullptr;
}
if (!shader->Link())
{
NazaraError("Failed to link shader");
return nullptr;
}
shader->SendInteger(shader->GetUniformLocation("ColorTexture"), 0);
shader->SendInteger(shader->GetUniformLocation("GBuffer2"), 1);
return shader;
}
DeferredFogPass::DeferredFogPass()
{
m_pointSampler.SetAnisotropyLevel(1);
m_pointSampler.SetFilterMode(SamplerFilter_Nearest);
m_pointSampler.SetWrapMode(SamplerWrap_Clamp);
m_shader = BuildFogShader();
m_shaderEyePositionLocation = m_shader->GetUniformLocation("EyePosition");
m_states.parameters[RendererParameter_DepthBuffer] = false;
}
DeferredFogPass::~DeferredFogPass() = default;
bool DeferredFogPass::Process( const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{
NazaraAssert(sceneData.viewer, "Invalid viewer");
m_workRTT->SetColorTarget(firstWorkTexture);
Renderer::SetTarget(m_workRTT);
Renderer::SetViewport(Recti(0, 0, m_dimensions.x, m_dimensions.y));
Renderer::SetShader(m_shader);
m_shader->SendVector(m_shaderEyePositionLocation, sceneData.viewer->GetEyePosition());
Renderer::SetRenderStates(m_states);
Renderer::SetTexture(0, m_workTextures[secondWorkTexture]);
Renderer::SetTexture(1, m_GBuffer[2]);
Renderer::SetTextureSampler(0, m_pointSampler);
Renderer::SetTextureSampler(1, m_pointSampler);
Renderer::DrawFullscreenQuad();
return true;
}
NzDeferredFogPass::NzDeferredFogPass()
{
m_pointSampler.SetAnisotropyLevel(1);
m_pointSampler.SetFilterMode(nzSamplerFilter_Nearest);
m_pointSampler.SetWrapMode(nzSamplerWrap_Clamp);
m_shader = BuildFogShader();
m_shaderEyePositionLocation = m_shader->GetUniformLocation("EyePosition");
m_states.parameters[nzRendererParameter_DepthBuffer] = false;
}
NzDeferredFogPass::~NzDeferredFogPass() = default;
bool NzDeferredFogPass::Process( const NzSceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{
NazaraAssert(sceneData.viewer, "Invalid viewer");
m_workRTT->SetColorTarget(firstWorkTexture);
NzRenderer::SetTarget(m_workRTT);
NzRenderer::SetViewport(NzRecti(0, 0, m_dimensions.x, m_dimensions.y));
NzRenderer::SetShader(m_shader);
m_shader->SendVector(m_shaderEyePositionLocation, sceneData.viewer->GetEyePosition());
NzRenderer::SetRenderStates(m_states);
NzRenderer::SetTexture(0, m_workTextures[secondWorkTexture]);
NzRenderer::SetTexture(1, m_GBuffer[2]);
NzRenderer::SetTextureSampler(0, m_pointSampler);
NzRenderer::SetTextureSampler(1, m_pointSampler);
NzRenderer::DrawFullscreenQuad();
return true;
}

View File

@@ -11,32 +11,35 @@
#include <Nazara/Renderer/Renderer.hpp>
#include <Nazara/Graphics/Debug.hpp>
NzDeferredForwardPass::NzDeferredForwardPass() = default;
NzDeferredForwardPass::~NzDeferredForwardPass() = default;
void NzDeferredForwardPass::Initialize(NzDeferredRenderTechnique* technique)
namespace Nz
{
NzDeferredRenderPass::Initialize(technique);
DeferredForwardPass::DeferredForwardPass() = default;
DeferredForwardPass::~DeferredForwardPass() = default;
m_forwardTechnique = technique->GetForwardTechnique();
}
bool NzDeferredForwardPass::Process(const NzSceneData& sceneData, unsigned int workTexture, unsigned sceneTexture) const
{
NazaraAssert(sceneData.viewer, "Invalid viewer");
NazaraUnused(workTexture);
m_workRTT->SetColorTarget(sceneTexture);
NzRenderer::SetTarget(m_workRTT);
NzRenderer::SetViewport(NzRecti(0, 0, m_dimensions.x, m_dimensions.y));
if (sceneData.background)
sceneData.background->Draw(sceneData.viewer);
NzRenderer::SetMatrix(nzMatrixType_Projection, sceneData.viewer->GetProjectionMatrix());
NzRenderer::SetMatrix(nzMatrixType_View, sceneData.viewer->GetViewMatrix());
m_forwardTechnique->Draw(sceneData);
return false;
void DeferredForwardPass::Initialize(DeferredRenderTechnique* technique)
{
DeferredRenderPass::Initialize(technique);
m_forwardTechnique = technique->GetForwardTechnique();
}
bool DeferredForwardPass::Process(const SceneData& sceneData, unsigned int workTexture, unsigned sceneTexture) const
{
NazaraAssert(sceneData.viewer, "Invalid viewer");
NazaraUnused(workTexture);
m_workRTT->SetColorTarget(sceneTexture);
Renderer::SetTarget(m_workRTT);
Renderer::SetViewport(Recti(0, 0, m_dimensions.x, m_dimensions.y));
if (sceneData.background)
sceneData.background->Draw(sceneData.viewer);
Renderer::SetMatrix(MatrixType_Projection, sceneData.viewer->GetProjectionMatrix());
Renderer::SetMatrix(MatrixType_View, sceneData.viewer->GetViewMatrix());
m_forwardTechnique->Draw(sceneData);
return false;
}
}

View File

@@ -16,244 +16,247 @@
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
NzDeferredGeometryPass::NzDeferredGeometryPass()
namespace Nz
{
m_clearShader = NzShaderLibrary::Get("DeferredGBufferClear");
m_clearStates.parameters[nzRendererParameter_DepthBuffer] = true;
m_clearStates.parameters[nzRendererParameter_FaceCulling] = true;
m_clearStates.parameters[nzRendererParameter_StencilTest] = true;
m_clearStates.depthFunc = nzRendererComparison_Always;
m_clearStates.frontFace.stencilCompare = nzRendererComparison_Always;
m_clearStates.frontFace.stencilPass = nzStencilOperation_Zero;
}
NzDeferredGeometryPass::~NzDeferredGeometryPass() = default;
bool NzDeferredGeometryPass::Process(const NzSceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{
NazaraAssert(sceneData.viewer, "Invalid viewer");
NazaraUnused(firstWorkTexture);
NazaraUnused(secondWorkTexture);
bool instancingEnabled = m_deferredTechnique->IsInstancingEnabled();
m_GBufferRTT->SetColorTargets({0, 1, 2}); // G-Buffer
NzRenderer::SetTarget(m_GBufferRTT);
NzRenderer::SetViewport(NzRecti(0, 0, m_dimensions.x, m_dimensions.y));
NzRenderer::SetRenderStates(m_clearStates);
NzRenderer::SetShader(m_clearShader);
NzRenderer::DrawFullscreenQuad();
NzRenderer::SetMatrix(nzMatrixType_Projection, sceneData.viewer->GetProjectionMatrix());
NzRenderer::SetMatrix(nzMatrixType_View, sceneData.viewer->GetViewMatrix());
const NzShader* lastShader = nullptr;
const ShaderUniforms* shaderUniforms = nullptr;
for (auto& matIt : m_renderQueue->opaqueModels)
DeferredGeometryPass::DeferredGeometryPass()
{
auto& matEntry = matIt.second;
m_clearShader = ShaderLibrary::Get("DeferredGBufferClear");
m_clearStates.parameters[RendererParameter_DepthBuffer] = true;
m_clearStates.parameters[RendererParameter_FaceCulling] = true;
m_clearStates.parameters[RendererParameter_StencilTest] = true;
m_clearStates.depthFunc = RendererComparison_Always;
m_clearStates.frontFace.stencilCompare = RendererComparison_Always;
m_clearStates.frontFace.stencilPass = StencilOperation_Zero;
}
if (matEntry.enabled)
DeferredGeometryPass::~DeferredGeometryPass() = default;
bool DeferredGeometryPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{
NazaraAssert(sceneData.viewer, "Invalid viewer");
NazaraUnused(firstWorkTexture);
NazaraUnused(secondWorkTexture);
bool instancingEnabled = m_deferredTechnique->IsInstancingEnabled();
m_GBufferRTT->SetColorTargets({0, 1, 2}); // G-Buffer
Renderer::SetTarget(m_GBufferRTT);
Renderer::SetViewport(Recti(0, 0, m_dimensions.x, m_dimensions.y));
Renderer::SetRenderStates(m_clearStates);
Renderer::SetShader(m_clearShader);
Renderer::DrawFullscreenQuad();
Renderer::SetMatrix(MatrixType_Projection, sceneData.viewer->GetProjectionMatrix());
Renderer::SetMatrix(MatrixType_View, sceneData.viewer->GetViewMatrix());
const Shader* lastShader = nullptr;
const ShaderUniforms* shaderUniforms = nullptr;
for (auto& matIt : m_renderQueue->opaqueModels)
{
NzDeferredRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
auto& matEntry = matIt.second;
if (!meshInstances.empty())
if (matEntry.enabled)
{
const NzMaterial* material = matIt.first;
DeferredRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap;
bool useInstancing = instancingEnabled && matEntry.instancingEnabled;
// On commence par récupérer le programme du matériau
nzUInt32 flags = nzShaderFlags_Deferred;
if (useInstancing)
flags |= nzShaderFlags_Instancing;
const NzShader* shader = material->Apply(flags);
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
if (!meshInstances.empty())
{
// Index des uniformes dans le shader
shaderUniforms = GetShaderUniforms(shader);
const Material* material = matIt.first;
// Couleur ambiante de la scène
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
// Position de la caméra
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
bool useInstancing = instancingEnabled && matEntry.instancingEnabled;
lastShader = shader;
}
// On commence par récupérer le programme du matériau
UInt32 flags = ShaderFlags_Deferred;
if (useInstancing)
flags |= ShaderFlags_Instancing;
// Meshes
for (auto& meshIt : meshInstances)
{
const NzMeshData& meshData = meshIt.first;
auto& meshEntry = meshIt.second;
const Shader* shader = material->Apply(flags);
std::vector<NzMatrix4f>& instances = meshEntry.instances;
if (!instances.empty())
// Les uniformes sont conservées au sein d'un programme, inutile de les renvoyer tant qu'il ne change pas
if (shader != lastShader)
{
const NzIndexBuffer* indexBuffer = meshData.indexBuffer;
const NzVertexBuffer* vertexBuffer = meshData.vertexBuffer;
// Index des uniformes dans le shader
shaderUniforms = GetShaderUniforms(shader);
// Gestion du draw call avant la boucle de rendu
NzRenderer::DrawCall drawFunc;
NzRenderer::DrawCallInstanced instancedDrawFunc;
unsigned int indexCount;
// Couleur ambiante de la scène
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
// Position de la caméra
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
if (indexBuffer)
lastShader = shader;
}
// Meshes
for (auto& meshIt : meshInstances)
{
const MeshData& meshData = meshIt.first;
auto& meshEntry = meshIt.second;
std::vector<Matrix4f>& instances = meshEntry.instances;
if (!instances.empty())
{
drawFunc = NzRenderer::DrawIndexedPrimitives;
instancedDrawFunc = NzRenderer::DrawIndexedPrimitivesInstanced;
indexCount = indexBuffer->GetIndexCount();
}
else
{
drawFunc = NzRenderer::DrawPrimitives;
instancedDrawFunc = NzRenderer::DrawPrimitivesInstanced;
indexCount = vertexBuffer->GetVertexCount();
}
const IndexBuffer* indexBuffer = meshData.indexBuffer;
const VertexBuffer* vertexBuffer = meshData.vertexBuffer;
NzRenderer::SetIndexBuffer(indexBuffer);
NzRenderer::SetVertexBuffer(vertexBuffer);
// Gestion du draw call avant la boucle de rendu
Renderer::DrawCall drawFunc;
Renderer::DrawCallInstanced instancedDrawFunc;
unsigned int indexCount;
if (useInstancing)
{
// On récupère le buffer d'instancing du Renderer et on le configure pour fonctionner avec des matrices
NzVertexBuffer* instanceBuffer = NzRenderer::GetInstanceBuffer();
instanceBuffer->SetVertexDeclaration(NzVertexDeclaration::Get(nzVertexLayout_Matrix4));
const NzMatrix4f* instanceMatrices = &instances[0];
unsigned int instanceCount = instances.size();
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Le nombre de matrices que peut contenir le buffer
while (instanceCount > 0)
if (indexBuffer)
{
// On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing)
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
instanceCount -= renderedInstanceCount;
// On remplit l'instancing buffer avec nos matrices world
instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true);
instanceMatrices += renderedInstanceCount;
// Et on affiche
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
drawFunc = Renderer::DrawIndexedPrimitives;
instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced;
indexCount = indexBuffer->GetIndexCount();
}
}
else
{
// Sans instancing, on doit effectuer un draw call pour chaque instance
// Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances
// À cause du temps de modification du buffer d'instancing
for (const NzMatrix4f& matrix : instances)
else
{
NzRenderer::SetMatrix(nzMatrixType_World, matrix);
drawFunc(meshData.primitiveMode, 0, indexCount);
drawFunc = Renderer::DrawPrimitives;
instancedDrawFunc = Renderer::DrawPrimitivesInstanced;
indexCount = vertexBuffer->GetVertexCount();
}
}
instances.clear();
Renderer::SetIndexBuffer(indexBuffer);
Renderer::SetVertexBuffer(vertexBuffer);
if (useInstancing)
{
// On récupère le buffer d'instancing du Renderer et on le configure pour fonctionner avec des matrices
VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer();
instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4));
const Matrix4f* instanceMatrices = &instances[0];
unsigned int instanceCount = instances.size();
unsigned int maxInstanceCount = instanceBuffer->GetVertexCount(); // Le nombre de matrices que peut contenir le buffer
while (instanceCount > 0)
{
// On calcule le nombre d'instances que l'on pourra afficher cette fois-ci (Selon la taille du buffer d'instancing)
unsigned int renderedInstanceCount = std::min(instanceCount, maxInstanceCount);
instanceCount -= renderedInstanceCount;
// On remplit l'instancing buffer avec nos matrices world
instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount, true);
instanceMatrices += renderedInstanceCount;
// Et on affiche
instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount);
}
}
else
{
// Sans instancing, on doit effectuer un draw call pour chaque instance
// Cela reste néanmoins plus rapide que l'instancing en dessous d'un certain nombre d'instances
// À cause du temps de modification du buffer d'instancing
for (const Matrix4f& matrix : instances)
{
Renderer::SetMatrix(MatrixType_World, matrix);
drawFunc(meshData.primitiveMode, 0, indexCount);
}
}
instances.clear();
}
}
}
// Et on remet à zéro les données
matEntry.enabled = false;
matEntry.instancingEnabled = false;
}
}
return false; // On ne fait que remplir le G-Buffer, les work texture ne sont pas affectées
}
bool DeferredGeometryPass::Resize(const Vector2ui& dimensions)
{
DeferredRenderPass::Resize(dimensions);
/*
G-Buffer:
Texture0: Diffuse Color + Flags
Texture1: Encoded normal
Texture2: Specular value + Shininess
Texture3: N/A
*/
try
{
ErrorFlags errFlags(ErrorFlag_ThrowException);
unsigned int width = dimensions.x;
unsigned int height = dimensions.y;
m_depthStencilBuffer->Create(PixelFormatType_Depth24Stencil8, width, height);
m_GBuffer[0]->Create(ImageType_2D, PixelFormatType_RGBA8, width, height); // Texture 0 : Diffuse Color + Specular
m_GBuffer[1]->Create(ImageType_2D, PixelFormatType_RG16F, width, height); // Texture 1 : Encoded normal
m_GBuffer[2]->Create(ImageType_2D, PixelFormatType_RGBA8, width, height); // Texture 2 : Depth (24bits) + Shininess
m_GBufferRTT->Create(true);
m_GBufferRTT->AttachTexture(AttachmentPoint_Color, 0, m_GBuffer[0]);
m_GBufferRTT->AttachTexture(AttachmentPoint_Color, 1, m_GBuffer[1]);
m_GBufferRTT->AttachTexture(AttachmentPoint_Color, 2, m_GBuffer[2]);
// Texture 3 : Emission map ?
m_GBufferRTT->AttachBuffer(AttachmentPoint_DepthStencil, 0, m_depthStencilBuffer);
m_GBufferRTT->Unlock();
m_workRTT->Create(true);
for (unsigned int i = 0; i < 2; ++i)
{
m_workTextures[i]->Create(ImageType_2D, PixelFormatType_RGBA8, width, height);
m_workRTT->AttachTexture(AttachmentPoint_Color, i, m_workTextures[i]);
}
// Et on remet à zéro les données
matEntry.enabled = false;
matEntry.instancingEnabled = false;
m_workRTT->AttachBuffer(AttachmentPoint_DepthStencil, 0, m_depthStencilBuffer);
m_workRTT->Unlock();
if (!m_workRTT->IsComplete() || !m_GBufferRTT->IsComplete())
{
NazaraError("Incomplete RTT");
return false;
}
return true;
}
}
return false; // On ne fait que remplir le G-Buffer, les work texture ne sont pas affectées
}
bool NzDeferredGeometryPass::Resize(const NzVector2ui& dimensions)
{
NzDeferredRenderPass::Resize(dimensions);
/*
G-Buffer:
Texture0: Diffuse Color + Flags
Texture1: Encoded normal
Texture2: Specular value + Shininess
Texture3: N/A
*/
try
{
NzErrorFlags errFlags(nzErrorFlag_ThrowException);
unsigned int width = dimensions.x;
unsigned int height = dimensions.y;
m_depthStencilBuffer->Create(nzPixelFormat_Depth24Stencil8, width, height);
m_GBuffer[0]->Create(nzImageType_2D, nzPixelFormat_RGBA8, width, height); // Texture 0 : Diffuse Color + Specular
m_GBuffer[1]->Create(nzImageType_2D, nzPixelFormat_RG16F, width, height); // Texture 1 : Encoded normal
m_GBuffer[2]->Create(nzImageType_2D, nzPixelFormat_RGBA8, width, height); // Texture 2 : Depth (24bits) + Shininess
m_GBufferRTT->Create(true);
m_GBufferRTT->AttachTexture(nzAttachmentPoint_Color, 0, m_GBuffer[0]);
m_GBufferRTT->AttachTexture(nzAttachmentPoint_Color, 1, m_GBuffer[1]);
m_GBufferRTT->AttachTexture(nzAttachmentPoint_Color, 2, m_GBuffer[2]);
// Texture 3 : Emission map ?
m_GBufferRTT->AttachBuffer(nzAttachmentPoint_DepthStencil, 0, m_depthStencilBuffer);
m_GBufferRTT->Unlock();
m_workRTT->Create(true);
for (unsigned int i = 0; i < 2; ++i)
catch (const std::exception& e)
{
m_workTextures[i]->Create(nzImageType_2D, nzPixelFormat_RGBA8, width, height);
m_workRTT->AttachTexture(nzAttachmentPoint_Color, i, m_workTextures[i]);
}
m_workRTT->AttachBuffer(nzAttachmentPoint_DepthStencil, 0, m_depthStencilBuffer);
m_workRTT->Unlock();
if (!m_workRTT->IsComplete() || !m_GBufferRTT->IsComplete())
{
NazaraError("Incomplete RTT");
NazaraError("Failed to create G-Buffer RTT: " + String(e.what()));
return false;
}
return true;
}
catch (const std::exception& e)
const DeferredGeometryPass::ShaderUniforms* DeferredGeometryPass::GetShaderUniforms(const Shader* shader) const
{
NazaraError("Failed to create G-Buffer RTT: " + NzString(e.what()));
return false;
}
}
auto it = m_shaderUniforms.find(shader);
if (it == m_shaderUniforms.end())
{
ShaderUniforms uniforms;
uniforms.shaderReleaseSlot.Connect(shader->OnShaderRelease, this, &DeferredGeometryPass::OnShaderInvalidated);
uniforms.shaderUniformInvalidatedSlot.Connect(shader->OnShaderUniformInvalidated, this, &DeferredGeometryPass::OnShaderInvalidated);
const NzDeferredGeometryPass::ShaderUniforms* NzDeferredGeometryPass::GetShaderUniforms(const NzShader* shader) const
{
auto it = m_shaderUniforms.find(shader);
if (it == m_shaderUniforms.end())
uniforms.eyePosition = shader->GetUniformLocation("EyePosition");
uniforms.sceneAmbient = shader->GetUniformLocation("SceneAmbient");
uniforms.textureOverlay = shader->GetUniformLocation("TextureOverlay");
it = m_shaderUniforms.emplace(shader, std::move(uniforms)).first;
}
return &it->second;
}
void DeferredGeometryPass::OnShaderInvalidated(const Shader* shader) const
{
ShaderUniforms uniforms;
uniforms.shaderReleaseSlot.Connect(shader->OnShaderRelease, this, &NzDeferredGeometryPass::OnShaderInvalidated);
uniforms.shaderUniformInvalidatedSlot.Connect(shader->OnShaderUniformInvalidated, this, &NzDeferredGeometryPass::OnShaderInvalidated);
uniforms.eyePosition = shader->GetUniformLocation("EyePosition");
uniforms.sceneAmbient = shader->GetUniformLocation("SceneAmbient");
uniforms.textureOverlay = shader->GetUniformLocation("TextureOverlay");
it = m_shaderUniforms.emplace(shader, std::move(uniforms)).first;
m_shaderUniforms.erase(shader);
}
return &it->second;
}
void NzDeferredGeometryPass::OnShaderInvalidated(const NzShader* shader) const
{
m_shaderUniforms.erase(shader);
}

View File

@@ -11,280 +11,283 @@
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
NzDeferredPhongLightingPass::NzDeferredPhongLightingPass() :
m_lightMeshesDrawing(false)
namespace Nz
{
m_directionalLightShader = NzShaderLibrary::Get("DeferredDirectionnalLight");
m_directionalLightShaderEyePositionLocation = m_directionalLightShader->GetUniformLocation("EyePosition");
m_directionalLightShaderSceneAmbientLocation = m_directionalLightShader->GetUniformLocation("SceneAmbient");
m_directionalLightUniforms.ubo = false;
m_directionalLightUniforms.locations.type = -1; // Type déjà connu
m_directionalLightUniforms.locations.color = m_directionalLightShader->GetUniformLocation("LightColor");
m_directionalLightUniforms.locations.factors = m_directionalLightShader->GetUniformLocation("LightFactors");
m_directionalLightUniforms.locations.parameters1 = m_directionalLightShader->GetUniformLocation("LightDirection");
m_directionalLightUniforms.locations.parameters2 = -1;
m_directionalLightUniforms.locations.parameters3 = -1;
m_pointSpotLightShader = NzShaderLibrary::Get("DeferredPointSpotLight");
m_pointSpotLightShaderDiscardLocation = m_pointSpotLightShader->GetUniformLocation("Discard");
m_pointSpotLightShaderEyePositionLocation = m_pointSpotLightShader->GetUniformLocation("EyePosition");
m_pointSpotLightShaderSceneAmbientLocation = m_pointSpotLightShader->GetUniformLocation("SceneAmbient");
m_pointSpotLightUniforms.ubo = false;
m_pointSpotLightUniforms.locations.type = m_pointSpotLightShader->GetUniformLocation("LightType");
m_pointSpotLightUniforms.locations.color = m_pointSpotLightShader->GetUniformLocation("LightColor");
m_pointSpotLightUniforms.locations.factors = m_pointSpotLightShader->GetUniformLocation("LightFactors");
m_pointSpotLightUniforms.locations.parameters1 = m_pointSpotLightShader->GetUniformLocation("LightParameters1");
m_pointSpotLightUniforms.locations.parameters2 = m_pointSpotLightShader->GetUniformLocation("LightParameters2");
m_pointSpotLightUniforms.locations.parameters3 = m_pointSpotLightShader->GetUniformLocation("LightParameters3");
m_pointSampler.SetAnisotropyLevel(1);
m_pointSampler.SetFilterMode(nzSamplerFilter_Nearest);
m_pointSampler.SetWrapMode(nzSamplerWrap_Clamp);
m_cone = NzMesh::New();
m_cone->CreateStatic();
m_coneMesh = static_cast<NzStaticMesh*>(m_cone->BuildSubMesh(NzPrimitive::Cone(1.f, 1.f, 16, NzMatrix4f::Rotate(NzEulerAnglesf(90.f, 0.f, 0.f)))));
m_sphere = NzMesh::New();
m_sphere->CreateStatic();
m_sphereMesh = static_cast<NzStaticMesh*>(m_sphere->BuildSubMesh(NzPrimitive::IcoSphere(1.f, 1)));
}
NzDeferredPhongLightingPass::~NzDeferredPhongLightingPass() = default;
void NzDeferredPhongLightingPass::EnableLightMeshesDrawing(bool enable)
{
m_lightMeshesDrawing = enable;
}
bool NzDeferredPhongLightingPass::IsLightMeshesDrawingEnabled() const
{
return m_lightMeshesDrawing;
}
bool NzDeferredPhongLightingPass::Process(const NzSceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{
NazaraAssert(sceneData.viewer, "Invalid viewer");
NazaraUnused(secondWorkTexture);
m_workRTT->SetColorTarget(firstWorkTexture);
NzRenderer::SetTarget(m_workRTT);
NzRenderer::SetViewport(NzRecti(0, 0, m_dimensions.x, m_dimensions.y));
NzRenderer::SetTexture(0, m_GBuffer[0]);
NzRenderer::SetTextureSampler(0, m_pointSampler);
NzRenderer::SetTexture(1, m_GBuffer[1]);
NzRenderer::SetTextureSampler(1, m_pointSampler);
NzRenderer::SetTexture(2, m_GBuffer[2]);
NzRenderer::SetTextureSampler(2, m_pointSampler);
NzRenderer::SetClearColor(NzColor::Black);
NzRenderer::Clear(nzRendererBuffer_Color);
NzRenderStates lightStates;
lightStates.dstBlend = nzBlendFunc_One;
lightStates.srcBlend = nzBlendFunc_One;
lightStates.parameters[nzRendererParameter_Blend] = true;
lightStates.parameters[nzRendererParameter_DepthBuffer] = false;
lightStates.parameters[nzRendererParameter_DepthWrite] = false;
// Directional lights
if (!m_renderQueue->directionalLights.empty())
DeferredPhongLightingPass::DeferredPhongLightingPass() :
m_lightMeshesDrawing(false)
{
NzRenderer::SetRenderStates(lightStates);
NzRenderer::SetShader(m_directionalLightShader);
m_directionalLightShader->SendColor(m_directionalLightShaderSceneAmbientLocation, sceneData.ambientColor);
m_directionalLightShader->SendVector(m_directionalLightShaderEyePositionLocation, sceneData.viewer->GetEyePosition());
m_directionalLightShader = ShaderLibrary::Get("DeferredDirectionnalLight");
m_directionalLightShaderEyePositionLocation = m_directionalLightShader->GetUniformLocation("EyePosition");
m_directionalLightShaderSceneAmbientLocation = m_directionalLightShader->GetUniformLocation("SceneAmbient");
for (auto& light : m_renderQueue->directionalLights)
{
m_directionalLightShader->SendColor(m_directionalLightUniforms.locations.color, light.color);
m_directionalLightShader->SendVector(m_directionalLightUniforms.locations.factors, NzVector2f(light.ambientFactor, light.diffuseFactor));
m_directionalLightShader->SendVector(m_directionalLightUniforms.locations.parameters1, NzVector4f(light.direction));
m_directionalLightUniforms.ubo = false;
m_directionalLightUniforms.locations.type = -1; // Type déjà connu
m_directionalLightUniforms.locations.color = m_directionalLightShader->GetUniformLocation("LightColor");
m_directionalLightUniforms.locations.factors = m_directionalLightShader->GetUniformLocation("LightFactors");
m_directionalLightUniforms.locations.parameters1 = m_directionalLightShader->GetUniformLocation("LightDirection");
m_directionalLightUniforms.locations.parameters2 = -1;
m_directionalLightUniforms.locations.parameters3 = -1;
NzRenderer::DrawFullscreenQuad();
}
m_pointSpotLightShader = ShaderLibrary::Get("DeferredPointSpotLight");
m_pointSpotLightShaderDiscardLocation = m_pointSpotLightShader->GetUniformLocation("Discard");
m_pointSpotLightShaderEyePositionLocation = m_pointSpotLightShader->GetUniformLocation("EyePosition");
m_pointSpotLightShaderSceneAmbientLocation = m_pointSpotLightShader->GetUniformLocation("SceneAmbient");
m_pointSpotLightUniforms.ubo = false;
m_pointSpotLightUniforms.locations.type = m_pointSpotLightShader->GetUniformLocation("LightType");
m_pointSpotLightUniforms.locations.color = m_pointSpotLightShader->GetUniformLocation("LightColor");
m_pointSpotLightUniforms.locations.factors = m_pointSpotLightShader->GetUniformLocation("LightFactors");
m_pointSpotLightUniforms.locations.parameters1 = m_pointSpotLightShader->GetUniformLocation("LightParameters1");
m_pointSpotLightUniforms.locations.parameters2 = m_pointSpotLightShader->GetUniformLocation("LightParameters2");
m_pointSpotLightUniforms.locations.parameters3 = m_pointSpotLightShader->GetUniformLocation("LightParameters3");
m_pointSampler.SetAnisotropyLevel(1);
m_pointSampler.SetFilterMode(SamplerFilter_Nearest);
m_pointSampler.SetWrapMode(SamplerWrap_Clamp);
m_cone = Mesh::New();
m_cone->CreateStatic();
m_coneMesh = static_cast<StaticMesh*>(m_cone->BuildSubMesh(Primitive::Cone(1.f, 1.f, 16, Matrix4f::Rotate(EulerAnglesf(90.f, 0.f, 0.f)))));
m_sphere = Mesh::New();
m_sphere->CreateStatic();
m_sphereMesh = static_cast<StaticMesh*>(m_sphere->BuildSubMesh(Primitive::IcoSphere(1.f, 1)));
}
// Point lights/Spot lights
if (!m_renderQueue->pointLights.empty() || !m_renderQueue->spotLights.empty())
DeferredPhongLightingPass::~DeferredPhongLightingPass() = default;
void DeferredPhongLightingPass::EnableLightMeshesDrawing(bool enable)
{
// http://www.altdevblogaday.com/2011/08/08/stencil-buffer-optimisation-for-deferred-lights/
lightStates.parameters[nzRendererParameter_StencilTest] = true;
lightStates.faceCulling = nzFaceSide_Front;
lightStates.backFace.stencilMask = 0xFF;
lightStates.backFace.stencilReference = 0;
lightStates.backFace.stencilFail = nzStencilOperation_Keep;
lightStates.backFace.stencilPass = nzStencilOperation_Keep;
lightStates.backFace.stencilZFail = nzStencilOperation_Invert;
lightStates.frontFace.stencilMask = 0xFF;
lightStates.frontFace.stencilReference = 0;
lightStates.frontFace.stencilFail = nzStencilOperation_Keep;
lightStates.frontFace.stencilPass = nzStencilOperation_Keep;
lightStates.frontFace.stencilZFail = nzStencilOperation_Invert;
m_lightMeshesDrawing = enable;
}
NzRenderer::SetRenderStates(lightStates);
bool DeferredPhongLightingPass::IsLightMeshesDrawingEnabled() const
{
return m_lightMeshesDrawing;
}
NzRenderer::SetShader(m_pointSpotLightShader);
m_pointSpotLightShader->SendColor(m_pointSpotLightShaderSceneAmbientLocation, sceneData.ambientColor);
m_pointSpotLightShader->SendVector(m_pointSpotLightShaderEyePositionLocation, sceneData.viewer->GetEyePosition());
bool DeferredPhongLightingPass::Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned secondWorkTexture) const
{
NazaraAssert(sceneData.viewer, "Invalid viewer");
NazaraUnused(secondWorkTexture);
NzMatrix4f lightMatrix;
lightMatrix.MakeIdentity();
if (!m_renderQueue->pointLights.empty())
m_workRTT->SetColorTarget(firstWorkTexture);
Renderer::SetTarget(m_workRTT);
Renderer::SetViewport(Recti(0, 0, m_dimensions.x, m_dimensions.y));
Renderer::SetTexture(0, m_GBuffer[0]);
Renderer::SetTextureSampler(0, m_pointSampler);
Renderer::SetTexture(1, m_GBuffer[1]);
Renderer::SetTextureSampler(1, m_pointSampler);
Renderer::SetTexture(2, m_GBuffer[2]);
Renderer::SetTextureSampler(2, m_pointSampler);
Renderer::SetClearColor(Color::Black);
Renderer::Clear(RendererBuffer_Color);
RenderStates lightStates;
lightStates.dstBlend = BlendFunc_One;
lightStates.srcBlend = BlendFunc_One;
lightStates.parameters[RendererParameter_Blend] = true;
lightStates.parameters[RendererParameter_DepthBuffer] = false;
lightStates.parameters[RendererParameter_DepthWrite] = false;
// Directional lights
if (!m_renderQueue->directionalLights.empty())
{
const NzIndexBuffer* indexBuffer = m_sphereMesh->GetIndexBuffer();
NzRenderer::SetIndexBuffer(indexBuffer);
NzRenderer::SetVertexBuffer(m_sphereMesh->GetVertexBuffer());
Renderer::SetRenderStates(lightStates);
Renderer::SetShader(m_directionalLightShader);
m_directionalLightShader->SendColor(m_directionalLightShaderSceneAmbientLocation, sceneData.ambientColor);
m_directionalLightShader->SendVector(m_directionalLightShaderEyePositionLocation, sceneData.viewer->GetEyePosition());
m_pointSpotLightShader->SendInteger(m_pointSpotLightUniforms.locations.type, nzLightType_Point);
for (const auto& light : m_renderQueue->pointLights)
for (auto& light : m_renderQueue->directionalLights)
{
m_pointSpotLightShader->SendColor(m_pointSpotLightUniforms.locations.color, light.color);
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.factors, NzVector2f(light.ambientFactor, light.diffuseFactor));
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters1, NzVector4f(light.position, light.attenuation));
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters2, NzVector4f(0.f, 0.f, 0.f, light.invRadius));
m_directionalLightShader->SendColor(m_directionalLightUniforms.locations.color, light.color);
m_directionalLightShader->SendVector(m_directionalLightUniforms.locations.factors, Vector2f(light.ambientFactor, light.diffuseFactor));
m_directionalLightShader->SendVector(m_directionalLightUniforms.locations.parameters1, Vector4f(light.direction));
lightMatrix.SetScale(NzVector3f(light.radius * 1.1f)); // Pour corriger les imperfections liées à la sphère
lightMatrix.SetTranslation(light.position);
NzRenderer::SetMatrix(nzMatrixType_World, lightMatrix);
// Rendu de la sphère dans le stencil buffer
NzRenderer::Enable(nzRendererParameter_ColorWrite, false);
NzRenderer::Enable(nzRendererParameter_DepthBuffer, true);
NzRenderer::Enable(nzRendererParameter_FaceCulling, false);
NzRenderer::SetStencilCompareFunction(nzRendererComparison_Always);
m_pointSpotLightShader->SendBoolean(m_pointSpotLightShaderDiscardLocation, true);
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount());
// Rendu de la sphère comme zone d'effet
NzRenderer::Enable(nzRendererParameter_ColorWrite, true);
NzRenderer::Enable(nzRendererParameter_DepthBuffer, false);
NzRenderer::Enable(nzRendererParameter_FaceCulling, true);
NzRenderer::SetStencilCompareFunction(nzRendererComparison_NotEqual, nzFaceSide_Back);
NzRenderer::SetStencilPassOperation(nzStencilOperation_Zero, nzFaceSide_Back);
m_pointSpotLightShader->SendBoolean(m_pointSpotLightShaderDiscardLocation, false);
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount());
Renderer::DrawFullscreenQuad();
}
}
if (m_lightMeshesDrawing)
// Point lights/Spot lights
if (!m_renderQueue->pointLights.empty() || !m_renderQueue->spotLights.empty())
{
// http://www.altdevblogaday.com/2011/08/08/stencil-buffer-optimisation-for-deferred-lights/
lightStates.parameters[RendererParameter_StencilTest] = true;
lightStates.faceCulling = FaceSide_Front;
lightStates.backFace.stencilMask = 0xFF;
lightStates.backFace.stencilReference = 0;
lightStates.backFace.stencilFail = StencilOperation_Keep;
lightStates.backFace.stencilPass = StencilOperation_Keep;
lightStates.backFace.stencilZFail = StencilOperation_Invert;
lightStates.frontFace.stencilMask = 0xFF;
lightStates.frontFace.stencilReference = 0;
lightStates.frontFace.stencilFail = StencilOperation_Keep;
lightStates.frontFace.stencilPass = StencilOperation_Keep;
lightStates.frontFace.stencilZFail = StencilOperation_Invert;
Renderer::SetRenderStates(lightStates);
Renderer::SetShader(m_pointSpotLightShader);
m_pointSpotLightShader->SendColor(m_pointSpotLightShaderSceneAmbientLocation, sceneData.ambientColor);
m_pointSpotLightShader->SendVector(m_pointSpotLightShaderEyePositionLocation, sceneData.viewer->GetEyePosition());
Matrix4f lightMatrix;
lightMatrix.MakeIdentity();
if (!m_renderQueue->pointLights.empty())
{
NzRenderer::Enable(nzRendererParameter_DepthBuffer, true);
NzRenderer::Enable(nzRendererParameter_DepthWrite, true);
NzRenderer::Enable(nzRendererParameter_FaceCulling, false);
NzRenderer::Enable(nzRendererParameter_StencilTest, false);
NzRenderer::SetFaceFilling(nzFaceFilling_Line);
const IndexBuffer* indexBuffer = m_sphereMesh->GetIndexBuffer();
Renderer::SetIndexBuffer(indexBuffer);
Renderer::SetVertexBuffer(m_sphereMesh->GetVertexBuffer());
const NzShader* shader = NzShaderLibrary::Get("DebugSimple");
static int colorLocation = shader->GetUniformLocation("Color");
NzRenderer::SetShader(shader);
m_pointSpotLightShader->SendInteger(m_pointSpotLightUniforms.locations.type, LightType_Point);
for (const auto& light : m_renderQueue->pointLights)
{
lightMatrix.SetScale(NzVector3f(light.radius * 1.1f)); // Pour corriger les imperfections liées à la sphère
m_pointSpotLightShader->SendColor(m_pointSpotLightUniforms.locations.color, light.color);
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.factors, Vector2f(light.ambientFactor, light.diffuseFactor));
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters1, Vector4f(light.position, light.attenuation));
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters2, Vector4f(0.f, 0.f, 0.f, light.invRadius));
lightMatrix.SetScale(Vector3f(light.radius * 1.1f)); // Pour corriger les imperfections liées à la sphère
lightMatrix.SetTranslation(light.position);
NzRenderer::SetMatrix(nzMatrixType_World, lightMatrix);
Renderer::SetMatrix(MatrixType_World, lightMatrix);
shader->SendColor(colorLocation, light.color);
// Rendu de la sphère dans le stencil buffer
Renderer::Enable(RendererParameter_ColorWrite, false);
Renderer::Enable(RendererParameter_DepthBuffer, true);
Renderer::Enable(RendererParameter_FaceCulling, false);
Renderer::SetStencilCompareFunction(RendererComparison_Always);
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount());
m_pointSpotLightShader->SendBoolean(m_pointSpotLightShaderDiscardLocation, true);
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount());
// Rendu de la sphère comme zone d'effet
Renderer::Enable(RendererParameter_ColorWrite, true);
Renderer::Enable(RendererParameter_DepthBuffer, false);
Renderer::Enable(RendererParameter_FaceCulling, true);
Renderer::SetStencilCompareFunction(RendererComparison_NotEqual, FaceSide_Back);
Renderer::SetStencilPassOperation(StencilOperation_Zero, FaceSide_Back);
m_pointSpotLightShader->SendBoolean(m_pointSpotLightShaderDiscardLocation, false);
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount());
}
NzRenderer::Enable(nzRendererParameter_DepthBuffer, false);
NzRenderer::Enable(nzRendererParameter_DepthWrite, false);
NzRenderer::Enable(nzRendererParameter_FaceCulling, true);
NzRenderer::Enable(nzRendererParameter_StencilTest, true);
NzRenderer::SetFaceFilling(nzFaceFilling_Fill);
}
}
if (m_lightMeshesDrawing)
{
Renderer::Enable(RendererParameter_DepthBuffer, true);
Renderer::Enable(RendererParameter_DepthWrite, true);
Renderer::Enable(RendererParameter_FaceCulling, false);
Renderer::Enable(RendererParameter_StencilTest, false);
Renderer::SetFaceFilling(FaceFilling_Line);
if (!m_renderQueue->spotLights.empty())
{
const NzIndexBuffer* indexBuffer = m_coneMesh->GetIndexBuffer();
NzRenderer::SetIndexBuffer(indexBuffer);
NzRenderer::SetVertexBuffer(m_coneMesh->GetVertexBuffer());
const Shader* shader = ShaderLibrary::Get("DebugSimple");
static int colorLocation = shader->GetUniformLocation("Color");
m_pointSpotLightShader->SendInteger(m_pointSpotLightUniforms.locations.type, nzLightType_Spot);
for (const auto& light : m_renderQueue->spotLights)
{
m_pointSpotLightShader->SendColor(m_pointSpotLightUniforms.locations.color, light.color);
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.factors, NzVector2f(light.ambientFactor, light.diffuseFactor));
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters1, NzVector4f(light.position, light.attenuation));
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters2, NzVector4f(light.direction, light.invRadius));
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters3, NzVector2f(light.innerAngleCosine, light.outerAngleCosine));
Renderer::SetShader(shader);
for (const auto& light : m_renderQueue->pointLights)
{
lightMatrix.SetScale(Vector3f(light.radius * 1.1f)); // Pour corriger les imperfections liées à la sphère
lightMatrix.SetTranslation(light.position);
float baseRadius = light.radius * light.outerAngleTangent * 1.1f;
lightMatrix.MakeTransform(light.position, NzQuaternionf::RotationBetween(NzVector3f::Forward(), light.direction), NzVector3f(baseRadius, baseRadius, light.radius));
Renderer::SetMatrix(MatrixType_World, lightMatrix);
NzRenderer::SetMatrix(nzMatrixType_World, lightMatrix);
shader->SendColor(colorLocation, light.color);
// Rendu de la sphère dans le stencil buffer
NzRenderer::Enable(nzRendererParameter_ColorWrite, false);
NzRenderer::Enable(nzRendererParameter_DepthBuffer, true);
NzRenderer::Enable(nzRendererParameter_FaceCulling, false);
NzRenderer::SetStencilCompareFunction(nzRendererComparison_Always);
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount());
}
m_pointSpotLightShader->SendBoolean(m_pointSpotLightShaderDiscardLocation, true);
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount());
// Rendu de la sphère comme zone d'effet
NzRenderer::Enable(nzRendererParameter_ColorWrite, true);
NzRenderer::Enable(nzRendererParameter_DepthBuffer, false);
NzRenderer::Enable(nzRendererParameter_FaceCulling, true);
NzRenderer::SetFaceCulling(nzFaceSide_Front);
NzRenderer::SetStencilCompareFunction(nzRendererComparison_NotEqual, nzFaceSide_Back);
NzRenderer::SetStencilPassOperation(nzStencilOperation_Zero, nzFaceSide_Back);
m_pointSpotLightShader->SendBoolean(m_pointSpotLightShaderDiscardLocation, false);
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount());
Renderer::Enable(RendererParameter_DepthBuffer, false);
Renderer::Enable(RendererParameter_DepthWrite, false);
Renderer::Enable(RendererParameter_FaceCulling, true);
Renderer::Enable(RendererParameter_StencilTest, true);
Renderer::SetFaceFilling(FaceFilling_Fill);
}
}
if (m_lightMeshesDrawing)
if (!m_renderQueue->spotLights.empty())
{
NzRenderer::Enable(nzRendererParameter_DepthBuffer, true);
NzRenderer::Enable(nzRendererParameter_DepthWrite, true);
NzRenderer::Enable(nzRendererParameter_FaceCulling, false);
NzRenderer::Enable(nzRendererParameter_StencilTest, false);
NzRenderer::SetFaceFilling(nzFaceFilling_Line);
const IndexBuffer* indexBuffer = m_coneMesh->GetIndexBuffer();
Renderer::SetIndexBuffer(indexBuffer);
Renderer::SetVertexBuffer(m_coneMesh->GetVertexBuffer());
const NzShader* shader = NzShaderLibrary::Get("DebugSimple");
static int colorLocation = shader->GetUniformLocation("Color");
NzRenderer::SetShader(shader);
m_pointSpotLightShader->SendInteger(m_pointSpotLightUniforms.locations.type, LightType_Spot);
for (const auto& light : m_renderQueue->spotLights)
{
m_pointSpotLightShader->SendColor(m_pointSpotLightUniforms.locations.color, light.color);
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.factors, Vector2f(light.ambientFactor, light.diffuseFactor));
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters1, Vector4f(light.position, light.attenuation));
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters2, Vector4f(light.direction, light.invRadius));
m_pointSpotLightShader->SendVector(m_pointSpotLightUniforms.locations.parameters3, Vector2f(light.innerAngleCosine, light.outerAngleCosine));
float baseRadius = light.radius * light.outerAngleTangent * 1.1f;
lightMatrix.MakeTransform(light.position, NzQuaternionf::RotationBetween(NzVector3f::Forward(), light.direction), NzVector3f(baseRadius, baseRadius, light.radius));
lightMatrix.MakeTransform(light.position, Quaternionf::RotationBetween(Vector3f::Forward(), light.direction), Vector3f(baseRadius, baseRadius, light.radius));
NzRenderer::SetMatrix(nzMatrixType_World, lightMatrix);
Renderer::SetMatrix(MatrixType_World, lightMatrix);
shader->SendColor(colorLocation, light.color);
// Rendu de la sphère dans le stencil buffer
Renderer::Enable(RendererParameter_ColorWrite, false);
Renderer::Enable(RendererParameter_DepthBuffer, true);
Renderer::Enable(RendererParameter_FaceCulling, false);
Renderer::SetStencilCompareFunction(RendererComparison_Always);
NzRenderer::DrawIndexedPrimitives(nzPrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount());
m_pointSpotLightShader->SendBoolean(m_pointSpotLightShaderDiscardLocation, true);
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount());
// Rendu de la sphère comme zone d'effet
Renderer::Enable(RendererParameter_ColorWrite, true);
Renderer::Enable(RendererParameter_DepthBuffer, false);
Renderer::Enable(RendererParameter_FaceCulling, true);
Renderer::SetFaceCulling(FaceSide_Front);
Renderer::SetStencilCompareFunction(RendererComparison_NotEqual, FaceSide_Back);
Renderer::SetStencilPassOperation(StencilOperation_Zero, FaceSide_Back);
m_pointSpotLightShader->SendBoolean(m_pointSpotLightShaderDiscardLocation, false);
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount());
}
NzRenderer::Enable(nzRendererParameter_DepthBuffer, false);
NzRenderer::Enable(nzRendererParameter_DepthWrite, false);
NzRenderer::Enable(nzRendererParameter_FaceCulling, true);
NzRenderer::Enable(nzRendererParameter_StencilTest, true);
NzRenderer::SetFaceFilling(nzFaceFilling_Fill);
if (m_lightMeshesDrawing)
{
Renderer::Enable(RendererParameter_DepthBuffer, true);
Renderer::Enable(RendererParameter_DepthWrite, true);
Renderer::Enable(RendererParameter_FaceCulling, false);
Renderer::Enable(RendererParameter_StencilTest, false);
Renderer::SetFaceFilling(FaceFilling_Line);
const Shader* shader = ShaderLibrary::Get("DebugSimple");
static int colorLocation = shader->GetUniformLocation("Color");
Renderer::SetShader(shader);
for (const auto& light : m_renderQueue->spotLights)
{
float baseRadius = light.radius * light.outerAngleTangent * 1.1f;
lightMatrix.MakeTransform(light.position, Quaternionf::RotationBetween(Vector3f::Forward(), light.direction), Vector3f(baseRadius, baseRadius, light.radius));
Renderer::SetMatrix(MatrixType_World, lightMatrix);
shader->SendColor(colorLocation, light.color);
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, indexBuffer->GetIndexCount());
}
Renderer::Enable(RendererParameter_DepthBuffer, false);
Renderer::Enable(RendererParameter_DepthWrite, false);
Renderer::Enable(RendererParameter_FaceCulling, true);
Renderer::Enable(RendererParameter_StencilTest, true);
Renderer::SetFaceFilling(FaceFilling_Fill);
}
}
Renderer::Enable(RendererParameter_StencilTest, false);
}
NzRenderer::Enable(nzRendererParameter_StencilTest, false);
return true;
}
return true;
}

View File

@@ -7,42 +7,45 @@
#include <Nazara/Graphics/DeferredRenderTechnique.hpp>
#include <Nazara/Graphics/Debug.hpp>
NzDeferredRenderPass::NzDeferredRenderPass() :
m_enabled(true)
namespace Nz
{
}
NzDeferredRenderPass::~NzDeferredRenderPass() = default;
void NzDeferredRenderPass::Enable(bool enable)
{
m_enabled = enable;
}
void NzDeferredRenderPass::Initialize(NzDeferredRenderTechnique* technique)
{
m_deferredTechnique = technique;
m_renderQueue = static_cast<NzDeferredRenderQueue*>(technique->GetRenderQueue());
m_depthStencilBuffer = technique->GetDepthStencilBuffer();
m_GBufferRTT = technique->GetGBufferRTT();
for (unsigned int i = 0; i < 3; ++i)
m_GBuffer[i] = technique->GetGBuffer(i);
m_workRTT = technique->GetWorkRTT();
for (unsigned int i = 0; i < 2; ++i)
m_workTextures[i] = technique->GetWorkTexture(i);
}
bool NzDeferredRenderPass::IsEnabled() const
{
return m_enabled;
}
bool NzDeferredRenderPass::Resize(const NzVector2ui& dimensions)
{
m_dimensions = dimensions;
return true;
DeferredRenderPass::DeferredRenderPass() :
m_enabled(true)
{
}
DeferredRenderPass::~DeferredRenderPass() = default;
void DeferredRenderPass::Enable(bool enable)
{
m_enabled = enable;
}
void DeferredRenderPass::Initialize(DeferredRenderTechnique* technique)
{
m_deferredTechnique = technique;
m_renderQueue = static_cast<DeferredRenderQueue*>(technique->GetRenderQueue());
m_depthStencilBuffer = technique->GetDepthStencilBuffer();
m_GBufferRTT = technique->GetGBufferRTT();
for (unsigned int i = 0; i < 3; ++i)
m_GBuffer[i] = technique->GetGBuffer(i);
m_workRTT = technique->GetWorkRTT();
for (unsigned int i = 0; i < 2; ++i)
m_workTextures[i] = technique->GetWorkTexture(i);
}
bool DeferredRenderPass::IsEnabled() const
{
return m_enabled;
}
bool DeferredRenderPass::Resize(const Vector2ui& dimensions)
{
m_dimensions = dimensions;
return true;
}
}

View File

@@ -10,190 +10,193 @@
///TODO: Rendre les billboards via Deferred Shading si possible
NzDeferredRenderQueue::NzDeferredRenderQueue(NzForwardRenderQueue* forwardQueue) :
m_forwardQueue(forwardQueue)
namespace Nz
{
}
void NzDeferredRenderQueue::AddBillboard(const NzMaterial* material, const NzVector3f& position, const NzVector2f& size, const NzVector2f& sinCos, const NzColor& color)
{
m_forwardQueue->AddBillboard(material, position, size, sinCos, color);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const NzColor> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const NzColor> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, colorPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const NzVector2f> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, alphaPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const NzColor> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const NzVector2f> sinCosPtr, NzSparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const NzColor> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, colorPtr);
}
void NzDeferredRenderQueue::AddBillboards(const NzMaterial* material, unsigned int count, NzSparsePtr<const NzVector3f> positionPtr, NzSparsePtr<const float> sizePtr, NzSparsePtr<const float> anglePtr, NzSparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, alphaPtr);
}
void NzDeferredRenderQueue::AddDrawable(const NzDrawable* drawable)
{
m_forwardQueue->AddDrawable(drawable);
}
void NzDeferredRenderQueue::AddMesh(const NzMaterial* material, const NzMeshData& meshData, const NzBoxf& meshAABB, const NzMatrix4f& transformMatrix)
{
if (material->IsEnabled(nzRendererParameter_Blend))
// Un matériau transparent ? J'aime pas, va voir dans la forward queue si j'y suis
m_forwardQueue->AddMesh(material, meshData, meshAABB, transformMatrix);
else
DeferredRenderQueue::DeferredRenderQueue(ForwardRenderQueue* forwardQueue) :
m_forwardQueue(forwardQueue)
{
auto it = opaqueModels.find(material);
if (it == opaqueModels.end())
{
BatchedModelEntry entry;
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &NzDeferredRenderQueue::OnMaterialInvalidation);
it = opaqueModels.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedModelEntry& entry = it->second;
entry.enabled = true;
auto& meshMap = entry.meshMap;
auto it2 = meshMap.find(meshData);
if (it2 == meshMap.end())
{
MeshInstanceEntry instanceEntry;
if (meshData.indexBuffer)
instanceEntry.indexBufferReleaseSlot.Connect(meshData.indexBuffer->OnIndexBufferRelease, this, &NzDeferredRenderQueue::OnIndexBufferInvalidation);
instanceEntry.vertexBufferReleaseSlot.Connect(meshData.vertexBuffer->OnVertexBufferRelease, this, &NzDeferredRenderQueue::OnVertexBufferInvalidation);
it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first;
}
// On ajoute la matrice à la liste des instances de cet objet
std::vector<NzMatrix4f>& instances = it2->second.instances;
instances.push_back(transformMatrix);
// Avons-nous suffisamment d'instances pour que le coût d'utilisation de l'instancing soit payé ?
if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT)
entry.instancingEnabled = true; // Apparemment oui, activons l'instancing avec ce matériau
}
}
void NzDeferredRenderQueue::AddSprites(const NzMaterial* material, const NzVertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const NzTexture* overlay)
{
m_forwardQueue->AddSprites(material, vertices, spriteCount, overlay);
}
void NzDeferredRenderQueue::Clear(bool fully)
{
NzAbstractRenderQueue::Clear(fully);
if (fully)
opaqueModels.clear();
m_forwardQueue->Clear(fully);
}
void NzDeferredRenderQueue::OnIndexBufferInvalidation(const NzIndexBuffer* indexBuffer)
{
for (auto& modelPair : opaqueModels)
void DeferredRenderQueue::AddBillboard(const Material* material, const Vector3f& position, const Vector2f& size, const Vector2f& sinCos, const Color& color)
{
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
m_forwardQueue->AddBillboard(material, position, size, sinCos, color);
}
void DeferredRenderQueue::AddBillboards(const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
}
void DeferredRenderQueue::AddBillboards(const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr);
}
void DeferredRenderQueue::AddBillboards(const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, colorPtr);
}
void DeferredRenderQueue::AddBillboards(const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const Vector2f> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, alphaPtr);
}
void DeferredRenderQueue::AddBillboards(const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const Color> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, colorPtr);
}
void DeferredRenderQueue::AddBillboards(const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const Vector2f> sinCosPtr, SparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr);
}
void DeferredRenderQueue::AddBillboards(const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const Color> colorPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, colorPtr);
}
void DeferredRenderQueue::AddBillboards(const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr)
{
m_forwardQueue->AddBillboards(material, count, positionPtr, sizePtr, anglePtr, alphaPtr);
}
void DeferredRenderQueue::AddDrawable(const Drawable* drawable)
{
m_forwardQueue->AddDrawable(drawable);
}
void DeferredRenderQueue::AddMesh(const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix)
{
if (material->IsEnabled(RendererParameter_Blend))
// Un matériau transparent ? J'aime pas, va voir dans la forward queue si j'y suis
m_forwardQueue->AddMesh(material, meshData, meshAABB, transformMatrix);
else
{
const NzMeshData& renderData = it->first;
if (renderData.indexBuffer == indexBuffer)
it = meshes.erase(it);
else
++it;
auto it = opaqueModels.find(material);
if (it == opaqueModels.end())
{
BatchedModelEntry entry;
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &DeferredRenderQueue::OnMaterialInvalidation);
it = opaqueModels.insert(std::make_pair(material, std::move(entry))).first;
}
BatchedModelEntry& entry = it->second;
entry.enabled = true;
auto& meshMap = entry.meshMap;
auto it2 = meshMap.find(meshData);
if (it2 == meshMap.end())
{
MeshInstanceEntry instanceEntry;
if (meshData.indexBuffer)
instanceEntry.indexBufferReleaseSlot.Connect(meshData.indexBuffer->OnIndexBufferRelease, this, &DeferredRenderQueue::OnIndexBufferInvalidation);
instanceEntry.vertexBufferReleaseSlot.Connect(meshData.vertexBuffer->OnVertexBufferRelease, this, &DeferredRenderQueue::OnVertexBufferInvalidation);
it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first;
}
// On ajoute la matrice à la liste des instances de cet objet
std::vector<Matrix4f>& instances = it2->second.instances;
instances.push_back(transformMatrix);
// Avons-nous suffisamment d'instances pour que le coût d'utilisation de l'instancing soit payé ?
if (instances.size() >= NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT)
entry.instancingEnabled = true; // Apparemment oui, activons l'instancing avec ce matériau
}
}
}
void NzDeferredRenderQueue::OnMaterialInvalidation(const NzMaterial* material)
{
opaqueModels.erase(material);
}
void NzDeferredRenderQueue::OnVertexBufferInvalidation(const NzVertexBuffer* vertexBuffer)
{
for (auto& modelPair : opaqueModels)
void DeferredRenderQueue::AddSprites(const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay)
{
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
m_forwardQueue->AddSprites(material, vertices, spriteCount, overlay);
}
void DeferredRenderQueue::Clear(bool fully)
{
AbstractRenderQueue::Clear(fully);
if (fully)
opaqueModels.clear();
m_forwardQueue->Clear(fully);
}
void DeferredRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer)
{
for (auto& modelPair : opaqueModels)
{
const NzMeshData& renderData = it->first;
if (renderData.vertexBuffer == vertexBuffer)
it = meshes.erase(it);
else
++it;
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const MeshData& renderData = it->first;
if (renderData.indexBuffer == indexBuffer)
it = meshes.erase(it);
else
++it;
}
}
}
}
bool NzDeferredRenderQueue::BatchedModelMaterialComparator::operator()(const NzMaterial* mat1, const NzMaterial* mat2) const
{
const NzUberShader* uberShader1 = mat1->GetShader();
const NzUberShader* uberShader2 = mat2->GetShader();
if (uberShader1 != uberShader2)
return uberShader1 < uberShader2;
const NzShader* shader1 = mat1->GetShaderInstance(nzShaderFlags_Deferred)->GetShader();
const NzShader* shader2 = mat2->GetShaderInstance(nzShaderFlags_Deferred)->GetShader();
if (shader1 != shader2)
return shader1 < shader2;
const NzTexture* diffuseMap1 = mat1->GetDiffuseMap();
const NzTexture* diffuseMap2 = mat2->GetDiffuseMap();
if (diffuseMap1 != diffuseMap2)
return diffuseMap1 < diffuseMap2;
return mat1 < mat2;
}
bool NzDeferredRenderQueue::MeshDataComparator::operator()(const NzMeshData& data1, const NzMeshData& data2) const
{
const NzBuffer* buffer1;
const NzBuffer* buffer2;
buffer1 = (data1.indexBuffer) ? data1.indexBuffer->GetBuffer() : nullptr;
buffer2 = (data2.indexBuffer) ? data2.indexBuffer->GetBuffer() : nullptr;
if (buffer1 != buffer2)
return buffer1 < buffer2;
buffer1 = data1.vertexBuffer->GetBuffer();
buffer2 = data2.vertexBuffer->GetBuffer();
if (buffer1 != buffer2)
return buffer1 < buffer2;
return data1.primitiveMode < data2.primitiveMode;
void DeferredRenderQueue::OnMaterialInvalidation(const Material* material)
{
opaqueModels.erase(material);
}
void DeferredRenderQueue::OnVertexBufferInvalidation(const VertexBuffer* vertexBuffer)
{
for (auto& modelPair : opaqueModels)
{
MeshInstanceContainer& meshes = modelPair.second.meshMap;
for (auto it = meshes.begin(); it != meshes.end();)
{
const MeshData& renderData = it->first;
if (renderData.vertexBuffer == vertexBuffer)
it = meshes.erase(it);
else
++it;
}
}
}
bool DeferredRenderQueue::BatchedModelMaterialComparator::operator()(const Material* mat1, const Material* mat2) const
{
const UberShader* uberShader1 = mat1->GetShader();
const UberShader* uberShader2 = mat2->GetShader();
if (uberShader1 != uberShader2)
return uberShader1 < uberShader2;
const Shader* shader1 = mat1->GetShaderInstance(ShaderFlags_Deferred)->GetShader();
const Shader* shader2 = mat2->GetShaderInstance(ShaderFlags_Deferred)->GetShader();
if (shader1 != shader2)
return shader1 < shader2;
const Texture* diffuseMap1 = mat1->GetDiffuseMap();
const Texture* diffuseMap2 = mat2->GetDiffuseMap();
if (diffuseMap1 != diffuseMap2)
return diffuseMap1 < diffuseMap2;
return mat1 < mat2;
}
bool DeferredRenderQueue::MeshDataComparator::operator()(const MeshData& data1, const MeshData& data2) const
{
const Buffer* buffer1;
const Buffer* buffer2;
buffer1 = (data1.indexBuffer) ? data1.indexBuffer->GetBuffer() : nullptr;
buffer2 = (data2.indexBuffer) ? data2.indexBuffer->GetBuffer() : nullptr;
if (buffer1 != buffer2)
return buffer1 < buffer2;
buffer1 = data1.vertexBuffer->GetBuffer();
buffer2 = data2.vertexBuffer->GetBuffer();
if (buffer1 != buffer2)
return buffer1 < buffer2;
return data1.primitiveMode < data2.primitiveMode;
}
}

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -10,115 +10,122 @@
#include <memory>
#include <Nazara/Graphics/Debug.hpp>
namespace
namespace Nz
{
nzTernary CheckStatic(NzInputStream& stream, const NzModelParameters& parameters)
namespace
{
NazaraUnused(stream);
NazaraUnused(parameters);
return nzTernary_Unknown;
}
bool LoadStatic(NzModel* model, NzInputStream& stream, const NzModelParameters& parameters)
{
NazaraUnused(parameters);
NzMeshRef mesh = NzMesh::New();
if (!mesh->LoadFromStream(stream, parameters.mesh))
Ternary CheckStatic(InputStream& stream, const ModelParameters& parameters)
{
NazaraError("Failed to load model mesh");
return false;
NazaraUnused(stream);
NazaraUnused(parameters);
return Ternary_Unknown;
}
if (mesh->IsAnimable())
bool LoadStatic(Model* model, InputStream& stream, const ModelParameters& parameters)
{
NazaraError("Can't load animated mesh into static model");
return false;
}
NazaraUnused(parameters);
model->Reset();
model->SetMesh(mesh);
if (parameters.loadMaterials)
{
unsigned int matCount = model->GetMaterialCount();
for (unsigned int i = 0; i < matCount; ++i)
MeshRef mesh = Mesh::New();
if (!mesh->LoadFromStream(stream, parameters.mesh))
{
NzString mat = mesh->GetMaterial(i);
if (!mat.IsEmpty())
NazaraError("Failed to load model mesh");
return false;
}
if (mesh->IsAnimable())
{
NazaraError("Can't load animated mesh into static model");
return false;
}
model->Reset();
model->SetMesh(mesh);
if (parameters.loadMaterials)
{
unsigned int matCount = model->GetMaterialCount();
for (unsigned int i = 0; i < matCount; ++i)
{
NzMaterialRef material = NzMaterial::New();
if (material->LoadFromFile(mat, parameters.material))
model->SetMaterial(i, material);
else
NazaraWarning("Failed to load material #" + NzString::Number(i));
String mat = mesh->GetMaterial(i);
if (!mat.IsEmpty())
{
MaterialRef material = Material::New();
if (material->LoadFromFile(mat, parameters.material))
model->SetMaterial(i, material);
else
NazaraWarning("Failed to load material #" + String::Number(i));
}
}
}
return true;
}
return true;
}
nzTernary CheckAnimated(NzInputStream& stream, const NzSkeletalModelParameters& parameters)
{
NazaraUnused(stream);
NazaraUnused(parameters);
return nzTernary_Unknown;
}
bool LoadAnimated(NzSkeletalModel* model, NzInputStream& stream, const NzSkeletalModelParameters& parameters)
{
NazaraUnused(parameters);
NzMeshRef mesh = NzMesh::New();
if (!mesh->LoadFromStream(stream, parameters.mesh))
Ternary CheckAnimated(InputStream& stream, const SkeletalModelParameters& parameters)
{
NazaraError("Failed to load model mesh");
return false;
NazaraUnused(stream);
NazaraUnused(parameters);
return Ternary_Unknown;
}
if (!mesh->IsAnimable())
bool LoadAnimated(SkeletalModel* model, InputStream& stream, const SkeletalModelParameters& parameters)
{
NazaraError("Can't load static mesh into animated model");
return false;
}
NazaraUnused(parameters);
model->Reset();
model->SetMesh(mesh);
if (parameters.loadMaterials)
{
unsigned int matCount = model->GetMaterialCount();
for (unsigned int i = 0; i < matCount; ++i)
MeshRef mesh = Mesh::New();
if (!mesh->LoadFromStream(stream, parameters.mesh))
{
NzString mat = mesh->GetMaterial(i);
if (!mat.IsEmpty())
NazaraError("Failed to load model mesh");
return false;
}
if (!mesh->IsAnimable())
{
NazaraError("Can't load static mesh into animated model");
return false;
}
model->Reset();
model->SetMesh(mesh);
if (parameters.loadMaterials)
{
unsigned int matCount = model->GetMaterialCount();
for (unsigned int i = 0; i < matCount; ++i)
{
NzMaterialRef material = NzMaterial::New();
if (material->LoadFromFile(mat, parameters.material))
model->SetMaterial(i, material);
else
NazaraWarning("Failed to load material #" + NzString::Number(i));
String mat = mesh->GetMaterial(i);
if (!mat.IsEmpty())
{
MaterialRef material = Material::New();
if (material->LoadFromFile(mat, parameters.material))
model->SetMaterial(i, material);
else
NazaraWarning("Failed to load material #" + String::Number(i));
}
}
}
return true;
}
}
namespace Loaders
{
void RegisterMesh()
{
ModelLoader::RegisterLoader(MeshLoader::IsExtensionSupported, CheckStatic, LoadStatic);
SkeletalModelLoader::RegisterLoader(MeshLoader::IsExtensionSupported, CheckAnimated, LoadAnimated);
}
return true;
void UnregisterMesh()
{
ModelLoader::UnregisterLoader(MeshLoader::IsExtensionSupported, CheckStatic, LoadStatic);
SkeletalModelLoader::UnregisterLoader(MeshLoader::IsExtensionSupported, CheckAnimated, LoadAnimated);
}
}
}
void NzLoaders_Mesh_Register()
{
NzModelLoader::RegisterLoader(NzMeshLoader::IsExtensionSupported, CheckStatic, LoadStatic);
NzSkeletalModelLoader::RegisterLoader(NzMeshLoader::IsExtensionSupported, CheckAnimated, LoadAnimated);
}
void NzLoaders_Mesh_Unregister()
{
NzModelLoader::UnregisterLoader(NzMeshLoader::IsExtensionSupported, CheckStatic, LoadStatic);
NzSkeletalModelLoader::UnregisterLoader(NzMeshLoader::IsExtensionSupported, CheckAnimated, LoadAnimated);
}

View File

@@ -9,7 +9,13 @@
#include <Nazara/Prerequesites.hpp>
void NzLoaders_Mesh_Register();
void NzLoaders_Mesh_Unregister();
namespace Nz
{
namespace Loaders
{
void RegisterMesh();
void UnregisterMesh();
}
}
#endif // NAZARA_LOADERS_MESH_HPP

View File

@@ -20,298 +20,304 @@
///TODO: N'avoir qu'un seul VertexBuffer communs à tous les meshes
namespace
namespace Nz
{
bool IsSupported(const NzString& extension)
namespace
{
return (extension == "obj");
}
nzTernary Check(NzInputStream& stream, const NzModelParameters& parameters)
{
NazaraUnused(stream);
NazaraUnused(parameters);
return nzTernary_Unknown;
}
bool LoadMaterials(NzModel* model, const NzString& filePath, const NzMaterialParams& parameters, const NzString* materials, const NzOBJParser::Mesh* meshes, unsigned int meshCount)
{
NzFile file(filePath);
if (!file.Open(nzOpenMode_ReadOnly | nzOpenMode_Text))
bool IsSupported(const String& extension)
{
NazaraError("Failed to open MTL file (" + file.GetPath() + ')');
return false;
return (extension == "obj");
}
NzMTLParser materialParser(file);
if (!materialParser.Parse())
Ternary Check(InputStream& stream, const ModelParameters& parameters)
{
NazaraError("MTL parser failed");
return false;
NazaraUnused(stream);
NazaraUnused(parameters);
return Ternary_Unknown;
}
std::unordered_map<NzString, NzMaterialRef> materialCache;
NzString baseDir = file.GetDirectory();
for (unsigned int i = 0; i < meshCount; ++i)
bool LoadMaterials(Model* model, const String& filePath, const MaterialParams& parameters, const String* materials, const OBJParser::Mesh* meshes, unsigned int meshCount)
{
const NzString& matName = materials[meshes[i].material];
const NzMTLParser::Material* mtlMat = materialParser.GetMaterial(matName);
if (!mtlMat)
File file(filePath);
if (!file.Open(OpenMode_ReadOnly | OpenMode_Text))
{
NazaraWarning("MTL has no material \"" + matName + '"');
continue;
NazaraError("Failed to open MTL file (" + file.GetPath() + ')');
return false;
}
auto it = materialCache.find(matName);
if (it == materialCache.end())
MTLParser materialParser(file);
if (!materialParser.Parse())
{
NzMaterialRef material = NzMaterial::New();
material->SetShader(parameters.shaderName);
NazaraError("MTL parser failed");
return false;
}
nzUInt8 alphaValue = static_cast<nzUInt8>(mtlMat->alpha*255.f);
NzColor ambientColor(mtlMat->ambient);
NzColor diffuseColor(mtlMat->diffuse);
NzColor specularColor(mtlMat->specular);
ambientColor.a = alphaValue;
diffuseColor.a = alphaValue;
specularColor.a = alphaValue;
material->SetAmbientColor(ambientColor);
material->SetDiffuseColor(diffuseColor);
material->SetSpecularColor(specularColor);
material->SetShininess(mtlMat->shininess);
bool isTranslucent = (alphaValue != 255);
if (parameters.loadAlphaMap && !mtlMat->alphaMap.IsEmpty())
std::unordered_map<String, MaterialRef> materialCache;
String baseDir = file.GetDirectory();
for (unsigned int i = 0; i < meshCount; ++i)
{
const String& matName = materials[meshes[i].material];
const MTLParser::Material* mtlMat = materialParser.GetMaterial(matName);
if (!mtlMat)
{
if (material->SetAlphaMap(baseDir + mtlMat->alphaMap))
isTranslucent = true; // Une alpha map indique de la transparence
NazaraWarning("MTL has no material \"" + matName + '"');
continue;
}
auto it = materialCache.find(matName);
if (it == materialCache.end())
{
MaterialRef material = Material::New();
material->SetShader(parameters.shaderName);
UInt8 alphaValue = static_cast<UInt8>(mtlMat->alpha*255.f);
Color ambientColor(mtlMat->ambient);
Color diffuseColor(mtlMat->diffuse);
Color specularColor(mtlMat->specular);
ambientColor.a = alphaValue;
diffuseColor.a = alphaValue;
specularColor.a = alphaValue;
material->SetAmbientColor(ambientColor);
material->SetDiffuseColor(diffuseColor);
material->SetSpecularColor(specularColor);
material->SetShininess(mtlMat->shininess);
bool isTranslucent = (alphaValue != 255);
if (parameters.loadAlphaMap && !mtlMat->alphaMap.IsEmpty())
{
if (material->SetAlphaMap(baseDir + mtlMat->alphaMap))
isTranslucent = true; // Une alpha map indique de la transparence
else
NazaraWarning("Failed to load alpha map (" + mtlMat->alphaMap + ')');
}
if (parameters.loadDiffuseMap && !mtlMat->diffuseMap.IsEmpty())
{
if (!material->SetDiffuseMap(baseDir + mtlMat->diffuseMap))
NazaraWarning("Failed to load diffuse map (" + mtlMat->diffuseMap + ')');
}
if (parameters.loadSpecularMap && !mtlMat->specularMap.IsEmpty())
{
if (!material->SetSpecularMap(baseDir + mtlMat->specularMap))
NazaraWarning("Failed to load specular map (" + mtlMat->specularMap + ')');
}
// Si nous avons une alpha map ou des couleurs transparentes,
// nous devons configurer le matériau pour accepter la transparence au mieux
if (isTranslucent)
{
// On paramètre le matériau pour accepter la transparence au mieux
material->Enable(RendererParameter_Blend, true);
material->Enable(RendererParameter_DepthWrite, false);
material->SetDstBlend(BlendFunc_InvSrcAlpha);
material->SetSrcBlend(BlendFunc_SrcAlpha);
}
it = materialCache.emplace(matName, std::move(material)).first;
}
model->SetMaterial(meshes[i].material, it->second);
}
return true;
}
bool Load(Model* model, InputStream& stream, const ModelParameters& parameters)
{
OBJParser parser(stream);
if (!parser.Parse())
{
NazaraError("OBJ parser failed");
return false;
}
MeshRef mesh = Mesh::New();
if (!mesh->CreateStatic()) // Ne devrait jamais échouer
{
NazaraInternalError("Failed to create mesh");
return false;
}
const String* materials = parser.GetMaterials();
const Vector4f* positions = parser.GetPositions();
const Vector3f* normals = parser.GetNormals();
const Vector3f* texCoords = parser.GetTexCoords();
const OBJParser::Mesh* meshes = parser.GetMeshes();
unsigned int meshCount = parser.GetMeshCount();
NazaraAssert(materials != nullptr && positions != nullptr && normals != nullptr &&
texCoords != nullptr && meshes != nullptr && meshCount > 0,
"Invalid OBJParser output");
// Un conteneur temporaire pour contenir les indices de face avant triangulation
std::vector<unsigned int> faceIndices(3); // Comme il y aura au moins trois sommets
for (unsigned int i = 0; i < meshCount; ++i)
{
unsigned int faceCount = meshes[i].faces.size();
if (faceCount == 0)
continue;
std::vector<unsigned int> indices;
indices.reserve(faceCount*3); // Pire cas si les faces sont des triangles
// Afin d'utiliser OBJParser::FaceVertex comme clé dans un unordered_map,
// nous devons fournir un foncteur de hash ainsi qu'un foncteur de comparaison
// Hash
struct FaceVertexHasher
{
std::size_t operator()(const OBJParser::FaceVertex& o) const
{
std::size_t seed = 0;
HashCombine(seed, o.normal);
HashCombine(seed, o.position);
HashCombine(seed, o.texCoord);
return seed;
}
};
// Comparaison
struct FaceVertexComparator
{
bool operator()(const OBJParser::FaceVertex& lhs, const OBJParser::FaceVertex& rhs) const
{
return lhs.normal == rhs.normal &&
lhs.position == rhs.position &&
lhs.texCoord == rhs.texCoord;
}
};
std::unordered_map<OBJParser::FaceVertex, unsigned int, FaceVertexHasher, FaceVertexComparator> vertices;
unsigned int vertexCount = 0;
for (unsigned int j = 0; j < faceCount; ++j)
{
unsigned int faceVertexCount = meshes[i].faces[j].vertices.size();
faceIndices.resize(faceVertexCount);
for (unsigned int k = 0; k < faceVertexCount; ++k)
{
const OBJParser::FaceVertex& vertex = meshes[i].faces[j].vertices[k];
auto it = vertices.find(vertex);
if (it == vertices.end())
it = vertices.emplace(vertex, vertexCount++).first;
faceIndices[k] = it->second;
}
for (unsigned int k = 1; k < faceVertexCount-1; ++k)
{
indices.push_back(faceIndices[0]);
indices.push_back(faceIndices[k]);
indices.push_back(faceIndices[k+1]);
}
}
// Création des buffers
IndexBufferRef indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits<UInt16>::max(), indices.size(), parameters.mesh.storage, BufferUsage_Static);
VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), vertexCount, parameters.mesh.storage, BufferUsage_Static);
// Remplissage des indices
IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly);
for (unsigned int j = 0; j < indices.size(); ++j)
indexMapper.Set(j, indices[j]);
indexMapper.Unmap(); // Pour laisser les autres tâches affecter l'index buffer
// Remplissage des vertices
bool hasNormals = true;
bool hasTexCoords = true;
BufferMapper<VertexBuffer> vertexMapper(vertexBuffer, BufferAccess_WriteOnly);
MeshVertex* meshVertices = static_cast<MeshVertex*>(vertexMapper.GetPointer());
for (auto& vertexPair : vertices)
{
const OBJParser::FaceVertex& vertexIndices = vertexPair.first;
unsigned int index = vertexPair.second;
MeshVertex& vertex = meshVertices[index];
const Vector4f& vec = positions[vertexIndices.position];
vertex.position.Set(vec.x, vec.y, vec.z);
vertex.position *= parameters.mesh.scale/vec.w;
if (vertexIndices.normal >= 0)
vertex.normal = normals[vertexIndices.normal];
else
NazaraWarning("Failed to load alpha map (" + mtlMat->alphaMap + ')');
hasNormals = false;
if (vertexIndices.texCoord >= 0)
{
const Vector3f& uvw = texCoords[vertexIndices.texCoord];
vertex.uv.Set(uvw.x, (parameters.mesh.flipUVs) ? 1.f - uvw.y : uvw.y); // Inversion des UVs si demandé
}
else
hasTexCoords = false;
}
if (parameters.loadDiffuseMap && !mtlMat->diffuseMap.IsEmpty())
vertexMapper.Unmap();
StaticMeshRef subMesh = StaticMesh::New(mesh);
if (!subMesh->Create(vertexBuffer))
{
if (!material->SetDiffuseMap(baseDir + mtlMat->diffuseMap))
NazaraWarning("Failed to load diffuse map (" + mtlMat->diffuseMap + ')');
NazaraError("Failed to create StaticMesh");
continue;
}
if (parameters.loadSpecularMap && !mtlMat->specularMap.IsEmpty())
{
if (!material->SetSpecularMap(baseDir + mtlMat->specularMap))
NazaraWarning("Failed to load specular map (" + mtlMat->specularMap + ')');
}
if (parameters.mesh.optimizeIndexBuffers)
indexBuffer->Optimize();
// Si nous avons une alpha map ou des couleurs transparentes,
// nous devons configurer le matériau pour accepter la transparence au mieux
if (isTranslucent)
{
// On paramètre le matériau pour accepter la transparence au mieux
material->Enable(nzRendererParameter_Blend, true);
material->Enable(nzRendererParameter_DepthWrite, false);
material->SetDstBlend(nzBlendFunc_InvSrcAlpha);
material->SetSrcBlend(nzBlendFunc_SrcAlpha);
}
subMesh->GenerateAABB();
subMesh->SetIndexBuffer(indexBuffer);
subMesh->SetMaterialIndex(meshes[i].material);
subMesh->SetPrimitiveMode(PrimitiveMode_TriangleList);
it = materialCache.emplace(matName, std::move(material)).first;
// Ce que nous pouvons générer dépend des données à disposition (par exemple les tangentes nécessitent des coordonnées de texture)
if (hasNormals && hasTexCoords)
subMesh->GenerateTangents();
else if (hasTexCoords)
subMesh->GenerateNormalsAndTangents();
else
subMesh->GenerateNormals();
mesh->AddSubMesh(meshes[i].name + '_' + materials[meshes[i].material], subMesh);
}
mesh->SetMaterialCount(parser.GetMaterialCount());
if (parameters.mesh.center)
mesh->Recenter();
model->SetMesh(mesh);
// On charge les matériaux si demandé
String mtlLib = parser.GetMtlLib();
if (parameters.loadMaterials && !mtlLib.IsEmpty())
{
ErrorFlags flags(ErrorFlag_ThrowExceptionDisabled);
LoadMaterials(model, stream.GetDirectory() + mtlLib, parameters.material, materials, meshes, meshCount);
}
model->SetMaterial(meshes[i].material, it->second);
return true;
}
return true;
}
bool Load(NzModel* model, NzInputStream& stream, const NzModelParameters& parameters)
namespace Loaders
{
NzOBJParser parser(stream);
if (!parser.Parse())
void RegisterOBJ()
{
NazaraError("OBJ parser failed");
return false;
ModelLoader::RegisterLoader(IsSupported, Check, Load);
}
NzMeshRef mesh = NzMesh::New();
if (!mesh->CreateStatic()) // Ne devrait jamais échouer
void UnregisterOBJ()
{
NazaraInternalError("Failed to create mesh");
return false;
ModelLoader::UnregisterLoader(IsSupported, Check, Load);
}
const NzString* materials = parser.GetMaterials();
const NzVector4f* positions = parser.GetPositions();
const NzVector3f* normals = parser.GetNormals();
const NzVector3f* texCoords = parser.GetTexCoords();
const NzOBJParser::Mesh* meshes = parser.GetMeshes();
unsigned int meshCount = parser.GetMeshCount();
NazaraAssert(materials != nullptr && positions != nullptr && normals != nullptr &&
texCoords != nullptr && meshes != nullptr && meshCount > 0,
"Invalid OBJParser output");
// Un conteneur temporaire pour contenir les indices de face avant triangulation
std::vector<unsigned int> faceIndices(3); // Comme il y aura au moins trois sommets
for (unsigned int i = 0; i < meshCount; ++i)
{
unsigned int faceCount = meshes[i].faces.size();
if (faceCount == 0)
continue;
std::vector<unsigned int> indices;
indices.reserve(faceCount*3); // Pire cas si les faces sont des triangles
// Afin d'utiliser OBJParser::FaceVertex comme clé dans un unordered_map,
// nous devons fournir un foncteur de hash ainsi qu'un foncteur de comparaison
// Hash
struct FaceVertexHasher
{
std::size_t operator()(const NzOBJParser::FaceVertex& o) const
{
std::size_t seed = 0;
NzHashCombine(seed, o.normal);
NzHashCombine(seed, o.position);
NzHashCombine(seed, o.texCoord);
return seed;
}
};
// Comparaison
struct FaceVertexComparator
{
bool operator()(const NzOBJParser::FaceVertex& lhs, const NzOBJParser::FaceVertex& rhs) const
{
return lhs.normal == rhs.normal &&
lhs.position == rhs.position &&
lhs.texCoord == rhs.texCoord;
}
};
std::unordered_map<NzOBJParser::FaceVertex, unsigned int, FaceVertexHasher, FaceVertexComparator> vertices;
unsigned int vertexCount = 0;
for (unsigned int j = 0; j < faceCount; ++j)
{
unsigned int faceVertexCount = meshes[i].faces[j].vertices.size();
faceIndices.resize(faceVertexCount);
for (unsigned int k = 0; k < faceVertexCount; ++k)
{
const NzOBJParser::FaceVertex& vertex = meshes[i].faces[j].vertices[k];
auto it = vertices.find(vertex);
if (it == vertices.end())
it = vertices.emplace(vertex, vertexCount++).first;
faceIndices[k] = it->second;
}
for (unsigned int k = 1; k < faceVertexCount-1; ++k)
{
indices.push_back(faceIndices[0]);
indices.push_back(faceIndices[k]);
indices.push_back(faceIndices[k+1]);
}
}
// Création des buffers
NzIndexBufferRef indexBuffer = NzIndexBuffer::New(vertexCount > std::numeric_limits<nzUInt16>::max(), indices.size(), parameters.mesh.storage, nzBufferUsage_Static);
NzVertexBufferRef vertexBuffer = NzVertexBuffer::New(NzVertexDeclaration::Get(nzVertexLayout_XYZ_Normal_UV_Tangent), vertexCount, parameters.mesh.storage, nzBufferUsage_Static);
// Remplissage des indices
NzIndexMapper indexMapper(indexBuffer, nzBufferAccess_WriteOnly);
for (unsigned int j = 0; j < indices.size(); ++j)
indexMapper.Set(j, indices[j]);
indexMapper.Unmap(); // Pour laisser les autres tâches affecter l'index buffer
// Remplissage des vertices
bool hasNormals = true;
bool hasTexCoords = true;
NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer, nzBufferAccess_WriteOnly);
NzMeshVertex* meshVertices = static_cast<NzMeshVertex*>(vertexMapper.GetPointer());
for (auto& vertexPair : vertices)
{
const NzOBJParser::FaceVertex& vertexIndices = vertexPair.first;
unsigned int index = vertexPair.second;
NzMeshVertex& vertex = meshVertices[index];
const NzVector4f& vec = positions[vertexIndices.position];
vertex.position.Set(vec.x, vec.y, vec.z);
vertex.position *= parameters.mesh.scale/vec.w;
if (vertexIndices.normal >= 0)
vertex.normal = normals[vertexIndices.normal];
else
hasNormals = false;
if (vertexIndices.texCoord >= 0)
{
const NzVector3f& uvw = texCoords[vertexIndices.texCoord];
vertex.uv.Set(uvw.x, (parameters.mesh.flipUVs) ? 1.f - uvw.y : uvw.y); // Inversion des UVs si demandé
}
else
hasTexCoords = false;
}
vertexMapper.Unmap();
NzStaticMeshRef subMesh = NzStaticMesh::New(mesh);
if (!subMesh->Create(vertexBuffer))
{
NazaraError("Failed to create StaticMesh");
continue;
}
if (parameters.mesh.optimizeIndexBuffers)
indexBuffer->Optimize();
subMesh->GenerateAABB();
subMesh->SetIndexBuffer(indexBuffer);
subMesh->SetMaterialIndex(meshes[i].material);
subMesh->SetPrimitiveMode(nzPrimitiveMode_TriangleList);
// Ce que nous pouvons générer dépend des données à disposition (par exemple les tangentes nécessitent des coordonnées de texture)
if (hasNormals && hasTexCoords)
subMesh->GenerateTangents();
else if (hasTexCoords)
subMesh->GenerateNormalsAndTangents();
else
subMesh->GenerateNormals();
mesh->AddSubMesh(meshes[i].name + '_' + materials[meshes[i].material], subMesh);
}
mesh->SetMaterialCount(parser.GetMaterialCount());
if (parameters.mesh.center)
mesh->Recenter();
model->SetMesh(mesh);
// On charge les matériaux si demandé
NzString mtlLib = parser.GetMtlLib();
if (parameters.loadMaterials && !mtlLib.IsEmpty())
{
NzErrorFlags flags(nzErrorFlag_ThrowExceptionDisabled);
LoadMaterials(model, stream.GetDirectory() + mtlLib, parameters.material, materials, meshes, meshCount);
}
return true;
}
}
void NzLoaders_OBJ_Register()
{
NzModelLoader::RegisterLoader(IsSupported, Check, Load);
}
void NzLoaders_OBJ_Unregister()
{
NzModelLoader::UnregisterLoader(IsSupported, Check, Load);
}

Some files were not shown because too many files have changed in this diff Show More