Added RenderTextures (And many others things)
-Added Forward, left and up vector (Vector3) -Added Matrix4::ConcatenateAffine shortcut -Added Quaternion::GetInverse() and Quaternion::Inverse() -Added Resource listeners -Added Depth and stencil pixel formats -All enums now have an ending "max" entry -Animation/Mesh::Add[Sequence/Skin/SubMesh] now returns a boolean -Contexts are now resources -Enhanced AnimatedMesh demo -Fixed MD2 facing -Fixed Vector3::CrossProduct -Made Resource thread-safe -Made OpenGL translation table global -Many bugfixes -MLT will now write malloc failure to the log -Most of the strcpy were replaced with faster memcpy -Occlusion queries availability is now always tested -OpenGL-related includes now requires NAZARA_RENDERER_OPENGL to be defined to have any effect -Pixel formats now have a type -Renamed RenderTarget::IsValid to IsRenderable -Renamed Quaternion::GetNormalized() to GetNormal() -Renamed Texture::Bind() to Prepare() -Renamed VectorX::Make[Ceil|Floor] to Maximize/Minimize -Removed MATH_MATRIX_COLUMN_MAJOR option (all matrices are column-major) -Removed RENDERER_ACTIVATE_RENDERWINDOW_ON_CREATION option (Render windows are active upon their creation) Former-commit-id: 0d1da1e32c156a958221edf04a5315c75b354450
This commit is contained in:
@@ -1,223 +1,229 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Audio module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Audio/SoundBuffer.hpp>
|
||||
#include <Nazara/Audio/Audio.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <AL/al.h>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
///FIXME: Adapter la création
|
||||
|
||||
bool NzSoundBufferParams::IsValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NzSoundBufferImpl
|
||||
{
|
||||
ALuint buffer;
|
||||
nzAudioFormat format;
|
||||
nzUInt32 duration;
|
||||
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)
|
||||
{
|
||||
NazaraError("Failed to create sound buffer");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NzSoundBuffer::~NzSoundBuffer()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzSoundBuffer::Create(nzAudioFormat format, unsigned int sampleCount, unsigned int sampleRate, const nzInt16* samples)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
if (sampleCount == 0)
|
||||
return true;
|
||||
|
||||
#if NAZARA_AUDIO_SAFE
|
||||
if (!IsFormatSupported(format))
|
||||
{
|
||||
NazaraError("Audio format is not supported");
|
||||
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, NzAudio::GetOpenALFormat(format), samples, sampleCount*sizeof(nzInt16), sampleRate);
|
||||
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
NazaraError("Failed to set OpenAL buffer");
|
||||
alDeleteBuffers(1, &buffer);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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 = new nzInt16[sampleCount];
|
||||
std::memcpy(&m_impl->samples[0], samples, sampleCount*sizeof(nzInt16));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzSoundBuffer::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
delete[] m_impl->samples;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
NzSoundBufferLoader::LoaderList NzSoundBuffer::s_loaders;
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Audio module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Audio/SoundBuffer.hpp>
|
||||
#include <Nazara/Audio/Audio.hpp>
|
||||
#include <Nazara/Audio/Config.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <AL/al.h>
|
||||
#include <Nazara/Audio/Debug.hpp>
|
||||
|
||||
///FIXME: Adapter la création
|
||||
|
||||
bool NzSoundBufferParams::IsValid() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
struct NzSoundBufferImpl
|
||||
{
|
||||
ALuint buffer;
|
||||
nzAudioFormat format;
|
||||
nzUInt32 duration;
|
||||
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)
|
||||
{
|
||||
NazaraError("Failed to create sound buffer");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NzSoundBuffer::~NzSoundBuffer()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (sampleCount == 0)
|
||||
{
|
||||
NazaraError("Sample rate must be different from zero");
|
||||
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, NzAudio::GetOpenALFormat(format), samples, sampleCount*sizeof(nzInt16), sampleRate);
|
||||
|
||||
if (alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
NazaraError("Failed to set OpenAL buffer");
|
||||
alDeleteBuffers(1, &buffer);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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 = new nzInt16[sampleCount];
|
||||
std::memcpy(&m_impl->samples[0], samples, sampleCount*sizeof(nzInt16));
|
||||
|
||||
NotifyCreated();
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzSoundBuffer::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
NotifyDestroy();
|
||||
|
||||
delete[] m_impl->samples;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
NzSoundBufferLoader::LoaderList NzSoundBuffer::s_loaders;
|
||||
|
||||
@@ -1,265 +1,265 @@
|
||||
/*
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Core module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Core/ByteArray.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
inline unsigned int nzPow2(unsigned int n)
|
||||
{
|
||||
unsigned int x = 1;
|
||||
|
||||
while(x <= n)
|
||||
x <<= 1;
|
||||
|
||||
return x;
|
||||
}
|
||||
// Cet algorithme est inspiré de la documentation de Qt
|
||||
inline unsigned int nzGetNewSize(unsigned int newSize)
|
||||
{
|
||||
if (newSize < 20)
|
||||
return newSize+4;
|
||||
else
|
||||
{
|
||||
if (newSize < (1 << 12)-12)
|
||||
return nzPow2(newSize << 1)-12;
|
||||
else
|
||||
return newSize + (1 << 11);
|
||||
}
|
||||
}
|
||||
|
||||
NzByteArray::NzByteArray() :
|
||||
m_sharedArray(&emptyArray)
|
||||
{
|
||||
}
|
||||
|
||||
NzByteArray::NzByteArray(const nzUInt8* buffer, unsigned int bufferLength)
|
||||
{
|
||||
if (bufferLength > 0)
|
||||
{
|
||||
m_sharedArray = new SharedArray;
|
||||
m_sharedArray->buffer = new nzUInt8[bufferLength];
|
||||
m_sharedArray->capacity = bufferLength;
|
||||
m_sharedArray->size = bufferLength;
|
||||
std::memcpy(m_sharedArray->buffer, buffer, bufferLength);
|
||||
}
|
||||
else
|
||||
m_sharedArray = &emptyArray;
|
||||
}
|
||||
|
||||
NzByteArray::NzByteArray(const NzByteArray& buffer) :
|
||||
m_sharedArray(buffer.m_sharedArray)
|
||||
{
|
||||
if (m_sharedArray != &emptyArray)
|
||||
{
|
||||
NazaraMutexLock(m_sharedArray->mutex);
|
||||
m_sharedArray->refCount++;
|
||||
NazaraMutexUnlock(m_sharedArray->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
NzByteArray::NzByteArray(NzByteArray&& buffer) :
|
||||
m_sharedArray(buffer.m_sharedArray)
|
||||
{
|
||||
buffer.m_sharedArray = &emptyArray;
|
||||
}
|
||||
|
||||
NzByteArray::NzByteArray(SharedArray* sharedArray) :
|
||||
m_sharedArray(sharedArray)
|
||||
{
|
||||
}
|
||||
|
||||
NzByteArray::~NzByteArray()
|
||||
{
|
||||
ReleaseArray();
|
||||
}
|
||||
|
||||
NzByteArray& NzByteArray::Append(const NzByteArray& byteArray)
|
||||
{
|
||||
if (byteArray.m_sharedArray->size == 0)
|
||||
return *this;
|
||||
|
||||
if (m_sharedArray->size == 0 && m_sharedArray->capacity < byteArray.m_sharedArray->size)
|
||||
return operator=(byteArray);
|
||||
|
||||
if (m_sharedArray->capacity >= m_sharedArray->size + byteArray.m_sharedArray->size)
|
||||
{
|
||||
EnsureOwnership();
|
||||
|
||||
std::memcpy(&m_sharedArray->buffer[m_sharedArray->size], byteArray.m_sharedArray->buffer, byteArray.m_sharedArray->size);
|
||||
m_sharedArray->size += byteArray.m_sharedArray->size;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int newSize = m_sharedArray->size + byteArray.m_sharedArray->size;
|
||||
unsigned int bufferSize = nzGetNewSize(newSize);
|
||||
|
||||
nzUInt8* buffer = new nzUInt8[bufferSize+1];
|
||||
std::memcpy(buffer, m_sharedArray->buffer, m_sharedArray->size);
|
||||
std::memcpy(&buffer[m_sharedArray->size], byteArray.m_sharedArray->buffer, byteArray.m_sharedArray->size);
|
||||
|
||||
ReleaseArray();
|
||||
m_sharedArray = new SharedArray;
|
||||
m_sharedArray->buffer = buffer;
|
||||
m_sharedArray->capacity = bufferSize;
|
||||
m_sharedArray->size = newSize;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void NzByteArray::Clear()
|
||||
{
|
||||
ReleaseArray();
|
||||
}
|
||||
|
||||
nzUInt8* NzByteArray::GetBuffer()
|
||||
{
|
||||
EnsureOwnership();
|
||||
|
||||
return m_sharedArray->buffer;
|
||||
}
|
||||
|
||||
unsigned int NzByteArray::GetCapacity() const
|
||||
{
|
||||
return m_sharedArray->capacity;
|
||||
}
|
||||
|
||||
const nzUInt8* NzByteArray::GetConstBuffer() const
|
||||
{
|
||||
return m_sharedArray->buffer;
|
||||
}
|
||||
|
||||
unsigned int NzByteArray::GetSize() const
|
||||
{
|
||||
return m_sharedArray->size;
|
||||
}
|
||||
|
||||
NzByteArray& NzByteArray::Insert(int pos, const nzUInt8* buffer, unsigned int bufferLength)
|
||||
{
|
||||
if (bufferLength == 0)
|
||||
return *this;
|
||||
|
||||
if (m_sharedArray->size == 0)
|
||||
return operator=(string);
|
||||
|
||||
if (pos < 0)
|
||||
pos = std::max(static_cast<int>(m_sharedArray->size + pos), 0);
|
||||
|
||||
unsigned int start = std::min(static_cast<unsigned int>(pos), m_sharedArray->size);
|
||||
|
||||
// Si le buffer est déjà suffisamment grand
|
||||
if (m_sharedArray->capacity >= m_sharedArray->size + bufferLength)
|
||||
{
|
||||
EnsureOwnership();
|
||||
|
||||
std::memmove(&m_sharedArray->buffer[start+bufferLength], &m_sharedArray->buffer[start], m_sharedArray->size);
|
||||
std::memcpy(&m_sharedArray->buffer[start], buffer, bufferLength);
|
||||
|
||||
m_sharedArray->size += bufferLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int newSize = m_sharedArray->size+bufferLength;
|
||||
nzUInt8* newBuffer = new nzUInt8[newSize+1];
|
||||
|
||||
nzUInt8* ptr = newBuffer;
|
||||
const nzUInt8* s = m_sharedArray->buffer;
|
||||
|
||||
while (ptr != &newBuffer[start])
|
||||
*ptr++ = *s++;
|
||||
|
||||
while (ptr != &newBuffer[start+bufferLength])
|
||||
*ptr++ = *buffer++;
|
||||
|
||||
std::strcpy(ptr, s);
|
||||
|
||||
ReleaseString();
|
||||
m_sharedArray = new SharedString;
|
||||
m_sharedArray->allocatedSize = newSize;
|
||||
m_sharedArray->buffer = newBuffer;
|
||||
m_sharedArray->size = newSize;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzByteArray& NzByteArray::Insert(int pos, const NzByteArray& byteArray)
|
||||
{
|
||||
if (string.m_sharedArray->size == 0)
|
||||
return *this;
|
||||
|
||||
if (m_sharedArray->size == 0 && m_sharedArray->capacity < string.m_sharedArray->size)
|
||||
return operator=(string);
|
||||
|
||||
if (pos < 0)
|
||||
pos = std::max(static_cast<int>(m_sharedArray->size + pos), 0);
|
||||
|
||||
unsigned int start = std::min(static_cast<unsigned int>(pos), m_sharedArray->size);
|
||||
|
||||
// Si le buffer est déjà suffisamment grand
|
||||
if (m_sharedArray->capacity >= m_sharedArray->size + string.m_sharedArray->size)
|
||||
{
|
||||
EnsureOwnership();
|
||||
|
||||
std::memmove(&m_sharedArray->string[start+string.m_sharedArray->size], &m_sharedArray->string[start], m_sharedArray->size*sizeof(char));
|
||||
std::memcpy(&m_sharedArray->string[start], string.m_sharedArray->string, string.m_sharedArray->size*sizeof(char));
|
||||
|
||||
m_sharedArray->size += string.m_sharedArray->size;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int newSize = m_sharedArray->size+string.m_sharedArray->size;
|
||||
char* newString = new char[newSize+1];
|
||||
|
||||
char* ptr = newString;
|
||||
const char* s = m_sharedArray->string;
|
||||
|
||||
while (ptr != &newString[start])
|
||||
*ptr++ = *s++;
|
||||
|
||||
const char* p = string.m_sharedArray->string;
|
||||
while (ptr != &newString[start+string.m_sharedArray->size])
|
||||
*ptr++ = *p++;
|
||||
|
||||
std::strcpy(ptr, s);
|
||||
|
||||
ReleaseString();
|
||||
m_sharedArray = new SharedString;
|
||||
m_sharedArray->capacity = newSize;
|
||||
m_sharedArray->size = newSize;
|
||||
m_sharedArray->string = newString;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool NzByteArray::IsEmpty() const
|
||||
{
|
||||
return m_sharedArray->size == 0;
|
||||
}
|
||||
|
||||
void NzByteArray::Reserve(unsigned int bufferSize)
|
||||
{
|
||||
if (m_sharedArray->allocatedSize >= bufferSize)
|
||||
return;
|
||||
|
||||
nzUInt8* ptr = new nzUInt8[bufferSize+1];
|
||||
if (m_sharedArray->size > 0)
|
||||
std::memcpy(ptr, m_sharedArray->buffer, m_sharedArray->size);
|
||||
|
||||
unsigned int size = m_sharedArray->size;
|
||||
|
||||
ReleaseArray();
|
||||
m_sharedArray = new SharedString;
|
||||
m_sharedArray->allocatedSize = bufferSize;
|
||||
m_sharedArray->buffer = ptr;
|
||||
m_sharedArray->size = size;
|
||||
}
|
||||
|
||||
NzByteArray::SharedString NzByteArray::emptyArray(0, 0, 0, nullptr);
|
||||
unsigned int NzByteArray::npos(static_cast<unsigned int>(-1));
|
||||
*/
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Core module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
/*
|
||||
#include <Nazara/Core/ByteArray.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
inline unsigned int nzPow2(unsigned int n)
|
||||
{
|
||||
unsigned int x = 1;
|
||||
|
||||
while(x <= n)
|
||||
x <<= 1;
|
||||
|
||||
return x;
|
||||
}
|
||||
// Cet algorithme est inspiré de la documentation de Qt
|
||||
inline unsigned int nzGetNewSize(unsigned int newSize)
|
||||
{
|
||||
if (newSize < 20)
|
||||
return newSize+4;
|
||||
else
|
||||
{
|
||||
if (newSize < (1 << 12)-12)
|
||||
return nzPow2(newSize << 1)-12;
|
||||
else
|
||||
return newSize + (1 << 11);
|
||||
}
|
||||
}
|
||||
|
||||
NzByteArray::NzByteArray() :
|
||||
m_sharedArray(&emptyArray)
|
||||
{
|
||||
}
|
||||
|
||||
NzByteArray::NzByteArray(const nzUInt8* buffer, unsigned int bufferLength)
|
||||
{
|
||||
if (bufferLength > 0)
|
||||
{
|
||||
m_sharedArray = new SharedArray;
|
||||
m_sharedArray->buffer = new nzUInt8[bufferLength];
|
||||
m_sharedArray->capacity = bufferLength;
|
||||
m_sharedArray->size = bufferLength;
|
||||
std::memcpy(m_sharedArray->buffer, buffer, bufferLength);
|
||||
}
|
||||
else
|
||||
m_sharedArray = &emptyArray;
|
||||
}
|
||||
|
||||
NzByteArray::NzByteArray(const NzByteArray& buffer) :
|
||||
m_sharedArray(buffer.m_sharedArray)
|
||||
{
|
||||
if (m_sharedArray != &emptyArray)
|
||||
{
|
||||
NazaraMutexLock(m_sharedArray->mutex);
|
||||
m_sharedArray->refCount++;
|
||||
NazaraMutexUnlock(m_sharedArray->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
NzByteArray::NzByteArray(NzByteArray&& buffer) noexcept :
|
||||
m_sharedArray(buffer.m_sharedArray)
|
||||
{
|
||||
buffer.m_sharedArray = &emptyArray;
|
||||
}
|
||||
|
||||
NzByteArray::NzByteArray(SharedArray* sharedArray) :
|
||||
m_sharedArray(sharedArray)
|
||||
{
|
||||
}
|
||||
|
||||
NzByteArray::~NzByteArray()
|
||||
{
|
||||
ReleaseArray();
|
||||
}
|
||||
|
||||
NzByteArray& NzByteArray::Append(const NzByteArray& byteArray)
|
||||
{
|
||||
if (byteArray.m_sharedArray->size == 0)
|
||||
return *this;
|
||||
|
||||
if (m_sharedArray->size == 0 && m_sharedArray->capacity < byteArray.m_sharedArray->size)
|
||||
return operator=(byteArray);
|
||||
|
||||
if (m_sharedArray->capacity >= m_sharedArray->size + byteArray.m_sharedArray->size)
|
||||
{
|
||||
EnsureOwnership();
|
||||
|
||||
std::memcpy(&m_sharedArray->buffer[m_sharedArray->size], byteArray.m_sharedArray->buffer, byteArray.m_sharedArray->size);
|
||||
m_sharedArray->size += byteArray.m_sharedArray->size;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int newSize = m_sharedArray->size + byteArray.m_sharedArray->size;
|
||||
unsigned int bufferSize = nzGetNewSize(newSize);
|
||||
|
||||
nzUInt8* buffer = new nzUInt8[bufferSize+1];
|
||||
std::memcpy(buffer, m_sharedArray->buffer, m_sharedArray->size);
|
||||
std::memcpy(&buffer[m_sharedArray->size], byteArray.m_sharedArray->buffer, byteArray.m_sharedArray->size);
|
||||
|
||||
ReleaseArray();
|
||||
m_sharedArray = new SharedArray;
|
||||
m_sharedArray->buffer = buffer;
|
||||
m_sharedArray->capacity = bufferSize;
|
||||
m_sharedArray->size = newSize;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void NzByteArray::Clear()
|
||||
{
|
||||
ReleaseArray();
|
||||
}
|
||||
|
||||
nzUInt8* NzByteArray::GetBuffer()
|
||||
{
|
||||
EnsureOwnership();
|
||||
|
||||
return m_sharedArray->buffer;
|
||||
}
|
||||
|
||||
unsigned int NzByteArray::GetCapacity() const
|
||||
{
|
||||
return m_sharedArray->capacity;
|
||||
}
|
||||
|
||||
const nzUInt8* NzByteArray::GetConstBuffer() const
|
||||
{
|
||||
return m_sharedArray->buffer;
|
||||
}
|
||||
|
||||
unsigned int NzByteArray::GetSize() const
|
||||
{
|
||||
return m_sharedArray->size;
|
||||
}
|
||||
|
||||
NzByteArray& NzByteArray::Insert(int pos, const nzUInt8* buffer, unsigned int bufferLength)
|
||||
{
|
||||
if (bufferLength == 0)
|
||||
return *this;
|
||||
|
||||
if (m_sharedArray->size == 0)
|
||||
return operator=(string);
|
||||
|
||||
if (pos < 0)
|
||||
pos = std::max(static_cast<int>(m_sharedArray->size + pos), 0);
|
||||
|
||||
unsigned int start = std::min(static_cast<unsigned int>(pos), m_sharedArray->size);
|
||||
|
||||
// Si le buffer est déjà suffisamment grand
|
||||
if (m_sharedArray->capacity >= m_sharedArray->size + bufferLength)
|
||||
{
|
||||
EnsureOwnership();
|
||||
|
||||
std::memmove(&m_sharedArray->buffer[start+bufferLength], &m_sharedArray->buffer[start], m_sharedArray->size);
|
||||
std::memcpy(&m_sharedArray->buffer[start], buffer, bufferLength);
|
||||
|
||||
m_sharedArray->size += bufferLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int newSize = m_sharedArray->size+bufferLength;
|
||||
nzUInt8* newBuffer = new nzUInt8[newSize+1];
|
||||
|
||||
nzUInt8* ptr = newBuffer;
|
||||
const nzUInt8* s = m_sharedArray->buffer;
|
||||
|
||||
while (ptr != &newBuffer[start])
|
||||
*ptr++ = *s++;
|
||||
|
||||
while (ptr != &newBuffer[start+bufferLength])
|
||||
*ptr++ = *buffer++;
|
||||
|
||||
std::strcpy(ptr, s);
|
||||
|
||||
ReleaseString();
|
||||
m_sharedArray = new SharedString;
|
||||
m_sharedArray->allocatedSize = newSize;
|
||||
m_sharedArray->buffer = newBuffer;
|
||||
m_sharedArray->size = newSize;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzByteArray& NzByteArray::Insert(int pos, const NzByteArray& byteArray)
|
||||
{
|
||||
if (string.m_sharedArray->size == 0)
|
||||
return *this;
|
||||
|
||||
if (m_sharedArray->size == 0 && m_sharedArray->capacity < string.m_sharedArray->size)
|
||||
return operator=(string);
|
||||
|
||||
if (pos < 0)
|
||||
pos = std::max(static_cast<int>(m_sharedArray->size + pos), 0);
|
||||
|
||||
unsigned int start = std::min(static_cast<unsigned int>(pos), m_sharedArray->size);
|
||||
|
||||
// Si le buffer est déjà suffisamment grand
|
||||
if (m_sharedArray->capacity >= m_sharedArray->size + string.m_sharedArray->size)
|
||||
{
|
||||
EnsureOwnership();
|
||||
|
||||
std::memmove(&m_sharedArray->string[start+string.m_sharedArray->size], &m_sharedArray->string[start], m_sharedArray->size*sizeof(char));
|
||||
std::memcpy(&m_sharedArray->string[start], string.m_sharedArray->string, string.m_sharedArray->size*sizeof(char));
|
||||
|
||||
m_sharedArray->size += string.m_sharedArray->size;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int newSize = m_sharedArray->size+string.m_sharedArray->size;
|
||||
char* newString = new char[newSize+1];
|
||||
|
||||
char* ptr = newString;
|
||||
const char* s = m_sharedArray->string;
|
||||
|
||||
while (ptr != &newString[start])
|
||||
*ptr++ = *s++;
|
||||
|
||||
const char* p = string.m_sharedArray->string;
|
||||
while (ptr != &newString[start+string.m_sharedArray->size])
|
||||
*ptr++ = *p++;
|
||||
|
||||
std::strcpy(ptr, s);
|
||||
|
||||
ReleaseString();
|
||||
m_sharedArray = new SharedString;
|
||||
m_sharedArray->capacity = newSize;
|
||||
m_sharedArray->size = newSize;
|
||||
m_sharedArray->string = newString;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool NzByteArray::IsEmpty() const
|
||||
{
|
||||
return m_sharedArray->size == 0;
|
||||
}
|
||||
|
||||
void NzByteArray::Reserve(unsigned int bufferSize)
|
||||
{
|
||||
if (m_sharedArray->allocatedSize >= bufferSize)
|
||||
return;
|
||||
|
||||
nzUInt8* ptr = new nzUInt8[bufferSize+1];
|
||||
if (m_sharedArray->size > 0)
|
||||
std::memcpy(ptr, m_sharedArray->buffer, m_sharedArray->size);
|
||||
|
||||
unsigned int size = m_sharedArray->size;
|
||||
|
||||
ReleaseArray();
|
||||
m_sharedArray = new SharedString;
|
||||
m_sharedArray->allocatedSize = bufferSize;
|
||||
m_sharedArray->buffer = ptr;
|
||||
m_sharedArray->size = size;
|
||||
}
|
||||
|
||||
NzByteArray::SharedString NzByteArray::emptyArray(0, 0, 0, nullptr);
|
||||
unsigned int NzByteArray::npos(static_cast<unsigned int>(-1));
|
||||
*/
|
||||
|
||||
@@ -1,264 +1,271 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Core module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Core/Debug/MemoryLeakTracker.hpp>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <windows.h>
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Block
|
||||
{
|
||||
std::size_t size;
|
||||
const char* file;
|
||||
Block* prev;
|
||||
Block* next;
|
||||
bool array;
|
||||
unsigned int line;
|
||||
unsigned int magic;
|
||||
};
|
||||
|
||||
bool initialized = false;
|
||||
const unsigned int magic = 0x51429EE;
|
||||
const char* MLTFileName = "NazaraLeaks.log";
|
||||
const char* nextFreeFile = "Internal error";
|
||||
unsigned int nextFreeLine = 0;
|
||||
|
||||
Block ptrList =
|
||||
{
|
||||
0,
|
||||
nullptr,
|
||||
&ptrList,
|
||||
&ptrList,
|
||||
false,
|
||||
0,
|
||||
magic
|
||||
};
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
CRITICAL_SECTION mutex;
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_t 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 (!initialized)
|
||||
Initialize();
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
EnterCriticalSection(&mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_lock(&mutex);
|
||||
#endif
|
||||
|
||||
Block* ptr = reinterpret_cast<Block*>(std::malloc(size+sizeof(Block)));
|
||||
if (!ptr)
|
||||
return nullptr; // Impossible d'envoyer une exception car cela allouerait de la mémoire avec new (boucle infinie)
|
||||
|
||||
ptr->array = multi;
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = size;
|
||||
ptr->magic = magic;
|
||||
|
||||
ptr->prev = ptrList.prev;
|
||||
ptr->next = &ptrList;
|
||||
ptrList.prev->next = ptr;
|
||||
ptrList.prev = ptr;
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
LeaveCriticalSection(&mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_unlock(&mutex);
|
||||
#endif
|
||||
|
||||
return reinterpret_cast<char*>(ptr)+sizeof(Block);
|
||||
}
|
||||
|
||||
void NzMemoryManager::Free(void* pointer, bool multi)
|
||||
{
|
||||
if (!pointer)
|
||||
return;
|
||||
|
||||
Block* ptr = reinterpret_cast<Block*>(reinterpret_cast<char*>(pointer)-sizeof(Block));
|
||||
if (ptr->magic != magic)
|
||||
return;
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
EnterCriticalSection(&mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_lock(&mutex);
|
||||
#endif
|
||||
|
||||
if (ptr->array != multi)
|
||||
{
|
||||
char* time = TimeInfo();
|
||||
|
||||
FILE* log = std::fopen(MLTFileName, "a");
|
||||
|
||||
if (nextFreeFile)
|
||||
{
|
||||
if (multi)
|
||||
std::fprintf(log, "%s Warning: delete[] after new at %s:%d\n", time, nextFreeFile, nextFreeLine);
|
||||
else
|
||||
std::fprintf(log, "%s Warning: delete after new[] at %s:%d\n", time, nextFreeFile, nextFreeLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (multi)
|
||||
std::fprintf(log, "%s Warning: delete[] after new at unknown position\n", time);
|
||||
else
|
||||
std::fprintf(log, "%s Warning: delete after new[] at unknown position\n", time);
|
||||
}
|
||||
|
||||
std::fclose(log);
|
||||
|
||||
std::free(time);
|
||||
}
|
||||
|
||||
ptr->magic = 0;
|
||||
ptr->prev->next = ptr->next;
|
||||
ptr->next->prev = ptr->prev;
|
||||
|
||||
std::free(ptr);
|
||||
|
||||
nextFreeFile = nullptr;
|
||||
nextFreeLine = 0;
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
LeaveCriticalSection(&mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_unlock(&mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NzMemoryManager::NextFree(const char* file, unsigned int line)
|
||||
{
|
||||
nextFreeFile = file;
|
||||
nextFreeLine = line;
|
||||
}
|
||||
|
||||
void NzMemoryManager::Initialize()
|
||||
{
|
||||
char* time = TimeInfo();
|
||||
|
||||
FILE* file = std::fopen(MLTFileName, "w");
|
||||
std::fprintf(file, "%s ==============================\n", time);
|
||||
std::fprintf(file, "%s Nazara Memory Leak Tracker \n", time);
|
||||
std::fprintf(file, "%s ==============================\n", time);
|
||||
std::fclose(file);
|
||||
|
||||
std::free(time);
|
||||
|
||||
if (std::atexit(Uninitialize) != 0)
|
||||
{
|
||||
static NzMemoryManager manager;
|
||||
}
|
||||
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS
|
||||
InitializeCriticalSection(&mutex);
|
||||
#endif
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
char* NzMemoryManager::TimeInfo()
|
||||
{
|
||||
char* buffer = reinterpret_cast<char*>(std::malloc(23*sizeof(char)));
|
||||
|
||||
time_t currentTime = std::time(nullptr);
|
||||
std::strftime(buffer, 23, "%d/%m/%Y - %H:%M:%S:", std::localtime(¤tTime));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void NzMemoryManager::Uninitialize()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS
|
||||
DeleteCriticalSection(&mutex);
|
||||
#endif
|
||||
|
||||
FILE* log = std::fopen(MLTFileName, "a");
|
||||
|
||||
char* time = TimeInfo();
|
||||
|
||||
std::fprintf(log, "%s Application finished, checking leaks...\n", time);
|
||||
|
||||
if (ptrList.next == &ptrList)
|
||||
{
|
||||
std::fprintf(log, "%s ==============================\n", time);
|
||||
std::fprintf(log, "%s No leak detected \n", time);
|
||||
std::fprintf(log, "%s ==============================", time);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fprintf(log, "%s ==============================\n", time);
|
||||
std::fprintf(log, "%s Leaks have been detected \n", time);
|
||||
std::fprintf(log, "%s ==============================\n\n", time);
|
||||
std::fputs("Leak list:\n", log);
|
||||
|
||||
Block* ptr = ptrList.next;
|
||||
unsigned int count = 0;
|
||||
unsigned int totalSize = 0;
|
||||
while (ptr != &ptrList)
|
||||
{
|
||||
count++;
|
||||
totalSize += ptr->size;
|
||||
if (ptr->file)
|
||||
std::fprintf(log, "-0x%p -> %d bytes allocated at %s:%d\n", reinterpret_cast<char*>(ptr)+sizeof(Block), ptr->size, ptr->file, ptr->line);
|
||||
else
|
||||
std::fprintf(log, "-0x%p -> %d bytes allocated at unknown position\n", reinterpret_cast<char*>(ptr)+sizeof(Block), ptr->size);
|
||||
|
||||
void* pointer = ptr;
|
||||
ptr = ptr->next;
|
||||
std::free(pointer);
|
||||
}
|
||||
|
||||
std::fprintf(log, "\n%d blocks leaked (%d bytes)", count, totalSize);
|
||||
}
|
||||
|
||||
std::free(time);
|
||||
std::fclose(log);
|
||||
}
|
||||
|
||||
void* operator new(std::size_t size, const char* file, unsigned int line)
|
||||
{
|
||||
return NzMemoryManager::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);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr, const char* file, unsigned int line) throw()
|
||||
{
|
||||
NzMemoryManager::NextFree(file, line);
|
||||
NzMemoryManager::Free(ptr, false);
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr, const char* file, unsigned int line) throw()
|
||||
{
|
||||
NzMemoryManager::NextFree(file, line);
|
||||
NzMemoryManager::Free(ptr, true);
|
||||
}
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Core module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Core/Debug/MemoryLeakTracker.hpp>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <windows.h>
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Block
|
||||
{
|
||||
std::size_t size;
|
||||
const char* file;
|
||||
Block* prev;
|
||||
Block* next;
|
||||
bool array;
|
||||
unsigned int line;
|
||||
unsigned int magic;
|
||||
};
|
||||
|
||||
bool initialized = false;
|
||||
const unsigned int magic = 0x51429EE;
|
||||
const char* MLTFileName = "NazaraLeaks.log";
|
||||
const char* nextFreeFile = "Internal error";
|
||||
unsigned int nextFreeLine = 0;
|
||||
|
||||
Block ptrList =
|
||||
{
|
||||
0,
|
||||
nullptr,
|
||||
&ptrList,
|
||||
&ptrList,
|
||||
false,
|
||||
0,
|
||||
magic
|
||||
};
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
CRITICAL_SECTION mutex;
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_t 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 (!initialized)
|
||||
Initialize();
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
EnterCriticalSection(&mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_lock(&mutex);
|
||||
#endif
|
||||
|
||||
Block* ptr = reinterpret_cast<Block*>(std::malloc(size+sizeof(Block)));
|
||||
if (!ptr)
|
||||
{
|
||||
// Pas d'information de temps (Car nécessitant une allocation)
|
||||
FILE* log = std::fopen(MLTFileName, "a");
|
||||
std::fprintf(log, "Failed to allocate memory (%d bytes)\n", size);
|
||||
std::fclose(log);
|
||||
|
||||
return nullptr; // Impossible d'envoyer une exception car cela allouerait de la mémoire avec new (boucle infinie)
|
||||
}
|
||||
|
||||
ptr->array = multi;
|
||||
ptr->file = file;
|
||||
ptr->line = line;
|
||||
ptr->size = size;
|
||||
ptr->magic = magic;
|
||||
|
||||
ptr->prev = ptrList.prev;
|
||||
ptr->next = &ptrList;
|
||||
ptrList.prev->next = ptr;
|
||||
ptrList.prev = ptr;
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
LeaveCriticalSection(&mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_unlock(&mutex);
|
||||
#endif
|
||||
|
||||
return reinterpret_cast<char*>(ptr)+sizeof(Block);
|
||||
}
|
||||
|
||||
void NzMemoryManager::Free(void* pointer, bool multi)
|
||||
{
|
||||
if (!pointer)
|
||||
return;
|
||||
|
||||
Block* ptr = reinterpret_cast<Block*>(reinterpret_cast<char*>(pointer)-sizeof(Block));
|
||||
if (ptr->magic != magic)
|
||||
return;
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
EnterCriticalSection(&mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_lock(&mutex);
|
||||
#endif
|
||||
|
||||
if (ptr->array != multi)
|
||||
{
|
||||
char* time = TimeInfo();
|
||||
|
||||
FILE* log = std::fopen(MLTFileName, "a");
|
||||
|
||||
if (nextFreeFile)
|
||||
{
|
||||
if (multi)
|
||||
std::fprintf(log, "%s Warning: delete[] after new at %s:%d\n", time, nextFreeFile, nextFreeLine);
|
||||
else
|
||||
std::fprintf(log, "%s Warning: delete after new[] at %s:%d\n", time, nextFreeFile, nextFreeLine);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (multi)
|
||||
std::fprintf(log, "%s Warning: delete[] after new at unknown position\n", time);
|
||||
else
|
||||
std::fprintf(log, "%s Warning: delete after new[] at unknown position\n", time);
|
||||
}
|
||||
|
||||
std::fclose(log);
|
||||
|
||||
std::free(time);
|
||||
}
|
||||
|
||||
ptr->magic = 0;
|
||||
ptr->prev->next = ptr->next;
|
||||
ptr->next->prev = ptr->prev;
|
||||
|
||||
std::free(ptr);
|
||||
|
||||
nextFreeFile = nullptr;
|
||||
nextFreeLine = 0;
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
LeaveCriticalSection(&mutex);
|
||||
#elif defined(NAZARA_PLATFORM_POSIX)
|
||||
pthread_mutex_unlock(&mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NzMemoryManager::NextFree(const char* file, unsigned int line)
|
||||
{
|
||||
nextFreeFile = file;
|
||||
nextFreeLine = line;
|
||||
}
|
||||
|
||||
void NzMemoryManager::Initialize()
|
||||
{
|
||||
char* time = TimeInfo();
|
||||
|
||||
FILE* file = std::fopen(MLTFileName, "w");
|
||||
std::fprintf(file, "%s ==============================\n", time);
|
||||
std::fprintf(file, "%s Nazara Memory Leak Tracker \n", time);
|
||||
std::fprintf(file, "%s ==============================\n", time);
|
||||
std::fclose(file);
|
||||
|
||||
std::free(time);
|
||||
|
||||
if (std::atexit(Uninitialize) != 0)
|
||||
{
|
||||
static NzMemoryManager manager;
|
||||
}
|
||||
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS
|
||||
InitializeCriticalSection(&mutex);
|
||||
#endif
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
char* NzMemoryManager::TimeInfo()
|
||||
{
|
||||
char* buffer = reinterpret_cast<char*>(std::malloc(23*sizeof(char)));
|
||||
|
||||
time_t currentTime = std::time(nullptr);
|
||||
std::strftime(buffer, 23, "%d/%m/%Y - %H:%M:%S:", std::localtime(¤tTime));
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void NzMemoryManager::Uninitialize()
|
||||
{
|
||||
#ifdef NAZARA_PLATFORM_WINDOWS
|
||||
DeleteCriticalSection(&mutex);
|
||||
#endif
|
||||
|
||||
FILE* log = std::fopen(MLTFileName, "a");
|
||||
|
||||
char* time = TimeInfo();
|
||||
|
||||
std::fprintf(log, "%s Application finished, checking leaks...\n", time);
|
||||
|
||||
if (ptrList.next == &ptrList)
|
||||
{
|
||||
std::fprintf(log, "%s ==============================\n", time);
|
||||
std::fprintf(log, "%s No leak detected \n", time);
|
||||
std::fprintf(log, "%s ==============================", time);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fprintf(log, "%s ==============================\n", time);
|
||||
std::fprintf(log, "%s Leaks have been detected \n", time);
|
||||
std::fprintf(log, "%s ==============================\n\n", time);
|
||||
std::fputs("Leak list:\n", log);
|
||||
|
||||
Block* ptr = ptrList.next;
|
||||
unsigned int count = 0;
|
||||
unsigned int totalSize = 0;
|
||||
while (ptr != &ptrList)
|
||||
{
|
||||
count++;
|
||||
totalSize += ptr->size;
|
||||
if (ptr->file)
|
||||
std::fprintf(log, "-0x%p -> %d bytes allocated at %s:%d\n", reinterpret_cast<char*>(ptr)+sizeof(Block), ptr->size, ptr->file, ptr->line);
|
||||
else
|
||||
std::fprintf(log, "-0x%p -> %d bytes allocated at unknown position\n", reinterpret_cast<char*>(ptr)+sizeof(Block), ptr->size);
|
||||
|
||||
void* pointer = ptr;
|
||||
ptr = ptr->next;
|
||||
std::free(pointer);
|
||||
}
|
||||
|
||||
std::fprintf(log, "\n%d blocks leaked (%d bytes)", count, totalSize);
|
||||
}
|
||||
|
||||
std::free(time);
|
||||
std::fclose(log);
|
||||
}
|
||||
|
||||
void* operator new(std::size_t size, const char* file, unsigned int line)
|
||||
{
|
||||
return NzMemoryManager::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);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr, const char* file, unsigned int line) throw()
|
||||
{
|
||||
NzMemoryManager::NextFree(file, line);
|
||||
NzMemoryManager::Free(ptr, false);
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr, const char* file, unsigned int line) throw()
|
||||
{
|
||||
NzMemoryManager::NextFree(file, line);
|
||||
NzMemoryManager::Free(ptr, true);
|
||||
}
|
||||
|
||||
@@ -1,54 +1,138 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Core module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Core/Resource.hpp>
|
||||
#include <Nazara/Core/Config.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzResource::NzResource(bool persistent) :
|
||||
m_resourcePersistent(persistent),
|
||||
m_resourceReferenceCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
NzResource::NzResource(const NzResource& resource) :
|
||||
m_resourcePersistent(resource.m_resourcePersistent),
|
||||
m_resourceReferenceCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
NzResource::~NzResource() = default;
|
||||
|
||||
void NzResource::AddResourceReference() const
|
||||
{
|
||||
m_resourceReferenceCount++;
|
||||
}
|
||||
|
||||
bool NzResource::IsPersistent() const
|
||||
{
|
||||
return m_resourcePersistent;
|
||||
}
|
||||
|
||||
void NzResource::RemoveResourceReference() const
|
||||
{
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (m_resourceReferenceCount == 0)
|
||||
{
|
||||
NazaraError("Impossible to remove reference (Ref. counter is already 0)");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (--m_resourceReferenceCount == 0 && !m_resourcePersistent)
|
||||
delete this;
|
||||
}
|
||||
|
||||
void NzResource::SetPersistent(bool persistent)
|
||||
{
|
||||
m_resourcePersistent = persistent;
|
||||
|
||||
if (!persistent && m_resourceReferenceCount == 0)
|
||||
delete this;
|
||||
}
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Core module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Core/Resource.hpp>
|
||||
#include <Nazara/Core/Config.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/ResourceListener.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzResource::NzResource(bool persistent) :
|
||||
m_resourcePersistent(persistent),
|
||||
m_resourceReferenceCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
NzResource::NzResource(const NzResource& resource) :
|
||||
m_resourcePersistent(resource.m_resourcePersistent),
|
||||
m_resourceReferenceCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
NzResource::~NzResource()
|
||||
{
|
||||
EnsureResourceListenerUpdate();
|
||||
|
||||
for (auto it = m_resourceListenersCache.begin(); it != m_resourceListenersCache.end(); ++it)
|
||||
(*it).listener->OnResourceReleased(this, (*it).index);
|
||||
}
|
||||
|
||||
void NzResource::AddResourceListener(NzResourceListener* listener, int index) const
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
if (m_resourceListeners.insert(NzResourceEntry(listener, index)).second)
|
||||
{
|
||||
m_resourceListenerUpdated = false;
|
||||
|
||||
// AddResourceReference()
|
||||
m_resourceReferenceCount++;
|
||||
}
|
||||
}
|
||||
|
||||
void NzResource::AddResourceReference() const
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
m_resourceReferenceCount++;
|
||||
}
|
||||
|
||||
bool NzResource::IsPersistent() const
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
return m_resourcePersistent;
|
||||
}
|
||||
|
||||
void NzResource::RemoveResourceListener(NzResourceListener* listener) const
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
if (m_resourceListeners.erase(listener) != 0)
|
||||
m_resourceListenerUpdated = false;
|
||||
else
|
||||
NazaraError(NzString::Pointer(listener) + " is not listening to " + NzString::Pointer(this));
|
||||
|
||||
RemoveResourceReference();
|
||||
}
|
||||
|
||||
void NzResource::RemoveResourceReference() const
|
||||
{
|
||||
NazaraMutexLock(m_mutex);
|
||||
|
||||
#if NAZARA_CORE_SAFE
|
||||
if (m_resourceReferenceCount == 0)
|
||||
{
|
||||
NazaraError("Impossible to remove reference (Ref. counter is already 0)");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (--m_resourceReferenceCount == 0 && !m_resourcePersistent)
|
||||
{
|
||||
NazaraMutexUnlock(m_mutex);
|
||||
delete this;
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraMutexUnlock(m_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void NzResource::SetPersistent(bool persistent)
|
||||
{
|
||||
NazaraMutexLock(m_mutex);
|
||||
|
||||
m_resourcePersistent = persistent;
|
||||
|
||||
if (!persistent && m_resourceReferenceCount == 0)
|
||||
{
|
||||
NazaraMutexUnlock(m_mutex);
|
||||
delete this;
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraMutexUnlock(m_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void NzResource::NotifyCreated()
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
EnsureResourceListenerUpdate();
|
||||
|
||||
for (auto it = m_resourceListenersCache.begin(); it != m_resourceListenersCache.end(); ++it)
|
||||
(*it).listener->OnResourceCreated(this, (*it).index);
|
||||
}
|
||||
|
||||
void NzResource::NotifyDestroy()
|
||||
{
|
||||
NazaraLock(m_mutex)
|
||||
|
||||
EnsureResourceListenerUpdate();
|
||||
|
||||
for (auto it = m_resourceListenersCache.begin(); it != m_resourceListenersCache.end(); ++it)
|
||||
(*it).listener->OnResourceDestroy(this, (*it).index);
|
||||
}
|
||||
|
||||
void NzResource::EnsureResourceListenerUpdate() const
|
||||
{
|
||||
// Déjà bloqué par une mutex
|
||||
if (!m_resourceListenerUpdated)
|
||||
{
|
||||
m_resourceListenersCache = m_resourceListeners;
|
||||
m_resourceListenerUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
26
src/Nazara/Core/ResourceListener.cpp
Normal file
26
src/Nazara/Core/ResourceListener.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Core module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Core/ResourceListener.hpp>
|
||||
#include <Nazara/Core/Debug.hpp>
|
||||
|
||||
NzResourceListener::~NzResourceListener() = default;
|
||||
|
||||
void NzResourceListener::OnResourceCreated(const NzResource* resource, int index)
|
||||
{
|
||||
NazaraUnused(resource);
|
||||
NazaraUnused(index);
|
||||
}
|
||||
|
||||
void NzResourceListener::OnResourceDestroy(const NzResource* resource, int index)
|
||||
{
|
||||
NazaraUnused(resource);
|
||||
NazaraUnused(index);
|
||||
}
|
||||
|
||||
void NzResourceListener::OnResourceReleased(const NzResource* resource, int index)
|
||||
{
|
||||
NazaraUnused(resource);
|
||||
NazaraUnused(index);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,355 +1,359 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/StringStream.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <vector>
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Renderer/Win32/ContextImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_LINUX)
|
||||
#include <Nazara/Renderer/Linux/ContextImpl.hpp>
|
||||
#else
|
||||
#error Lack of implementation: Context
|
||||
#endif
|
||||
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
NAZARA_THREADLOCAL NzContext* currentContext = nullptr;
|
||||
NAZARA_THREADLOCAL NzContext* threadContext = nullptr;
|
||||
|
||||
std::vector<NzContext*> contexts;
|
||||
|
||||
void CALLBACK DebugCallback(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, int length, const char* message, void* userParam)
|
||||
{
|
||||
NazaraUnused(length);
|
||||
|
||||
NzStringStream ss;
|
||||
ss << "OpenGL debug message (ID: 0x" << NzString::Number(id, 16) << "):\n";
|
||||
ss << "Sent by context: " << userParam;
|
||||
ss << "\n-Source: ";
|
||||
switch (source)
|
||||
{
|
||||
case GL_DEBUG_SOURCE_API_ARB:
|
||||
ss << "OpenGL";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
|
||||
ss << "Operating system";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
|
||||
ss << "Shader compiler";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
|
||||
ss << "Shader compiler";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_APPLICATION_ARB:
|
||||
ss << "Application";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_OTHER_ARB:
|
||||
ss << "Other";
|
||||
break;
|
||||
|
||||
default:
|
||||
// Peut être rajouté par une extension
|
||||
ss << "Unknown";
|
||||
break;
|
||||
}
|
||||
ss << '\n';
|
||||
|
||||
ss << "-Type: ";
|
||||
switch (type)
|
||||
{
|
||||
case GL_DEBUG_TYPE_ERROR_ARB:
|
||||
ss << "Error";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
|
||||
ss << "Deprecated behavior";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
|
||||
ss << "Undefined behavior";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_PORTABILITY_ARB:
|
||||
ss << "Portability";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_PERFORMANCE_ARB:
|
||||
ss << "Performance";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_OTHER_ARB:
|
||||
ss << "Other";
|
||||
break;
|
||||
|
||||
default:
|
||||
// Peut être rajouté par une extension
|
||||
ss << "Unknown";
|
||||
break;
|
||||
}
|
||||
ss << '\n';
|
||||
|
||||
ss << "-Severity: ";
|
||||
switch (severity)
|
||||
{
|
||||
case GL_DEBUG_SEVERITY_HIGH_ARB:
|
||||
ss << "High";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SEVERITY_MEDIUM_ARB:
|
||||
ss << "Medium";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SEVERITY_LOW_ARB:
|
||||
ss << "Low";
|
||||
break;
|
||||
|
||||
default:
|
||||
// Peut être rajouté par une extension
|
||||
ss << "Unknown";
|
||||
break;
|
||||
}
|
||||
ss << '\n';
|
||||
|
||||
ss << "Message: " << message << '\n';
|
||||
|
||||
NazaraNotice(ss);
|
||||
}
|
||||
}
|
||||
|
||||
NzContext::NzContext() :
|
||||
m_impl(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
NzContext::~NzContext()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzContext::Create(const NzContextParameters& parameters)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
m_parameters = parameters;
|
||||
if (m_parameters.shared && !m_parameters.shareContext)
|
||||
m_parameters.shareContext = s_reference;
|
||||
|
||||
m_impl = new NzContextImpl;
|
||||
if (!m_impl->Create(m_parameters))
|
||||
{
|
||||
NazaraError("Failed to create context implementation");
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_impl->Activate())
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
|
||||
m_impl->Destroy();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_parameters.antialiasingLevel > 0)
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
|
||||
if (NzOpenGL::IsSupported(NzOpenGL::DebugOutput) && m_parameters.debugMode)
|
||||
{
|
||||
glDebugMessageCallback(&DebugCallback, this);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzContext::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
if (currentContext == this)
|
||||
NzContextImpl::Desactivate();
|
||||
|
||||
m_impl->Destroy();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const NzContextParameters& NzContext::GetParameters() const
|
||||
{
|
||||
#ifdef NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
NazaraError("No context has been created");
|
||||
#endif
|
||||
|
||||
return m_parameters;
|
||||
}
|
||||
|
||||
bool NzContext::IsActive() const
|
||||
{
|
||||
#ifdef NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("No context has been created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return currentContext == this;
|
||||
}
|
||||
|
||||
bool NzContext::SetActive(bool active)
|
||||
{
|
||||
#ifdef NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("No context has been created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Si le contexte est déjà activé/désactivé
|
||||
if ((currentContext == this) == active)
|
||||
return true;
|
||||
|
||||
if (active)
|
||||
{
|
||||
if (!m_impl->Activate())
|
||||
return false;
|
||||
|
||||
currentContext = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!NzContextImpl::Desactivate())
|
||||
return false;
|
||||
|
||||
currentContext = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzContext::SwapBuffers()
|
||||
{
|
||||
#ifdef NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("No context has been created");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_parameters.doubleBuffered)
|
||||
{
|
||||
NazaraError("Context is not double buffered");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SwapBuffers();
|
||||
}
|
||||
|
||||
bool NzContext::EnsureContext()
|
||||
{
|
||||
if (!currentContext)
|
||||
{
|
||||
if (!threadContext)
|
||||
{
|
||||
NzContext* context = new NzContext;
|
||||
if (!context->Create())
|
||||
{
|
||||
NazaraError("Failed to create context");
|
||||
delete context;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
contexts.push_back(context);
|
||||
|
||||
threadContext = context;
|
||||
}
|
||||
|
||||
if (!threadContext->SetActive(true))
|
||||
{
|
||||
NazaraError("Failed to active thread context");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NzContext* NzContext::GetCurrent()
|
||||
{
|
||||
return currentContext;
|
||||
}
|
||||
|
||||
const NzContext* NzContext::GetReference()
|
||||
{
|
||||
return s_reference;
|
||||
}
|
||||
|
||||
NzContext* NzContext::GetThreadContext()
|
||||
{
|
||||
EnsureContext();
|
||||
|
||||
return threadContext;
|
||||
}
|
||||
|
||||
bool NzContext::Initialize()
|
||||
{
|
||||
NzContextParameters parameters;
|
||||
// parameters.compatibilityProfile = true;
|
||||
parameters.shared = false; // Difficile de partager le contexte de référence avec lui-même
|
||||
|
||||
s_reference = new NzContext;
|
||||
if (!s_reference->Create(parameters))
|
||||
{
|
||||
delete s_reference;
|
||||
s_reference = nullptr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Le contexte de référence doit rester désactivé pour le partage
|
||||
s_reference->SetActive(false);
|
||||
|
||||
NzContextParameters::defaultShareContext = s_reference;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzContext::Uninitialize()
|
||||
{
|
||||
for (NzContext* context : contexts)
|
||||
delete context;
|
||||
|
||||
contexts.clear(); // On supprime tous les contextes créés
|
||||
|
||||
delete s_reference;
|
||||
s_reference = nullptr;
|
||||
}
|
||||
|
||||
NzContext* NzContext::s_reference = nullptr;
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/StringStream.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <vector>
|
||||
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
#include <Nazara/Renderer/Win32/ContextImpl.hpp>
|
||||
#elif defined(NAZARA_PLATFORM_LINUX)
|
||||
#include <Nazara/Renderer/Linux/ContextImpl.hpp>
|
||||
#else
|
||||
#error Lack of implementation: Context
|
||||
#endif
|
||||
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
NAZARA_THREADLOCAL NzContext* currentContext = nullptr;
|
||||
NAZARA_THREADLOCAL NzContext* threadContext = nullptr;
|
||||
|
||||
std::vector<NzContext*> contexts;
|
||||
|
||||
void CALLBACK DebugCallback(unsigned int source, unsigned int type, unsigned int id, unsigned int severity, int length, const char* message, void* userParam)
|
||||
{
|
||||
NazaraUnused(length);
|
||||
|
||||
NzStringStream ss;
|
||||
ss << "OpenGL debug message (ID: 0x" << NzString::Number(id, 16) << "):\n";
|
||||
ss << "Sent by context: " << userParam;
|
||||
ss << "\n-Source: ";
|
||||
switch (source)
|
||||
{
|
||||
case GL_DEBUG_SOURCE_API_ARB:
|
||||
ss << "OpenGL";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB:
|
||||
ss << "Operating system";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_SHADER_COMPILER_ARB:
|
||||
ss << "Shader compiler";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_THIRD_PARTY_ARB:
|
||||
ss << "Shader compiler";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_APPLICATION_ARB:
|
||||
ss << "Application";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SOURCE_OTHER_ARB:
|
||||
ss << "Other";
|
||||
break;
|
||||
|
||||
default:
|
||||
// Peut être rajouté par une extension
|
||||
ss << "Unknown";
|
||||
break;
|
||||
}
|
||||
ss << '\n';
|
||||
|
||||
ss << "-Type: ";
|
||||
switch (type)
|
||||
{
|
||||
case GL_DEBUG_TYPE_ERROR_ARB:
|
||||
ss << "Error";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB:
|
||||
ss << "Deprecated behavior";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB:
|
||||
ss << "Undefined behavior";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_PORTABILITY_ARB:
|
||||
ss << "Portability";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_PERFORMANCE_ARB:
|
||||
ss << "Performance";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_TYPE_OTHER_ARB:
|
||||
ss << "Other";
|
||||
break;
|
||||
|
||||
default:
|
||||
// Peut être rajouté par une extension
|
||||
ss << "Unknown";
|
||||
break;
|
||||
}
|
||||
ss << '\n';
|
||||
|
||||
ss << "-Severity: ";
|
||||
switch (severity)
|
||||
{
|
||||
case GL_DEBUG_SEVERITY_HIGH_ARB:
|
||||
ss << "High";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SEVERITY_MEDIUM_ARB:
|
||||
ss << "Medium";
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SEVERITY_LOW_ARB:
|
||||
ss << "Low";
|
||||
break;
|
||||
|
||||
default:
|
||||
// Peut être rajouté par une extension
|
||||
ss << "Unknown";
|
||||
break;
|
||||
}
|
||||
ss << '\n';
|
||||
|
||||
ss << "Message: " << message << '\n';
|
||||
|
||||
NazaraNotice(ss);
|
||||
}
|
||||
}
|
||||
|
||||
NzContext::NzContext() :
|
||||
m_impl(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
NzContext::~NzContext()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzContext::Create(const NzContextParameters& parameters)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
m_parameters = parameters;
|
||||
if (m_parameters.shared && !m_parameters.shareContext)
|
||||
m_parameters.shareContext = s_reference;
|
||||
|
||||
m_impl = new NzContextImpl;
|
||||
if (!m_impl->Create(m_parameters))
|
||||
{
|
||||
NazaraError("Failed to create context implementation");
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_impl->Activate())
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
|
||||
m_impl->Destroy();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_parameters.antialiasingLevel > 0)
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
|
||||
if (NzOpenGL::IsSupported(nzOpenGLExtension_DebugOutput) && m_parameters.debugMode)
|
||||
{
|
||||
glDebugMessageCallback(&DebugCallback, this);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
#endif
|
||||
}
|
||||
|
||||
NotifyCreated();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzContext::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
NotifyDestroy();
|
||||
|
||||
if (currentContext == this)
|
||||
NzContextImpl::Desactivate();
|
||||
|
||||
m_impl->Destroy();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const NzContextParameters& NzContext::GetParameters() const
|
||||
{
|
||||
#ifdef NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
NazaraError("No context has been created");
|
||||
#endif
|
||||
|
||||
return m_parameters;
|
||||
}
|
||||
|
||||
bool NzContext::IsActive() const
|
||||
{
|
||||
#ifdef NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("No context has been created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return currentContext == this;
|
||||
}
|
||||
|
||||
bool NzContext::SetActive(bool active)
|
||||
{
|
||||
#ifdef NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("No context has been created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Si le contexte est déjà activé/désactivé
|
||||
if ((currentContext == this) == active)
|
||||
return true;
|
||||
|
||||
if (active)
|
||||
{
|
||||
if (!m_impl->Activate())
|
||||
return false;
|
||||
|
||||
currentContext = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!NzContextImpl::Desactivate())
|
||||
return false;
|
||||
|
||||
currentContext = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzContext::SwapBuffers()
|
||||
{
|
||||
#ifdef NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("No context has been created");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_parameters.doubleBuffered)
|
||||
{
|
||||
NazaraError("Context is not double buffered");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->SwapBuffers();
|
||||
}
|
||||
|
||||
bool NzContext::EnsureContext()
|
||||
{
|
||||
if (!currentContext)
|
||||
{
|
||||
if (!threadContext)
|
||||
{
|
||||
NzContext* context = new NzContext;
|
||||
if (!context->Create())
|
||||
{
|
||||
NazaraError("Failed to create context");
|
||||
delete context;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
contexts.push_back(context);
|
||||
|
||||
threadContext = context;
|
||||
}
|
||||
|
||||
if (!threadContext->SetActive(true))
|
||||
{
|
||||
NazaraError("Failed to active thread context");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NzContext* NzContext::GetCurrent()
|
||||
{
|
||||
return currentContext;
|
||||
}
|
||||
|
||||
const NzContext* NzContext::GetReference()
|
||||
{
|
||||
return s_reference;
|
||||
}
|
||||
|
||||
NzContext* NzContext::GetThreadContext()
|
||||
{
|
||||
EnsureContext();
|
||||
|
||||
return threadContext;
|
||||
}
|
||||
|
||||
bool NzContext::Initialize()
|
||||
{
|
||||
NzContextParameters parameters;
|
||||
// parameters.compatibilityProfile = true;
|
||||
parameters.shared = false; // Difficile de partager le contexte de référence avec lui-même
|
||||
|
||||
s_reference = new NzContext;
|
||||
if (!s_reference->Create(parameters))
|
||||
{
|
||||
delete s_reference;
|
||||
s_reference = nullptr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Le contexte de référence doit rester désactivé pour le partage
|
||||
s_reference->SetActive(false);
|
||||
|
||||
NzContextParameters::defaultShareContext = s_reference;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzContext::Uninitialize()
|
||||
{
|
||||
for (NzContext* context : contexts)
|
||||
delete context;
|
||||
|
||||
contexts.clear(); // On supprime tous les contextes créés
|
||||
|
||||
delete s_reference;
|
||||
s_reference = nullptr;
|
||||
}
|
||||
|
||||
NzContext* NzContext::s_reference = nullptr;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,73 +1,81 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_GLSLSHADER_HPP
|
||||
#define NAZARA_GLSLSHADER_HPP
|
||||
|
||||
#include <Nazara/Core/String.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Shader.hpp>
|
||||
#include <Nazara/Renderer/ShaderImpl.hpp>
|
||||
#include <map>
|
||||
|
||||
class NzGLSLShader : public NzShaderImpl
|
||||
{
|
||||
public:
|
||||
NzGLSLShader(NzShader* parent);
|
||||
~NzGLSLShader();
|
||||
|
||||
bool Bind();
|
||||
bool BindTextures();
|
||||
|
||||
bool Compile();
|
||||
|
||||
bool Create();
|
||||
void Destroy();
|
||||
|
||||
NzString GetLog() const;
|
||||
nzShaderLanguage GetLanguage() const;
|
||||
NzString GetSourceCode(nzShaderType type) const;
|
||||
int GetUniformLocation(const NzString& name) const;
|
||||
|
||||
bool IsLoaded(nzShaderType type) const;
|
||||
|
||||
bool Load(nzShaderType type, const NzString& source);
|
||||
bool Lock();
|
||||
|
||||
bool SendBoolean(int location, bool value);
|
||||
bool SendDouble(int location, double value);
|
||||
bool SendFloat(int location, float value);
|
||||
bool SendInteger(int location, int value);
|
||||
bool SendMatrix(int location, const NzMatrix4d& matrix);
|
||||
bool SendMatrix(int location, const NzMatrix4f& matrix);
|
||||
bool SendTexture(int location, const NzTexture* texture);
|
||||
bool SendVector(int location, const NzVector2d& vector);
|
||||
bool SendVector(int location, const NzVector2f& vector);
|
||||
bool SendVector(int location, const NzVector3d& vector);
|
||||
bool SendVector(int location, const NzVector3f& vector);
|
||||
bool SendVector(int location, const NzVector4d& vector);
|
||||
bool SendVector(int location, const NzVector4f& vector);
|
||||
|
||||
void Unbind();
|
||||
void Unlock();
|
||||
|
||||
private:
|
||||
struct TextureSlot
|
||||
{
|
||||
bool updated = false;
|
||||
nzUInt8 unit;
|
||||
const NzTexture* texture;
|
||||
};
|
||||
|
||||
mutable std::map<NzString, GLint> m_idCache;
|
||||
std::map<GLint, TextureSlot> m_textures;
|
||||
GLuint m_program;
|
||||
GLuint m_shaders[nzShaderType_Max+1];
|
||||
NzShader* m_parent;
|
||||
NzString m_log;
|
||||
};
|
||||
|
||||
#endif // NAZARA_GLSLSHADER_HPPs
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NAZARA_GLSLSHADER_HPP
|
||||
#define NAZARA_GLSLSHADER_HPP
|
||||
|
||||
#include <Nazara/Core/ResourceListener.hpp>
|
||||
#include <Nazara/Core/String.hpp>
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Shader.hpp>
|
||||
#include <Nazara/Renderer/ShaderImpl.hpp>
|
||||
#include <map>
|
||||
|
||||
class NzResource;
|
||||
|
||||
class NzGLSLShader : public NzShaderImpl, NzResourceListener
|
||||
{
|
||||
public:
|
||||
NzGLSLShader(NzShader* parent);
|
||||
~NzGLSLShader();
|
||||
|
||||
bool Bind();
|
||||
bool BindTextures();
|
||||
|
||||
bool Compile();
|
||||
|
||||
bool Create();
|
||||
void Destroy();
|
||||
|
||||
NzString GetLog() const;
|
||||
nzShaderLanguage GetLanguage() const;
|
||||
NzString GetSourceCode(nzShaderType type) const;
|
||||
int GetUniformLocation(const NzString& name) const;
|
||||
|
||||
bool IsLoaded(nzShaderType type) const;
|
||||
|
||||
bool Load(nzShaderType type, const NzString& source);
|
||||
bool Lock();
|
||||
|
||||
bool SendBoolean(int location, bool value);
|
||||
bool SendDouble(int location, double value);
|
||||
bool SendFloat(int location, float value);
|
||||
bool SendInteger(int location, int value);
|
||||
bool SendMatrix(int location, const NzMatrix4d& matrix);
|
||||
bool SendMatrix(int location, const NzMatrix4f& matrix);
|
||||
bool SendTexture(int location, const NzTexture* texture);
|
||||
bool SendVector(int location, const NzVector2d& vector);
|
||||
bool SendVector(int location, const NzVector2f& vector);
|
||||
bool SendVector(int location, const NzVector3d& vector);
|
||||
bool SendVector(int location, const NzVector3f& vector);
|
||||
bool SendVector(int location, const NzVector4d& vector);
|
||||
bool SendVector(int location, const NzVector4f& vector);
|
||||
|
||||
void Unbind();
|
||||
void Unlock();
|
||||
|
||||
private:
|
||||
void OnResourceCreated(const NzResource* resource, int index) override;
|
||||
void OnResourceDestroy(const NzResource* resource, int index) override;
|
||||
void OnResourceReleased(const NzResource* resource, int index) override;
|
||||
|
||||
struct TextureSlot
|
||||
{
|
||||
bool enabled;
|
||||
bool updated = false;
|
||||
nzUInt8 unit;
|
||||
const NzTexture* texture;
|
||||
};
|
||||
|
||||
mutable std::map<NzString, GLint> m_idCache;
|
||||
std::map<GLint, TextureSlot> m_textures;
|
||||
GLuint m_program;
|
||||
GLuint m_shaders[nzShaderType_Max+1];
|
||||
NzShader* m_parent;
|
||||
NzString m_log;
|
||||
};
|
||||
|
||||
#endif // NAZARA_GLSLSHADER_HPPs
|
||||
|
||||
@@ -1,250 +1,218 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/HardwareBuffer.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
GLenum bufferLock[] = {
|
||||
GL_WRITE_ONLY, // nzBufferAccess_DiscardAndWrite
|
||||
GL_READ_ONLY, // nzBufferAccess_ReadOnly
|
||||
GL_READ_WRITE, // nzBufferAccess_ReadWrite
|
||||
GL_WRITE_ONLY // nzBufferAccess_WriteOnly
|
||||
};
|
||||
|
||||
GLenum bufferLockRange[] = {
|
||||
GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_DiscardAndWrite
|
||||
GL_MAP_READ_BIT, // nzBufferAccess_ReadOnly
|
||||
GL_MAP_READ_BIT | GL_MAP_WRITE_BIT, // nzBufferAccess_ReadWrite
|
||||
GL_MAP_WRITE_BIT // nzBufferAccess_WriteOnly
|
||||
};
|
||||
|
||||
GLenum bufferTarget[] = {
|
||||
GL_ELEMENT_ARRAY_BUFFER, // nzBufferType_Index,
|
||||
GL_ARRAY_BUFFER, // nzBufferType_Vertex
|
||||
};
|
||||
|
||||
GLenum bufferTargetBinding[] = {
|
||||
GL_ELEMENT_ARRAY_BUFFER_BINDING, // nzBufferType_Index,
|
||||
GL_ARRAY_BUFFER_BINDING, // nzBufferType_Vertex
|
||||
};
|
||||
|
||||
GLenum bufferUsage[] = {
|
||||
// J'ai choisi DYNAMIC à la place de STREAM car DYNAMIC semble plus adapté au profil "une mise à jour pour quelques rendus"
|
||||
// Ce qui est je pense le scénario qui arrivera le plus souvent (Prévoir une option pour permettre d'utiliser le STREAM_DRAW ?)
|
||||
// Source: http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=160839
|
||||
GL_DYNAMIC_DRAW, // nzBufferUsage_Dynamic
|
||||
GL_STATIC_DRAW // nzBufferUsage_Static
|
||||
};
|
||||
|
||||
using LockRoutine = nzUInt8* (*)(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size);
|
||||
|
||||
nzUInt8* LockBuffer(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size)
|
||||
{
|
||||
NazaraUnused(size);
|
||||
|
||||
if (access == nzBufferAccess_DiscardAndWrite)
|
||||
{
|
||||
GLint bufSize;
|
||||
glGetBufferParameteriv(bufferTargetBinding[type], GL_BUFFER_SIZE, &bufSize);
|
||||
|
||||
GLint bufUsage;
|
||||
glGetBufferParameteriv(bufferTargetBinding[type], GL_BUFFER_USAGE, &bufUsage);
|
||||
|
||||
// On discard le buffer
|
||||
glBufferData(bufferTargetBinding[type], bufSize, nullptr, bufUsage);
|
||||
}
|
||||
|
||||
void* ptr = glMapBuffer(bufferTarget[type], bufferLock[access]);
|
||||
if (ptr)
|
||||
return reinterpret_cast<nzUInt8*>(ptr) + offset;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nzUInt8* LockBufferRange(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size)
|
||||
{
|
||||
return reinterpret_cast<nzUInt8*>(glMapBufferRange(bufferTarget[type], offset, size, bufferLockRange[access]));
|
||||
}
|
||||
|
||||
nzUInt8* LockBufferFirstRun(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size);
|
||||
|
||||
LockRoutine mapBuffer = LockBufferFirstRun;
|
||||
|
||||
nzUInt8* LockBufferFirstRun(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size)
|
||||
{
|
||||
if (glMapBufferRange)
|
||||
mapBuffer = LockBufferRange;
|
||||
else
|
||||
mapBuffer = LockBuffer;
|
||||
|
||||
return mapBuffer(type, access, offset, size);
|
||||
}
|
||||
}
|
||||
|
||||
NzHardwareBuffer::NzHardwareBuffer(NzBuffer* parent, nzBufferType type) :
|
||||
m_type(type),
|
||||
m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
NzHardwareBuffer::~NzHardwareBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
void NzHardwareBuffer::Bind()
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (NzContext::GetCurrent() == nullptr)
|
||||
{
|
||||
NazaraError("No active context");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
glBindBuffer(bufferTarget[m_type], m_buffer);
|
||||
}
|
||||
|
||||
bool NzHardwareBuffer::Create(unsigned int size, nzBufferUsage usage)
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
m_buffer = 0;
|
||||
glGenBuffers(1, &m_buffer);
|
||||
|
||||
GLint previous;
|
||||
glGetIntegerv(bufferTargetBinding[m_type], &previous);
|
||||
|
||||
glBindBuffer(bufferTarget[m_type], m_buffer);
|
||||
glBufferData(bufferTarget[m_type], size, nullptr, bufferUsage[usage]);
|
||||
|
||||
// Pour ne pas perturber le rendu, on interfère pas avec le binding déjà présent
|
||||
if (previous != 0)
|
||||
glBindBuffer(bufferTarget[m_type], previous);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzHardwareBuffer::Destroy()
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
glDeleteBuffers(1, &m_buffer);
|
||||
}
|
||||
|
||||
bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int size)
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
GLuint previous;
|
||||
glGetIntegerv(bufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous));
|
||||
|
||||
if (previous != m_buffer)
|
||||
glBindBuffer(bufferTarget[m_type], m_buffer);
|
||||
|
||||
// Il semblerait que glBuffer(Sub)Data soit plus performant que glMapBuffer(Range) en dessous d'un certain seuil
|
||||
// http://www.stevestreeting.com/2007/03/17/glmapbuffer-vs-glbuffersubdata-the-return/
|
||||
if (size < 32*1024)
|
||||
{
|
||||
// http://www.opengl.org/wiki/Vertex_Specification_Best_Practices
|
||||
if (size == m_parent->GetSize())
|
||||
glBufferData(bufferTarget[m_type], m_parent->GetSize(), nullptr, bufferUsage[m_parent->GetUsage()]); // Discard
|
||||
|
||||
glBufferSubData(bufferTarget[m_type], offset, size, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
nzUInt8* ptr = mapBuffer(m_type, (size == m_parent->GetSize()) ? nzBufferAccess_DiscardAndWrite : nzBufferAccess_WriteOnly, offset, size);
|
||||
if (!ptr)
|
||||
{
|
||||
NazaraError("Failed to map buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::memcpy(ptr, data, size);
|
||||
|
||||
if (glUnmapBuffer(bufferTarget[m_type]) != GL_TRUE)
|
||||
{
|
||||
// Une erreur rare est survenue, nous devons réinitialiser le buffer
|
||||
NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')');
|
||||
|
||||
glBufferData(bufferTarget[m_type], m_parent->GetSize(), nullptr, bufferUsage[m_parent->GetStorage()]);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérations chaînées)
|
||||
if (previous != m_buffer && previous != 0)
|
||||
glBindBuffer(bufferTarget[m_type], previous);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void* NzHardwareBuffer::GetPointer()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool NzHardwareBuffer::IsHardware() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void* NzHardwareBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned int size)
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
// Pour ne pas perturber le rendu, on interfère pas avec le binding déjà présent
|
||||
GLuint previous;
|
||||
glGetIntegerv(bufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous));
|
||||
|
||||
if (previous != m_buffer)
|
||||
glBindBuffer(bufferTarget[m_type], m_buffer);
|
||||
|
||||
void* ptr = mapBuffer(m_type, access, offset, size);
|
||||
|
||||
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérrations chaînées)
|
||||
if (previous != m_buffer && previous != 0)
|
||||
glBindBuffer(bufferTarget[m_type], previous);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool NzHardwareBuffer::Unmap()
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
GLuint previous;
|
||||
glGetIntegerv(bufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous));
|
||||
|
||||
if (previous != m_buffer)
|
||||
glBindBuffer(bufferTarget[m_type], m_buffer);
|
||||
|
||||
if (glUnmapBuffer(bufferTarget[m_type]) != GL_TRUE)
|
||||
{
|
||||
// Une erreur rare est survenue, nous devons réinitialiser le buffer
|
||||
NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')');
|
||||
|
||||
glBufferData(bufferTarget[m_type], m_parent->GetSize(), nullptr, bufferUsage[m_parent->GetStorage()]);
|
||||
|
||||
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérations chaînées)
|
||||
if (previous != m_buffer && previous != 0)
|
||||
glBindBuffer(bufferTarget[m_type], previous);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérations chaînées)
|
||||
if (previous != m_buffer && previous != 0)
|
||||
glBindBuffer(bufferTarget[m_type], previous);
|
||||
|
||||
return true;
|
||||
}
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/HardwareBuffer.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
using LockRoutine = nzUInt8* (*)(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size);
|
||||
|
||||
nzUInt8* LockBuffer(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size)
|
||||
{
|
||||
NazaraUnused(size);
|
||||
|
||||
if (access == nzBufferAccess_DiscardAndWrite)
|
||||
{
|
||||
GLint bufSize;
|
||||
glGetBufferParameteriv(NzOpenGL::BufferTargetBinding[type], GL_BUFFER_SIZE, &bufSize);
|
||||
|
||||
GLint bufUsage;
|
||||
glGetBufferParameteriv(NzOpenGL::BufferTargetBinding[type], GL_BUFFER_USAGE, &bufUsage);
|
||||
|
||||
// On discard le buffer
|
||||
glBufferData(NzOpenGL::BufferTargetBinding[type], bufSize, nullptr, bufUsage);
|
||||
}
|
||||
|
||||
void* ptr = glMapBuffer(NzOpenGL::BufferTarget[type], NzOpenGL::BufferLock[access]);
|
||||
if (ptr)
|
||||
return reinterpret_cast<nzUInt8*>(ptr) + offset;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nzUInt8* LockBufferRange(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size)
|
||||
{
|
||||
return reinterpret_cast<nzUInt8*>(glMapBufferRange(NzOpenGL::BufferTarget[type], offset, size, NzOpenGL::BufferLockRange[access]));
|
||||
}
|
||||
|
||||
nzUInt8* LockBufferFirstRun(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size);
|
||||
|
||||
LockRoutine mapBuffer = LockBufferFirstRun;
|
||||
|
||||
nzUInt8* LockBufferFirstRun(nzBufferType type, nzBufferAccess access, unsigned int offset, unsigned int size)
|
||||
{
|
||||
if (glMapBufferRange)
|
||||
mapBuffer = LockBufferRange;
|
||||
else
|
||||
mapBuffer = LockBuffer;
|
||||
|
||||
return mapBuffer(type, access, offset, size);
|
||||
}
|
||||
}
|
||||
|
||||
NzHardwareBuffer::NzHardwareBuffer(NzBuffer* parent, nzBufferType type) :
|
||||
m_type(type),
|
||||
m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
NzHardwareBuffer::~NzHardwareBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
void NzHardwareBuffer::Bind()
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (NzContext::GetCurrent() == nullptr)
|
||||
{
|
||||
NazaraError("No active context");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
glBindBuffer(NzOpenGL::BufferTarget[m_type], m_buffer);
|
||||
}
|
||||
|
||||
bool NzHardwareBuffer::Create(unsigned int size, nzBufferUsage usage)
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
m_buffer = 0;
|
||||
glGenBuffers(1, &m_buffer);
|
||||
|
||||
GLint previous;
|
||||
glGetIntegerv(NzOpenGL::BufferTargetBinding[m_type], &previous);
|
||||
|
||||
glBindBuffer(NzOpenGL::BufferTarget[m_type], m_buffer);
|
||||
glBufferData(NzOpenGL::BufferTarget[m_type], size, nullptr, NzOpenGL::BufferUsage[usage]);
|
||||
|
||||
// Pour ne pas perturber le rendu, on interfère pas avec le binding déjà présent
|
||||
if (previous != 0)
|
||||
glBindBuffer(NzOpenGL::BufferTarget[m_type], previous);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzHardwareBuffer::Destroy()
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
glDeleteBuffers(1, &m_buffer);
|
||||
}
|
||||
|
||||
bool NzHardwareBuffer::Fill(const void* data, unsigned int offset, unsigned int size)
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
GLuint previous;
|
||||
glGetIntegerv(NzOpenGL::BufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous));
|
||||
|
||||
if (previous != m_buffer)
|
||||
glBindBuffer(NzOpenGL::BufferTarget[m_type], m_buffer);
|
||||
|
||||
// Il semblerait que glBuffer(Sub)Data soit plus performant que glMapBuffer(Range) en dessous d'un certain seuil
|
||||
// http://www.stevestreeting.com/2007/03/17/glmapbuffer-vs-glbuffersubdata-the-return/
|
||||
if (size < 32*1024)
|
||||
{
|
||||
// http://www.opengl.org/wiki/Vertex_Specification_Best_Practices
|
||||
if (size == m_parent->GetSize())
|
||||
glBufferData(NzOpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, NzOpenGL::BufferUsage[m_parent->GetUsage()]); // Discard
|
||||
|
||||
glBufferSubData(NzOpenGL::BufferTarget[m_type], offset, size, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
nzUInt8* ptr = mapBuffer(m_type, (size == m_parent->GetSize()) ? nzBufferAccess_DiscardAndWrite : nzBufferAccess_WriteOnly, offset, size);
|
||||
if (!ptr)
|
||||
{
|
||||
NazaraError("Failed to map buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::memcpy(ptr, data, size);
|
||||
|
||||
if (glUnmapBuffer(NzOpenGL::BufferTarget[m_type]) != GL_TRUE)
|
||||
{
|
||||
// Une erreur rare est survenue, nous devons réinitialiser le buffer
|
||||
NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')');
|
||||
|
||||
glBufferData(NzOpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, NzOpenGL::BufferUsage[m_parent->GetStorage()]);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérations chaînées)
|
||||
if (previous != m_buffer && previous != 0)
|
||||
glBindBuffer(NzOpenGL::BufferTarget[m_type], previous);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void* NzHardwareBuffer::GetPointer()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool NzHardwareBuffer::IsHardware() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void* NzHardwareBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned int size)
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
// Pour ne pas perturber le rendu, on interfère pas avec le binding déjà présent
|
||||
GLuint previous;
|
||||
glGetIntegerv(NzOpenGL::BufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous));
|
||||
|
||||
if (previous != m_buffer)
|
||||
glBindBuffer(NzOpenGL::BufferTarget[m_type], m_buffer);
|
||||
|
||||
void* ptr = mapBuffer(m_type, access, offset, size);
|
||||
|
||||
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérrations chaînées)
|
||||
if (previous != m_buffer && previous != 0)
|
||||
glBindBuffer(NzOpenGL::BufferTarget[m_type], previous);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool NzHardwareBuffer::Unmap()
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
GLuint previous;
|
||||
glGetIntegerv(NzOpenGL::BufferTargetBinding[m_type], reinterpret_cast<GLint*>(&previous));
|
||||
|
||||
if (previous != m_buffer)
|
||||
glBindBuffer(NzOpenGL::BufferTarget[m_type], m_buffer);
|
||||
|
||||
if (glUnmapBuffer(NzOpenGL::BufferTarget[m_type]) != GL_TRUE)
|
||||
{
|
||||
// Une erreur rare est survenue, nous devons réinitialiser le buffer
|
||||
NazaraError("Failed to unmap buffer, reinitialising content... (OpenGL error : 0x" + NzString::Number(glGetError(), 16) + ')');
|
||||
|
||||
glBufferData(NzOpenGL::BufferTarget[m_type], m_parent->GetSize(), nullptr, NzOpenGL::BufferUsage[m_parent->GetStorage()]);
|
||||
|
||||
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérations chaînées)
|
||||
if (previous != m_buffer && previous != 0)
|
||||
glBindBuffer(NzOpenGL::BufferTarget[m_type], previous);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Inutile de rebinder s'il n'y avait aucun buffer (Optimise les opérations chaînées)
|
||||
if (previous != m_buffer && previous != 0)
|
||||
glBindBuffer(NzOpenGL::BufferTarget[m_type], previous);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,102 +1,98 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/OcclusionQuery.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
NzOcclusionQuery::NzOcclusionQuery() :
|
||||
m_id(0)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (IsSupported())
|
||||
{
|
||||
#endif
|
||||
NzContext::EnsureContext();
|
||||
|
||||
glGenQueries(1, reinterpret_cast<GLuint*>(&m_id));
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraError("Occlusion queries not supported");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_id)
|
||||
{
|
||||
NazaraError("Failed to create occlusion query");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NzOcclusionQuery::~NzOcclusionQuery()
|
||||
{
|
||||
if (m_id)
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
GLuint query = static_cast<GLuint>(m_id);
|
||||
glDeleteQueries(1, &query);
|
||||
}
|
||||
}
|
||||
|
||||
void NzOcclusionQuery::Begin()
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (NzContext::GetCurrent() == nullptr)
|
||||
{
|
||||
NazaraError("No active context");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
glBeginQuery(GL_SAMPLES_PASSED, m_id);
|
||||
}
|
||||
|
||||
void NzOcclusionQuery::End()
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (NzContext::GetCurrent() == nullptr)
|
||||
{
|
||||
NazaraError("No active context");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
glEndQuery(GL_SAMPLES_PASSED);
|
||||
}
|
||||
|
||||
unsigned int NzOcclusionQuery::GetResult() const
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
GLuint result;
|
||||
glGetQueryObjectuiv(m_id, GL_QUERY_RESULT, &result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NzOcclusionQuery::IsResultAvailable() const
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
GLint available;
|
||||
glGetQueryObjectiv(m_id, GL_QUERY_RESULT_AVAILABLE, &available);
|
||||
|
||||
return available == GL_TRUE;
|
||||
}
|
||||
|
||||
bool NzOcclusionQuery::IsSupported()
|
||||
{
|
||||
return NzRenderer::HasCapability(nzRendererCap_OcclusionQuery);
|
||||
}
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/OcclusionQuery.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Config.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
NzOcclusionQuery::NzOcclusionQuery() :
|
||||
m_id(0)
|
||||
{
|
||||
if (IsSupported())
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
glGenQueries(1, reinterpret_cast<GLuint*>(&m_id));
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraError("Occlusion queries not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_id)
|
||||
{
|
||||
NazaraError("Failed to create occlusion query");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NzOcclusionQuery::~NzOcclusionQuery()
|
||||
{
|
||||
if (m_id)
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
GLuint query = static_cast<GLuint>(m_id);
|
||||
glDeleteQueries(1, &query);
|
||||
}
|
||||
}
|
||||
|
||||
void NzOcclusionQuery::Begin()
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (NzContext::GetCurrent() == nullptr)
|
||||
{
|
||||
NazaraError("No active context");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
glBeginQuery(GL_SAMPLES_PASSED, m_id);
|
||||
}
|
||||
|
||||
void NzOcclusionQuery::End()
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (NzContext::GetCurrent() == nullptr)
|
||||
{
|
||||
NazaraError("No active context");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
glEndQuery(GL_SAMPLES_PASSED);
|
||||
}
|
||||
|
||||
unsigned int NzOcclusionQuery::GetResult() const
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
GLuint result;
|
||||
glGetQueryObjectuiv(m_id, GL_QUERY_RESULT, &result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NzOcclusionQuery::IsResultAvailable() const
|
||||
{
|
||||
NzContext::EnsureContext();
|
||||
|
||||
GLint available;
|
||||
glGetQueryObjectiv(m_id, GL_QUERY_RESULT_AVAILABLE, &available);
|
||||
|
||||
return available == GL_TRUE;
|
||||
}
|
||||
|
||||
bool NzOcclusionQuery::IsSupported()
|
||||
{
|
||||
return NzRenderer::HasCapability(nzRendererCap_OcclusionQuery);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
728
src/Nazara/Renderer/RenderTexture.cpp
Normal file
728
src/Nazara/Renderer/RenderTexture.cpp
Normal file
@@ -0,0 +1,728 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/RenderTexture.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/Renderer.hpp>
|
||||
#include <vector>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
struct Attachment
|
||||
{
|
||||
union
|
||||
{
|
||||
GLuint buffer;
|
||||
NzTexture* texture;
|
||||
};
|
||||
|
||||
bool isBuffer;
|
||||
bool isUsed = false;
|
||||
};
|
||||
|
||||
unsigned int attachmentIndex[nzAttachmentPoint_Max+1] =
|
||||
{
|
||||
2, // nzAttachmentPoint_Color
|
||||
0, // nzAttachmentPoint_Depth
|
||||
0, // nzAttachmentPoint_DepthStencil
|
||||
1 // nzAttachmentPoint_Stencil
|
||||
};
|
||||
|
||||
nzAttachmentPoint formatTypeToAttachment[nzPixelFormatType_Max+1] =
|
||||
{
|
||||
nzAttachmentPoint_Color, // nzPixelFormatType_Color
|
||||
nzAttachmentPoint_Depth, // nzPixelFormatType_Depth
|
||||
nzAttachmentPoint_DepthStencil, // nzPixelFormatType_DepthStencil
|
||||
nzAttachmentPoint_Stencil // nzPixelFormatType_Stencil
|
||||
};
|
||||
|
||||
GLuint lockedPrevious = 0;
|
||||
nzUInt8 lockedLevel = 0;
|
||||
}
|
||||
|
||||
struct NzRenderTextureImpl
|
||||
{
|
||||
GLuint fbo;
|
||||
std::vector<Attachment> attachements;
|
||||
std::vector<GLenum> drawBuffers;
|
||||
NzContext* context;
|
||||
bool checked = false;
|
||||
bool complete = false;
|
||||
bool drawBuffersUpdated = true;
|
||||
unsigned int height;
|
||||
unsigned int width;
|
||||
};
|
||||
|
||||
NzRenderTexture::~NzRenderTexture()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzRenderTexture::AttachBuffer(nzAttachmentPoint attachmentPoint, nzUInt8 index, nzPixelFormat format)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attachmentPoint != nzAttachmentPoint_Color && index > 0)
|
||||
{
|
||||
NazaraError("Index must be 0 for non-color attachments");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int depthStencilIndex = attachmentIndex[nzAttachmentPoint_DepthStencil];
|
||||
if (attachmentPoint == nzAttachmentPoint_Stencil && m_impl->attachements.size() > depthStencilIndex &&
|
||||
m_impl->attachements[depthStencilIndex].isUsed)
|
||||
{
|
||||
NazaraError("Stencil target already attached by DepthStencil attachment");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (formatTypeToAttachment[NzPixelFormat::GetType(format)] != attachmentPoint)
|
||||
{
|
||||
NazaraError("Pixel format type does not match attachment point type");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
NzOpenGL::Format openglFormat;
|
||||
if (!NzOpenGL::TranslateFormat(format, &openglFormat, NzOpenGL::FormatType_RenderBuffer))
|
||||
{
|
||||
NazaraError("Failed to translate pixel format into OpenGL format");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Détachement de l'attache précédente (Si il y a)
|
||||
Detach(attachmentPoint, index);
|
||||
|
||||
GLuint renderBuffer = 0;
|
||||
|
||||
glGenRenderbuffers(1, &renderBuffer);
|
||||
if (!renderBuffer)
|
||||
{
|
||||
NazaraError("Failed to create renderbuffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLint previous;
|
||||
glGetIntegerv(GL_RENDERBUFFER_BINDING, &previous);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, openglFormat.internalFormat, m_impl->width, m_impl->height);
|
||||
|
||||
if (previous != 0)
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, previous);
|
||||
|
||||
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, GL_RENDERBUFFER, renderBuffer);
|
||||
Unlock();
|
||||
|
||||
unsigned int minSize = attachmentIndex[attachmentPoint]+index+1;
|
||||
if (m_impl->attachements.size() < minSize)
|
||||
m_impl->attachements.resize(minSize);
|
||||
|
||||
Attachment& attachment = m_impl->attachements[minSize-1];
|
||||
attachment.isBuffer = true;
|
||||
attachment.isUsed = true;
|
||||
attachment.buffer = renderBuffer;
|
||||
|
||||
m_impl->checked = false;
|
||||
m_impl->drawBuffersUpdated = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzRenderTexture::AttachTexture(nzAttachmentPoint attachmentPoint, nzUInt8 index, NzTexture* texture)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attachmentPoint != nzAttachmentPoint_Color && index > 0)
|
||||
{
|
||||
NazaraError("Index must be 0 for non-color attachments");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int depthStencilIndex = attachmentIndex[nzAttachmentPoint_DepthStencil];
|
||||
if (attachmentPoint == nzAttachmentPoint_Stencil && m_impl->attachements.size() > depthStencilIndex &&
|
||||
m_impl->attachements[depthStencilIndex].isUsed)
|
||||
{
|
||||
NazaraError("Stencil target already attached by DepthStencil attachment");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!texture || !texture->IsValid())
|
||||
{
|
||||
NazaraError("Invalid texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (texture->GetWidth() < m_impl->width || texture->GetHeight() < m_impl->height)
|
||||
{
|
||||
NazaraError("Texture cannot be smaller than render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (texture->GetRenderTexture() != nullptr)
|
||||
{
|
||||
NazaraError("Texture already used by another render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (formatTypeToAttachment[NzPixelFormat::GetType(texture->GetFormat())] != attachmentPoint)
|
||||
{
|
||||
NazaraError("Pixel format type does not match attachment point type");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Détachement de l'attache précédente (Si il y a)
|
||||
Detach(attachmentPoint, index);
|
||||
|
||||
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, texture->GetOpenGLID(), 0);
|
||||
Unlock();
|
||||
|
||||
unsigned int minSize = attachmentIndex[attachmentPoint]+index+1;
|
||||
if (m_impl->attachements.size() < minSize)
|
||||
m_impl->attachements.resize(minSize);
|
||||
|
||||
Attachment& attachment = m_impl->attachements[minSize-1];
|
||||
attachment.isBuffer = true;
|
||||
attachment.isUsed = true;
|
||||
attachment.texture = texture;
|
||||
|
||||
texture->AddResourceListener(this, minSize-1);
|
||||
texture->SetRenderTexture(this);
|
||||
|
||||
m_impl->checked = false;
|
||||
m_impl->drawBuffersUpdated = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzRenderTexture::AttachTexture(nzAttachmentPoint attachmentPoint, nzUInt8 index, NzTexture* texture, unsigned int z)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attachmentPoint != nzAttachmentPoint_Color && index > 0)
|
||||
{
|
||||
NazaraError("Index must be 0 for non-color attachments");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (attachmentPoint == nzAttachmentPoint_Stencil)
|
||||
{
|
||||
NazaraError("Targeting stencil-only textures is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int depthStencilIndex = attachmentIndex[nzAttachmentPoint_DepthStencil];
|
||||
if (attachmentPoint == nzAttachmentPoint_Stencil && m_impl->attachements.size() > depthStencilIndex &&
|
||||
m_impl->attachements[depthStencilIndex].isUsed)
|
||||
{
|
||||
NazaraError("Stencil target already attached by DepthStencil attachment");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!texture || !texture->IsValid())
|
||||
{
|
||||
NazaraError("Invalid texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (texture->GetWidth() < m_impl->width || texture->GetHeight() < m_impl->height)
|
||||
{
|
||||
NazaraError("Texture cannot be smaller than render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int depth = (texture->GetType() == nzImageType_Cubemap) ? 6 : texture->GetDepth();
|
||||
if (z >= depth)
|
||||
{
|
||||
NazaraError("Z value exceeds depth (" + NzString::Number(z) + " >= (" + NzString::Number(depth) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (texture->GetRenderTexture() != nullptr)
|
||||
{
|
||||
NazaraError("Texture already used by another render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (formatTypeToAttachment[NzPixelFormat::GetType(texture->GetFormat())] != attachmentPoint)
|
||||
{
|
||||
NazaraError("Pixel format type does not match attachment point type");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Détachement de l'attache précédente (Si il y a)
|
||||
Detach(attachmentPoint, index);
|
||||
|
||||
switch (texture->GetType())
|
||||
{
|
||||
case nzImageType_1D:
|
||||
glFramebufferTexture1D(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, GL_TEXTURE_1D, texture->GetOpenGLID(), 0);
|
||||
break;
|
||||
|
||||
case nzImageType_1D_Array:
|
||||
case nzImageType_2D_Array:
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, texture->GetOpenGLID(), 0, z);
|
||||
break;
|
||||
|
||||
case nzImageType_2D:
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, NzOpenGL::TextureTarget[texture->GetType()], texture->GetOpenGLID(), 0);
|
||||
break;
|
||||
|
||||
case nzImageType_3D:
|
||||
glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, GL_TEXTURE_3D, texture->GetOpenGLID(), 0, z);
|
||||
break;
|
||||
|
||||
case nzImageType_Cubemap:
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, NzOpenGL::CubemapFace[z], texture->GetOpenGLID(), 0);
|
||||
break;
|
||||
}
|
||||
Unlock();
|
||||
|
||||
unsigned int minSize = attachmentIndex[attachmentPoint]+index+1;
|
||||
if (m_impl->attachements.size() < minSize)
|
||||
m_impl->attachements.resize(minSize);
|
||||
|
||||
Attachment& attachment = m_impl->attachements[minSize-1];
|
||||
attachment.isBuffer = true;
|
||||
attachment.isUsed = true;
|
||||
attachment.texture = texture;
|
||||
|
||||
texture->AddResourceListener(this);
|
||||
texture->SetRenderTexture(this);
|
||||
|
||||
m_impl->checked = false;
|
||||
m_impl->drawBuffersUpdated = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzRenderTexture::Create(unsigned int width, unsigned int height, bool lock)
|
||||
{
|
||||
if (!IsSupported())
|
||||
{
|
||||
NazaraError("Render textures not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (width == 0)
|
||||
{
|
||||
NazaraError("Width must be at least 1 (0)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (height == 0)
|
||||
{
|
||||
NazaraError("Height must be at least 1 (0)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NzContext::GetCurrent() == nullptr)
|
||||
{
|
||||
NazaraError("No active context");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
NzRenderTextureImpl* impl = new NzRenderTextureImpl;
|
||||
impl->width = width;
|
||||
impl->height = height;
|
||||
|
||||
impl->context = NzContext::GetCurrent();
|
||||
impl->context->AddResourceListener(this);
|
||||
|
||||
impl->fbo = 0;
|
||||
glGenFramebuffers(1, &impl->fbo);
|
||||
|
||||
if (!impl->fbo)
|
||||
{
|
||||
NazaraError("Failed to create framebuffer");
|
||||
delete impl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = impl;
|
||||
|
||||
if (lock && !Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
delete impl;
|
||||
m_impl = nullptr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzRenderTexture::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (NzContext::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture can only be used with it's creation context");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->context->RemoveResourceListener(this);
|
||||
|
||||
for (Attachment& attachment : m_impl->attachements)
|
||||
{
|
||||
if (attachment.isUsed)
|
||||
{
|
||||
if (attachment.isBuffer)
|
||||
glDeleteRenderbuffers(1, &attachment.buffer);
|
||||
else
|
||||
{
|
||||
attachment.texture->RemoveResourceListener(this);
|
||||
attachment.texture->SetRenderTexture(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glDeleteFramebuffers(1, &m_impl->fbo);
|
||||
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void NzRenderTexture::Detach(nzAttachmentPoint attachmentPoint, nzUInt8 index)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return;
|
||||
}
|
||||
|
||||
if (attachmentPoint != nzAttachmentPoint_Color && index > 0)
|
||||
{
|
||||
NazaraError("Index must be 0 for non-color attachments");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int attachIndex = attachmentIndex[attachmentPoint]+index;
|
||||
if (attachIndex >= m_impl->attachements.size())
|
||||
return;
|
||||
|
||||
Attachment& attachement = m_impl->attachements[attachIndex];
|
||||
if (!attachement.isUsed)
|
||||
return;
|
||||
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return;
|
||||
}
|
||||
|
||||
attachement.isUsed = false;
|
||||
|
||||
if (attachement.isBuffer)
|
||||
{
|
||||
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, GL_RENDERBUFFER, 0);
|
||||
glDeleteRenderbuffers(1, &attachement.buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, NzOpenGL::Attachment[attachmentPoint]+index, 0, 0);
|
||||
attachement.texture->RemoveResourceListener(this);
|
||||
attachement.texture->SetRenderTexture(nullptr);
|
||||
}
|
||||
|
||||
Unlock();
|
||||
|
||||
m_impl->checked = false;
|
||||
m_impl->drawBuffersUpdated = false;
|
||||
|
||||
}
|
||||
|
||||
unsigned int NzRenderTexture::GetHeight() const
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->height;
|
||||
}
|
||||
|
||||
NzRenderTargetParameters NzRenderTexture::GetParameters() const
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return NzRenderTargetParameters();
|
||||
}
|
||||
#endif
|
||||
|
||||
return NzRenderTargetParameters();
|
||||
}
|
||||
|
||||
unsigned int NzRenderTexture::GetWidth() const
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->width;
|
||||
}
|
||||
|
||||
bool NzRenderTexture::IsComplete() const
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_impl->checked)
|
||||
{
|
||||
if (!Lock())
|
||||
{
|
||||
NazaraError("Failed to lock render texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
|
||||
Unlock();
|
||||
|
||||
m_impl->complete = false;
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_COMPLETE:
|
||||
m_impl->complete = true;
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
NazaraError("Incomplete attachment");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
NazaraInternalError("Incomplete draw buffer");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
NazaraInternalError("Incomplete read buffer");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
NazaraError("Incomplete missing attachment");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
|
||||
NazaraError("Incomplete multisample");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
|
||||
NazaraError("Incomplete layer targets");
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
NazaraError("Render texture has unsupported attachments");
|
||||
break;
|
||||
|
||||
default:
|
||||
NazaraInternalError("Unknown error");
|
||||
}
|
||||
|
||||
m_impl->checked = true;
|
||||
}
|
||||
|
||||
return m_impl->complete;
|
||||
}
|
||||
|
||||
bool NzRenderTexture::IsRenderable() const
|
||||
{
|
||||
return IsComplete();
|
||||
}
|
||||
|
||||
bool NzRenderTexture::IsValid() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
bool NzRenderTexture::Lock() const
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NzContext::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lockedLevel++ == 0)
|
||||
{
|
||||
GLint previous;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previous);
|
||||
|
||||
lockedPrevious = previous;
|
||||
|
||||
if (lockedPrevious != m_impl->fbo)
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_impl->fbo);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzRenderTexture::Unlock() const
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Render texture not created");
|
||||
return;
|
||||
}
|
||||
|
||||
if (NzContext::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return;
|
||||
}
|
||||
|
||||
if (lockedLevel == 0)
|
||||
{
|
||||
NazaraWarning("Unlock called on non-locked texture");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (--lockedLevel == 0 && lockedPrevious != m_impl->fbo) // Ici, il est important qu'un FBO soit débindé si l'ancien était 0
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, lockedPrevious);
|
||||
}
|
||||
|
||||
bool NzRenderTexture::HasContext() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NzRenderTexture::IsSupported()
|
||||
{
|
||||
return NzRenderer::HasCapability(nzRendererCap_RenderTexture);
|
||||
}
|
||||
|
||||
bool NzRenderTexture::Activate()
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (NzContext::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_impl->drawBuffersUpdated)
|
||||
{
|
||||
m_impl->drawBuffers.clear();
|
||||
m_impl->drawBuffers.reserve(m_impl->attachements.size());
|
||||
for (unsigned int i = attachmentIndex[nzAttachmentPoint_Color]; i < m_impl->attachements.size(); ++i)
|
||||
{
|
||||
if (m_impl->attachements[i].isUsed)
|
||||
m_impl->drawBuffers.push_back(GL_COLOR_ATTACHMENT0 + i - attachmentIndex[nzAttachmentPoint_Color]);
|
||||
}
|
||||
|
||||
m_impl->drawBuffersUpdated = true;
|
||||
}
|
||||
|
||||
glDrawBuffers(m_impl->drawBuffers.size(), &m_impl->drawBuffers[0]);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_impl->fbo);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzRenderTexture::Desactivate()
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (NzContext::GetCurrent() != m_impl->context)
|
||||
{
|
||||
NazaraError("RenderTexture cannot be used with this context");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
glFlush();
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void NzRenderTexture::OnResourceDestroy(const NzResource* resource, int index)
|
||||
{
|
||||
if (resource == m_impl->context)
|
||||
// Notre context a été détruit, libérons la RenderTexture pour éviter un leak
|
||||
Destroy();
|
||||
else
|
||||
{
|
||||
// Sinon, c'est une texture
|
||||
|
||||
// La ressource n'est plus, du coup nous mettons à jour
|
||||
Attachment& attachement = m_impl->attachements[index];
|
||||
attachement.isUsed = false;
|
||||
|
||||
m_impl->checked = false;
|
||||
m_impl->drawBuffersUpdated = false;
|
||||
}
|
||||
}
|
||||
@@ -1,278 +1,276 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/RenderWindow.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Thread.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/Texture.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
NzRenderWindow::NzRenderWindow(NzVideoMode mode, const NzString& title, nzUInt32 style, const NzContextParameters& parameters)
|
||||
{
|
||||
Create(mode, title, style, parameters);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Failed to create render window");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NzRenderWindow::NzRenderWindow(NzWindowHandle handle, const NzContextParameters& parameters)
|
||||
{
|
||||
Create(handle, parameters);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Failed to create render window");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NzRenderWindow::~NzRenderWindow()
|
||||
{
|
||||
// Nécessaire si NzWindow::Destroy est appelé par son destructeur
|
||||
OnWindowDestroying();
|
||||
}
|
||||
|
||||
bool NzRenderWindow::CopyToImage(NzImage* image)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_context)
|
||||
{
|
||||
NazaraError("Window has not been created");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!image)
|
||||
{
|
||||
NazaraError("Image must be valid");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_context->SetActive(true))
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
return false;
|
||||
}
|
||||
|
||||
NzVector2ui size = GetSize();
|
||||
|
||||
if (!image->Create(nzImageType_2D, nzPixelFormat_RGBA8, size.x, size.y, 1, 1))
|
||||
{
|
||||
NazaraError("Failed to create image");
|
||||
return false;
|
||||
}
|
||||
|
||||
nzUInt8* pixels = image->GetPixels();
|
||||
glReadPixels(0, 0, size.x, size.y, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
image->FlipVertically();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzRenderWindow::CopyToTexture(NzTexture* texture)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_context)
|
||||
{
|
||||
NazaraError("Window has not been created");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!texture)
|
||||
{
|
||||
NazaraError("Texture must be valid");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_context->SetActive(true))
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
return false;
|
||||
}
|
||||
|
||||
NzVector2ui size = GetSize();
|
||||
|
||||
if (!texture->Create(nzImageType_2D, nzPixelFormat_RGBA8, size.x, size.y, 1, 1, true))
|
||||
{
|
||||
NazaraError("Failed to create texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, size.x, size.y);
|
||||
|
||||
texture->Unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzRenderWindow::Create(NzVideoMode mode, const NzString& title, nzUInt32 style, const NzContextParameters& parameters)
|
||||
{
|
||||
m_parameters = parameters;
|
||||
return NzWindow::Create(mode, title, style);
|
||||
}
|
||||
|
||||
bool NzRenderWindow::Create(NzWindowHandle handle, const NzContextParameters& parameters)
|
||||
{
|
||||
m_parameters = parameters;
|
||||
return NzWindow::Create(handle);
|
||||
}
|
||||
|
||||
void NzRenderWindow::Display()
|
||||
{
|
||||
if (m_framerateLimit > 0)
|
||||
{
|
||||
int remainingTime = 1000/m_framerateLimit - m_clock.GetMilliseconds();
|
||||
if (remainingTime > 0)
|
||||
NzThread::Sleep(remainingTime);
|
||||
|
||||
m_clock.Restart();
|
||||
}
|
||||
|
||||
if (m_context && m_parameters.doubleBuffered)
|
||||
m_context->SwapBuffers();
|
||||
}
|
||||
|
||||
void NzRenderWindow::EnableVerticalSync(bool enabled)
|
||||
{
|
||||
if (m_context)
|
||||
{
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
if (!m_context->SetActive(true))
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
return;
|
||||
}
|
||||
|
||||
if (wglSwapInterval)
|
||||
wglSwapInterval(enabled ? 1 : 0);
|
||||
else
|
||||
#elif defined(NAZARA_PLATFORM_LINUX)
|
||||
if (!m_context->SetActive(true))
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
return;
|
||||
}
|
||||
|
||||
if (glXSwapInterval)
|
||||
glXSwapInterval(enabled ? 1 : 0);
|
||||
else
|
||||
#else
|
||||
#error Vertical Sync is not supported on this platform
|
||||
#endif
|
||||
NazaraError("Vertical Sync is not supported on this platform");
|
||||
}
|
||||
else
|
||||
NazaraError("No context");
|
||||
}
|
||||
|
||||
NzContextParameters NzRenderWindow::GetContextParameters() const
|
||||
{
|
||||
if (m_context)
|
||||
return m_context->GetParameters();
|
||||
else
|
||||
{
|
||||
NazaraError("Window not created/context not initialized");
|
||||
return NzContextParameters();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int NzRenderWindow::GetHeight() const
|
||||
{
|
||||
return NzWindow::GetHeight();
|
||||
}
|
||||
|
||||
NzRenderTargetParameters NzRenderWindow::GetParameters() const
|
||||
{
|
||||
if (m_context)
|
||||
{
|
||||
const NzContextParameters& parameters = m_context->GetParameters();
|
||||
return NzRenderTargetParameters(parameters.antialiasingLevel, parameters.depthBits, parameters.stencilBits);
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraError("Window not created/context not initialized");
|
||||
return NzRenderTargetParameters();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int NzRenderWindow::GetWidth() const
|
||||
{
|
||||
return NzWindow::GetWidth();
|
||||
}
|
||||
|
||||
bool NzRenderWindow::HasContext() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzRenderWindow::IsValid() const
|
||||
{
|
||||
return m_impl != nullptr && m_context != nullptr;
|
||||
}
|
||||
|
||||
void NzRenderWindow::SetFramerateLimit(unsigned int limit)
|
||||
{
|
||||
m_framerateLimit = limit;
|
||||
}
|
||||
|
||||
bool NzRenderWindow::Activate()
|
||||
{
|
||||
if (m_context->SetActive(true))
|
||||
{
|
||||
glDrawBuffer((m_parameters.doubleBuffered) ? GL_BACK : GL_FRONT);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraError("Failed to activate window's context");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void NzRenderWindow::OnWindowDestroying()
|
||||
{
|
||||
if (m_context)
|
||||
{
|
||||
delete m_context;
|
||||
m_context = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool NzRenderWindow::OnWindowCreated()
|
||||
{
|
||||
m_parameters.doubleBuffered = true;
|
||||
m_parameters.window = GetHandle();
|
||||
|
||||
m_context = new NzContext;
|
||||
if (!m_context->Create(m_parameters))
|
||||
{
|
||||
NazaraError("Failed not create context");
|
||||
delete m_context;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
EnableVerticalSync(false);
|
||||
|
||||
#if NAZARA_RENDERER_ACTIVATE_RENDERWINDOW_ON_CREATION
|
||||
if (!SetActive(true)) // Les fenêtres s'activent à la création
|
||||
NazaraWarning("Failed to activate window");
|
||||
#endif
|
||||
|
||||
m_clock.Restart();
|
||||
|
||||
return true;
|
||||
}
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/RenderWindow.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/Thread.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <Nazara/Renderer/Texture.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
NzRenderWindow::NzRenderWindow(NzVideoMode mode, const NzString& title, nzUInt32 style, const NzContextParameters& parameters)
|
||||
{
|
||||
Create(mode, title, style, parameters);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Failed to create render window");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NzRenderWindow::NzRenderWindow(NzWindowHandle handle, const NzContextParameters& parameters)
|
||||
{
|
||||
Create(handle, parameters);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Failed to create render window");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NzRenderWindow::~NzRenderWindow()
|
||||
{
|
||||
// Nécessaire si NzWindow::Destroy est appelé par son destructeur
|
||||
OnWindowDestroy();
|
||||
}
|
||||
|
||||
bool NzRenderWindow::CopyToImage(NzImage* image)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_context)
|
||||
{
|
||||
NazaraError("Window has not been created");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!image)
|
||||
{
|
||||
NazaraError("Image must be valid");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_context->SetActive(true))
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
return false;
|
||||
}
|
||||
|
||||
NzVector2ui size = GetSize();
|
||||
|
||||
if (!image->Create(nzImageType_2D, nzPixelFormat_RGBA8, size.x, size.y, 1, 1))
|
||||
{
|
||||
NazaraError("Failed to create image");
|
||||
return false;
|
||||
}
|
||||
|
||||
nzUInt8* pixels = image->GetPixels();
|
||||
glReadPixels(0, 0, size.x, size.y, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
image->FlipVertically();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzRenderWindow::CopyToTexture(NzTexture* texture)
|
||||
{
|
||||
#if NAZARA_RENDERER_SAFE
|
||||
if (!m_context)
|
||||
{
|
||||
NazaraError("Window has not been created");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!texture)
|
||||
{
|
||||
NazaraError("Texture must be valid");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_context->SetActive(true))
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
return false;
|
||||
}
|
||||
|
||||
NzVector2ui size = GetSize();
|
||||
|
||||
if (!texture->Create(nzImageType_2D, nzPixelFormat_RGBA8, size.x, size.y, 1, 1, true))
|
||||
{
|
||||
NazaraError("Failed to create texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, size.x, size.y);
|
||||
|
||||
texture->Unlock();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzRenderWindow::Create(NzVideoMode mode, const NzString& title, nzUInt32 style, const NzContextParameters& parameters)
|
||||
{
|
||||
m_parameters = parameters;
|
||||
return NzWindow::Create(mode, title, style);
|
||||
}
|
||||
|
||||
bool NzRenderWindow::Create(NzWindowHandle handle, const NzContextParameters& parameters)
|
||||
{
|
||||
m_parameters = parameters;
|
||||
return NzWindow::Create(handle);
|
||||
}
|
||||
|
||||
void NzRenderWindow::Display()
|
||||
{
|
||||
if (m_framerateLimit > 0)
|
||||
{
|
||||
int remainingTime = 1000/m_framerateLimit - m_clock.GetMilliseconds();
|
||||
if (remainingTime > 0)
|
||||
NzThread::Sleep(remainingTime);
|
||||
|
||||
m_clock.Restart();
|
||||
}
|
||||
|
||||
if (m_context && m_parameters.doubleBuffered)
|
||||
m_context->SwapBuffers();
|
||||
}
|
||||
|
||||
void NzRenderWindow::EnableVerticalSync(bool enabled)
|
||||
{
|
||||
if (m_context)
|
||||
{
|
||||
#if defined(NAZARA_PLATFORM_WINDOWS)
|
||||
if (!m_context->SetActive(true))
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
return;
|
||||
}
|
||||
|
||||
if (wglSwapInterval)
|
||||
wglSwapInterval(enabled ? 1 : 0);
|
||||
else
|
||||
#elif defined(NAZARA_PLATFORM_LINUX)
|
||||
if (!m_context->SetActive(true))
|
||||
{
|
||||
NazaraError("Failed to activate context");
|
||||
return;
|
||||
}
|
||||
|
||||
if (glXSwapInterval)
|
||||
glXSwapInterval(enabled ? 1 : 0);
|
||||
else
|
||||
#else
|
||||
#error Vertical Sync is not supported on this platform
|
||||
#endif
|
||||
NazaraError("Vertical Sync is not supported on this platform");
|
||||
}
|
||||
else
|
||||
NazaraError("No context");
|
||||
}
|
||||
|
||||
unsigned int NzRenderWindow::GetHeight() const
|
||||
{
|
||||
return NzWindow::GetHeight();
|
||||
}
|
||||
|
||||
NzRenderTargetParameters NzRenderWindow::GetParameters() const
|
||||
{
|
||||
if (m_context)
|
||||
{
|
||||
const NzContextParameters& parameters = m_context->GetParameters();
|
||||
return NzRenderTargetParameters(parameters.antialiasingLevel, parameters.depthBits, parameters.stencilBits);
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraError("Window not created/context not initialized");
|
||||
return NzRenderTargetParameters();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int NzRenderWindow::GetWidth() const
|
||||
{
|
||||
return NzWindow::GetWidth();
|
||||
}
|
||||
|
||||
bool NzRenderWindow::IsRenderable() const
|
||||
{
|
||||
return m_impl != nullptr; // Si m_impl est valide, alors m_context l'est aussi
|
||||
}
|
||||
|
||||
void NzRenderWindow::SetFramerateLimit(unsigned int limit)
|
||||
{
|
||||
m_framerateLimit = limit;
|
||||
}
|
||||
|
||||
NzContextParameters NzRenderWindow::GetContextParameters() const
|
||||
{
|
||||
if (m_context)
|
||||
return m_context->GetParameters();
|
||||
else
|
||||
{
|
||||
NazaraError("Window not created/context not initialized");
|
||||
return NzContextParameters();
|
||||
}
|
||||
}
|
||||
|
||||
bool NzRenderWindow::HasContext() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzRenderWindow::Activate()
|
||||
{
|
||||
if (m_context->SetActive(true))
|
||||
{
|
||||
glDrawBuffer((m_parameters.doubleBuffered) ? GL_BACK : GL_FRONT);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraError("Failed to activate window's context");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool NzRenderWindow::OnWindowCreated()
|
||||
{
|
||||
m_parameters.doubleBuffered = true;
|
||||
m_parameters.window = GetHandle();
|
||||
|
||||
m_context = new NzContext;
|
||||
if (!m_context->Create(m_parameters))
|
||||
{
|
||||
NazaraError("Failed not create context");
|
||||
delete m_context;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
EnableVerticalSync(false);
|
||||
|
||||
if (!SetActive(true)) // Les fenêtres s'activent à la création
|
||||
NazaraWarning("Failed to activate window");
|
||||
|
||||
m_clock.Restart();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzRenderWindow::OnWindowDestroy()
|
||||
{
|
||||
if (m_context)
|
||||
{
|
||||
delete m_context;
|
||||
m_context = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,231 +1,234 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
// Code inspiré de NeHe (Lesson1) et de la SFML par Laurent Gomila
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Win32/ContextImpl.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/LockGuard.hpp>
|
||||
#include <Nazara/Core/Mutex.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <cstring>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
NzContextImpl::NzContextImpl()
|
||||
{
|
||||
}
|
||||
|
||||
bool NzContextImpl::Activate()
|
||||
{
|
||||
return wglMakeCurrent(m_deviceContext, m_context);
|
||||
}
|
||||
|
||||
bool NzContextImpl::Create(NzContextParameters& parameters)
|
||||
{
|
||||
if (parameters.window)
|
||||
{
|
||||
m_window = static_cast<HWND>(parameters.window);
|
||||
m_ownsWindow = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_window = CreateWindowA("STATIC", nullptr, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
|
||||
if (!m_window)
|
||||
{
|
||||
NazaraError("Failed to create window");
|
||||
return false;
|
||||
}
|
||||
|
||||
ShowWindow(m_window, SW_HIDE);
|
||||
m_ownsWindow = true;
|
||||
}
|
||||
|
||||
m_deviceContext = GetDC(m_window);
|
||||
if (!m_deviceContext)
|
||||
{
|
||||
NazaraError("Failed to get device context");
|
||||
Destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
int pixelFormat = 0;
|
||||
if (parameters.antialiasingLevel > 0)
|
||||
{
|
||||
if (wglChoosePixelFormat)
|
||||
{
|
||||
bool valid;
|
||||
UINT numFormats;
|
||||
|
||||
int attributes[] = {
|
||||
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
|
||||
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
|
||||
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
|
||||
WGL_COLOR_BITS_ARB, (parameters.bitsPerPixel == 32) ? 24 : parameters.bitsPerPixel,
|
||||
WGL_ALPHA_BITS_ARB, (parameters.bitsPerPixel == 32) ? 8 : 0,
|
||||
WGL_DEPTH_BITS_ARB, parameters.depthBits,
|
||||
WGL_STENCIL_BITS_ARB, parameters.stencilBits,
|
||||
WGL_DOUBLE_BUFFER_ARB, (parameters.doubleBuffered) ? GL_TRUE : GL_FALSE,
|
||||
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
|
||||
WGL_SAMPLES_ARB, parameters.antialiasingLevel,
|
||||
0, 0
|
||||
};
|
||||
|
||||
do
|
||||
{
|
||||
valid = wglChoosePixelFormat(m_deviceContext, attributes, nullptr, 1, &pixelFormat, &numFormats);
|
||||
}
|
||||
while ((!valid || numFormats == 0) && --attributes[19] > 0);
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
NazaraWarning("Could not find a format matching requirements, disabling antialiasing...");
|
||||
pixelFormat = 0;
|
||||
}
|
||||
|
||||
parameters.antialiasingLevel = attributes[19];
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraWarning("Antialiasing is not supported");
|
||||
parameters.antialiasingLevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PIXELFORMATDESCRIPTOR descriptor;
|
||||
ZeroMemory(&descriptor, sizeof(PIXELFORMATDESCRIPTOR));
|
||||
descriptor.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
descriptor.nVersion = 1;
|
||||
|
||||
if (pixelFormat == 0)
|
||||
{
|
||||
descriptor.cColorBits = parameters.bitsPerPixel;
|
||||
descriptor.cDepthBits = parameters.depthBits;
|
||||
descriptor.cStencilBits = parameters.stencilBits;
|
||||
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
|
||||
descriptor.iPixelType = PFD_TYPE_RGBA;
|
||||
|
||||
if (parameters.bitsPerPixel == 32)
|
||||
descriptor.cAlphaBits = 8;
|
||||
|
||||
if (parameters.doubleBuffered)
|
||||
descriptor.dwFlags |= PFD_DOUBLEBUFFER;
|
||||
|
||||
pixelFormat = ChoosePixelFormat(m_deviceContext, &descriptor);
|
||||
if (pixelFormat == 0)
|
||||
{
|
||||
NazaraError("Failed to choose pixel format");
|
||||
Destroy();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!SetPixelFormat(m_deviceContext, pixelFormat, &descriptor))
|
||||
{
|
||||
NazaraError("Failed to set pixel format");
|
||||
Destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Arrivé ici, le format de pixel est choisi, nous récupérons donc les paramètres réels du futur contexte
|
||||
if (DescribePixelFormat(m_deviceContext, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &descriptor) != 0)
|
||||
{
|
||||
parameters.bitsPerPixel = descriptor.cColorBits + descriptor.cAlphaBits;
|
||||
parameters.depthBits = descriptor.cDepthBits;
|
||||
parameters.stencilBits = descriptor.cDepthBits;
|
||||
}
|
||||
else
|
||||
NazaraWarning("Failed to get context's parameters");
|
||||
|
||||
HGLRC shareContext = (parameters.shared) ? static_cast<NzContextImpl*>(parameters.shareContext->m_impl)->m_context : nullptr;
|
||||
|
||||
m_context = nullptr;
|
||||
if (wglCreateContextAttribs)
|
||||
{
|
||||
int attributes[4*2+1];
|
||||
int* attrib = attributes;
|
||||
|
||||
*attrib++ = WGL_CONTEXT_MAJOR_VERSION_ARB;
|
||||
*attrib++ = parameters.majorVersion;
|
||||
|
||||
*attrib++ = WGL_CONTEXT_MINOR_VERSION_ARB;
|
||||
*attrib++ = parameters.minorVersion;
|
||||
|
||||
int flags = 0;
|
||||
|
||||
if (parameters.majorVersion >= 3)
|
||||
{
|
||||
*attrib++ = WGL_CONTEXT_PROFILE_MASK_ARB;
|
||||
if (parameters.compatibilityProfile)
|
||||
*attrib++ = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
|
||||
else
|
||||
{
|
||||
*attrib++ = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
|
||||
|
||||
flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
||||
}
|
||||
}
|
||||
|
||||
if (parameters.debugMode)
|
||||
flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
|
||||
if (flags)
|
||||
{
|
||||
*attrib++ = WGL_CONTEXT_FLAGS_ARB;
|
||||
*attrib++ = flags;
|
||||
}
|
||||
|
||||
*attrib++ = 0;
|
||||
|
||||
m_context = wglCreateContextAttribs(m_deviceContext, shareContext, attributes);
|
||||
}
|
||||
|
||||
if (!m_context)
|
||||
{
|
||||
m_context = wglCreateContext(m_deviceContext);
|
||||
|
||||
if (shareContext)
|
||||
{
|
||||
// wglShareLists n'est pas thread-safe (source: SFML)
|
||||
static NzMutex mutex;
|
||||
NzLockGuard lock(mutex);
|
||||
|
||||
if (!wglShareLists(shareContext, m_context))
|
||||
NazaraWarning("Failed to share the context: " + NzGetLastSystemError());
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_context)
|
||||
{
|
||||
NazaraError("Failed to create context");
|
||||
Destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzContextImpl::Destroy()
|
||||
{
|
||||
if (m_context)
|
||||
wglDeleteContext(m_context);
|
||||
|
||||
if (m_deviceContext)
|
||||
ReleaseDC(m_window, m_deviceContext);
|
||||
|
||||
if (m_ownsWindow)
|
||||
DestroyWindow(m_window);
|
||||
}
|
||||
|
||||
void NzContextImpl::SwapBuffers()
|
||||
{
|
||||
::SwapBuffers(m_deviceContext);
|
||||
}
|
||||
|
||||
bool NzContextImpl::Desactivate()
|
||||
{
|
||||
return wglMakeCurrent(nullptr, nullptr);
|
||||
}
|
||||
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Renderer module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
// Code inspiré de NeHe (Lesson1) et de la SFML par Laurent Gomila
|
||||
|
||||
#include <Nazara/Renderer/OpenGL.hpp>
|
||||
#include <Nazara/Renderer/Win32/ContextImpl.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/LockGuard.hpp>
|
||||
#include <Nazara/Core/Mutex.hpp>
|
||||
#include <Nazara/Renderer/Context.hpp>
|
||||
#include <cstring>
|
||||
#include <Nazara/Renderer/Debug.hpp>
|
||||
|
||||
NzContextImpl::NzContextImpl()
|
||||
{
|
||||
}
|
||||
|
||||
bool NzContextImpl::Activate()
|
||||
{
|
||||
return wglMakeCurrent(m_deviceContext, m_context);
|
||||
}
|
||||
|
||||
bool NzContextImpl::Create(NzContextParameters& parameters)
|
||||
{
|
||||
if (parameters.window)
|
||||
{
|
||||
m_window = static_cast<HWND>(parameters.window);
|
||||
m_ownsWindow = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_window = CreateWindowA("STATIC", nullptr, WS_DISABLED | WS_POPUP, 0, 0, 1, 1, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
|
||||
if (!m_window)
|
||||
{
|
||||
NazaraError("Failed to create window");
|
||||
return false;
|
||||
}
|
||||
|
||||
ShowWindow(m_window, SW_HIDE);
|
||||
m_ownsWindow = true;
|
||||
}
|
||||
|
||||
m_deviceContext = GetDC(m_window);
|
||||
if (!m_deviceContext)
|
||||
{
|
||||
NazaraError("Failed to get device context");
|
||||
Destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
int pixelFormat = 0;
|
||||
if (parameters.antialiasingLevel > 0)
|
||||
{
|
||||
if (wglChoosePixelFormat)
|
||||
{
|
||||
bool valid;
|
||||
UINT numFormats;
|
||||
|
||||
int attributes[] = {
|
||||
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
|
||||
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
|
||||
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
|
||||
WGL_COLOR_BITS_ARB, (parameters.bitsPerPixel == 32) ? 24 : parameters.bitsPerPixel,
|
||||
WGL_ALPHA_BITS_ARB, (parameters.bitsPerPixel == 32) ? 8 : 0,
|
||||
WGL_DEPTH_BITS_ARB, parameters.depthBits,
|
||||
WGL_STENCIL_BITS_ARB, parameters.stencilBits,
|
||||
WGL_DOUBLE_BUFFER_ARB, (parameters.doubleBuffered) ? GL_TRUE : GL_FALSE,
|
||||
WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
|
||||
WGL_SAMPLES_ARB, parameters.antialiasingLevel,
|
||||
0, 0
|
||||
};
|
||||
|
||||
do
|
||||
{
|
||||
valid = wglChoosePixelFormat(m_deviceContext, attributes, nullptr, 1, &pixelFormat, &numFormats);
|
||||
}
|
||||
while ((!valid || numFormats == 0) && --attributes[19] > 0);
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
NazaraWarning("Could not find a format matching requirements, disabling antialiasing...");
|
||||
pixelFormat = 0;
|
||||
}
|
||||
|
||||
parameters.antialiasingLevel = attributes[19];
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraWarning("Antialiasing is not supported");
|
||||
parameters.antialiasingLevel = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PIXELFORMATDESCRIPTOR descriptor;
|
||||
ZeroMemory(&descriptor, sizeof(PIXELFORMATDESCRIPTOR));
|
||||
descriptor.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
descriptor.nVersion = 1;
|
||||
|
||||
if (pixelFormat == 0)
|
||||
{
|
||||
descriptor.cColorBits = parameters.bitsPerPixel;
|
||||
descriptor.cDepthBits = parameters.depthBits;
|
||||
descriptor.cStencilBits = parameters.stencilBits;
|
||||
descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
|
||||
descriptor.iPixelType = PFD_TYPE_RGBA;
|
||||
|
||||
if (parameters.bitsPerPixel == 32)
|
||||
descriptor.cAlphaBits = 8;
|
||||
|
||||
if (parameters.doubleBuffered)
|
||||
descriptor.dwFlags |= PFD_DOUBLEBUFFER;
|
||||
|
||||
pixelFormat = ChoosePixelFormat(m_deviceContext, &descriptor);
|
||||
if (pixelFormat == 0)
|
||||
{
|
||||
NazaraError("Failed to choose pixel format");
|
||||
Destroy();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!SetPixelFormat(m_deviceContext, pixelFormat, &descriptor))
|
||||
{
|
||||
NazaraError("Failed to set pixel format");
|
||||
Destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Arrivé ici, le format de pixel est choisi, nous récupérons donc les paramètres réels du futur contexte
|
||||
if (DescribePixelFormat(m_deviceContext, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &descriptor) != 0)
|
||||
{
|
||||
parameters.bitsPerPixel = descriptor.cColorBits + descriptor.cAlphaBits;
|
||||
parameters.depthBits = descriptor.cDepthBits;
|
||||
parameters.stencilBits = descriptor.cDepthBits;
|
||||
}
|
||||
else
|
||||
NazaraWarning("Failed to get context's parameters");
|
||||
|
||||
HGLRC shareContext = (parameters.shared) ? static_cast<NzContextImpl*>(parameters.shareContext->m_impl)->m_context : nullptr;
|
||||
|
||||
m_context = nullptr;
|
||||
if (wglCreateContextAttribs)
|
||||
{
|
||||
int attributes[4*2+1];
|
||||
int* attrib = attributes;
|
||||
|
||||
*attrib++ = WGL_CONTEXT_MAJOR_VERSION_ARB;
|
||||
*attrib++ = parameters.majorVersion;
|
||||
|
||||
*attrib++ = WGL_CONTEXT_MINOR_VERSION_ARB;
|
||||
*attrib++ = parameters.minorVersion;
|
||||
|
||||
if (parameters.majorVersion >= 3)
|
||||
{
|
||||
*attrib++ = WGL_CONTEXT_PROFILE_MASK_ARB;
|
||||
*attrib++ = (parameters.compatibilityProfile) ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB : WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
|
||||
}
|
||||
|
||||
if (parameters.debugMode)
|
||||
{
|
||||
*attrib++ = WGL_CONTEXT_FLAGS_ARB;
|
||||
*attrib++ = WGL_CONTEXT_DEBUG_BIT_ARB;
|
||||
|
||||
// Les contextes forward-compatible ne sont plus utilisés pour cette raison :
|
||||
// http://www.opengl.org/discussion_boards/showthread.php/175052-Forward-compatible-vs-Core-profile
|
||||
}
|
||||
|
||||
*attrib++ = 0;
|
||||
|
||||
m_context = wglCreateContextAttribs(m_deviceContext, shareContext, attributes);
|
||||
}
|
||||
|
||||
if (!m_context)
|
||||
{
|
||||
m_context = wglCreateContext(m_deviceContext);
|
||||
|
||||
if (shareContext)
|
||||
{
|
||||
// wglShareLists n'est pas thread-safe (source: SFML)
|
||||
static NzMutex mutex;
|
||||
NzLockGuard lock(mutex);
|
||||
|
||||
if (!wglShareLists(shareContext, m_context))
|
||||
NazaraWarning("Failed to share the context: " + NzGetLastSystemError());
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_context)
|
||||
{
|
||||
NazaraError("Failed to create context");
|
||||
Destroy();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzContextImpl::Destroy()
|
||||
{
|
||||
if (m_context)
|
||||
{
|
||||
if (wglGetCurrentContext() == m_context)
|
||||
wglMakeCurrent(nullptr, nullptr);
|
||||
|
||||
wglDeleteContext(m_context);
|
||||
m_context = nullptr;
|
||||
}
|
||||
|
||||
if (m_deviceContext)
|
||||
{
|
||||
ReleaseDC(m_window, m_deviceContext);
|
||||
m_deviceContext = nullptr;
|
||||
}
|
||||
|
||||
if (m_ownsWindow)
|
||||
{
|
||||
DestroyWindow(m_window);
|
||||
m_window = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void NzContextImpl::SwapBuffers()
|
||||
{
|
||||
::SwapBuffers(m_deviceContext);
|
||||
}
|
||||
|
||||
bool NzContextImpl::Desactivate()
|
||||
{
|
||||
return wglMakeCurrent(nullptr, nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,317 +1,342 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Animation.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Utility/Config.hpp>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
struct NzAnimationImpl
|
||||
{
|
||||
std::map<NzString, unsigned int> sequenceMap;
|
||||
std::vector<NzSequence> sequences;
|
||||
nzAnimationType type;
|
||||
unsigned int frameCount;
|
||||
};
|
||||
|
||||
bool NzAnimationParams::IsValid() const
|
||||
{
|
||||
if (startFrame > endFrame)
|
||||
{
|
||||
NazaraError("Start frame must be lower than end frame");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NzAnimation::~NzAnimation()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
unsigned int NzAnimation::AddSequence(const NzSequence& sequence)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int index = m_impl->sequences.size();
|
||||
|
||||
if (!sequence.name.IsEmpty())
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
auto it = m_impl->sequenceMap.find(sequence.name);
|
||||
if (it != m_impl->sequenceMap.end())
|
||||
{
|
||||
NazaraError("Sequence name \"" + sequence.name + "\" is already used");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->sequenceMap[sequence.name] = index;
|
||||
}
|
||||
|
||||
m_impl->sequences.push_back(sequence);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
bool NzAnimation::Create(nzAnimationType type, unsigned int frameCount)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (type == nzAnimationType_Static)
|
||||
{
|
||||
NazaraError("Invalid type");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (frameCount == 0)
|
||||
{
|
||||
NazaraError("Frame count must be over zero");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl = new NzAnimationImpl;
|
||||
m_impl->frameCount = frameCount;
|
||||
m_impl->type = type;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzAnimation::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int NzAnimation::GetFrameCount() const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->frameCount;
|
||||
}
|
||||
|
||||
NzSequence* NzAnimation::GetSequence(const NzString& sequenceName)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto it = m_impl->sequenceMap.find(sequenceName);
|
||||
if (it == m_impl->sequenceMap.end())
|
||||
{
|
||||
NazaraError("Sequence not found");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &m_impl->sequences[it->second];
|
||||
#else
|
||||
return &m_impl->sequences[m_impl->sequenceMap[sequenceName]];
|
||||
#endif
|
||||
}
|
||||
|
||||
NzSequence* NzAnimation::GetSequence(unsigned int index)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (index >= m_impl->sequences.size())
|
||||
{
|
||||
NazaraError("Sequence index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->sequences.size()) + ')');
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return &m_impl->sequences[index];
|
||||
}
|
||||
|
||||
const NzSequence* NzAnimation::GetSequence(const NzString& sequenceName) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto it = m_impl->sequenceMap.find(sequenceName);
|
||||
if (it == m_impl->sequenceMap.end())
|
||||
{
|
||||
NazaraError("Sequence not found");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &m_impl->sequences[it->second];
|
||||
#else
|
||||
return &m_impl->sequences[m_impl->sequenceMap[sequenceName]];
|
||||
#endif
|
||||
}
|
||||
|
||||
const NzSequence* NzAnimation::GetSequence(unsigned int index) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (index >= m_impl->sequences.size())
|
||||
{
|
||||
NazaraError("Sequence index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->sequences.size()) + ')');
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return &m_impl->sequences[index];
|
||||
}
|
||||
|
||||
unsigned int NzAnimation::GetSequenceCount() const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->sequences.size();
|
||||
}
|
||||
|
||||
nzAnimationType NzAnimation::GetType() const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return nzAnimationType_Static; // Ce qui est une valeur invalide pour NzAnimation
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->type;
|
||||
}
|
||||
|
||||
bool NzAnimation::HasSequence(const NzString& sequenceName) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->sequenceMap.find(sequenceName) != m_impl->sequenceMap.end();
|
||||
}
|
||||
|
||||
bool NzAnimation::HasSequence(unsigned int index) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return index >= m_impl->sequences.size();
|
||||
}
|
||||
|
||||
bool NzAnimation::IsValid() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
bool NzAnimation::LoadFromFile(const NzString& filePath, const NzAnimationParams& params)
|
||||
{
|
||||
return NzAnimationLoader::LoadFromFile(this, filePath, params);
|
||||
}
|
||||
|
||||
bool NzAnimation::LoadFromMemory(const void* data, std::size_t size, const NzAnimationParams& params)
|
||||
{
|
||||
return NzAnimationLoader::LoadFromMemory(this, data, size, params);
|
||||
}
|
||||
|
||||
bool NzAnimation::LoadFromStream(NzInputStream& stream, const NzAnimationParams& params)
|
||||
{
|
||||
return NzAnimationLoader::LoadFromStream(this, stream, params);
|
||||
}
|
||||
|
||||
void NzAnimation::RemoveSequence(const NzString& identifier)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = m_impl->sequenceMap.find(identifier);
|
||||
if (it == m_impl->sequenceMap.end())
|
||||
{
|
||||
NazaraError("SubMesh not found");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int index = it->second;
|
||||
#else
|
||||
unsigned int index = m_impl->sequenceMap[identifier];
|
||||
#endif
|
||||
|
||||
auto it2 = m_impl->sequences.begin();
|
||||
std::advance(it2, index);
|
||||
|
||||
m_impl->sequences.erase(it2);
|
||||
}
|
||||
|
||||
void NzAnimation::RemoveSequence(unsigned int index)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return;
|
||||
}
|
||||
|
||||
if (index >= m_impl->sequences.size())
|
||||
{
|
||||
NazaraError("Sequence index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->sequences.size()) + ')');
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto it = m_impl->sequences.begin();
|
||||
std::advance(it, index);
|
||||
|
||||
m_impl->sequences.erase(it);
|
||||
}
|
||||
|
||||
NzAnimationLoader::LoaderList NzAnimation::s_loaders;
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Animation.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Utility/Config.hpp>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
struct NzAnimationImpl
|
||||
{
|
||||
std::map<NzString, unsigned int> sequenceMap;
|
||||
std::vector<NzSequence> sequences;
|
||||
nzAnimationType type;
|
||||
unsigned int frameCount;
|
||||
};
|
||||
|
||||
bool NzAnimationParams::IsValid() const
|
||||
{
|
||||
if (startFrame > endFrame)
|
||||
{
|
||||
NazaraError("Start frame must be lower than end frame");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NzAnimation::~NzAnimation()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzAnimation::AddSequence(const NzSequence& sequence)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int index = m_impl->sequences.size();
|
||||
|
||||
if (!sequence.name.IsEmpty())
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
auto it = m_impl->sequenceMap.find(sequence.name);
|
||||
if (it != m_impl->sequenceMap.end())
|
||||
{
|
||||
NazaraError("Sequence name \"" + sequence.name + "\" is already used");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl->sequenceMap[sequence.name] = index;
|
||||
}
|
||||
|
||||
m_impl->sequences.push_back(sequence);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzAnimation::Create(nzAnimationType type, unsigned int frameCount)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (type == nzAnimationType_Static)
|
||||
{
|
||||
NazaraError("Invalid type");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (frameCount == 0)
|
||||
{
|
||||
NazaraError("Frame count must be over zero");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_impl = new NzAnimationImpl;
|
||||
m_impl->frameCount = frameCount;
|
||||
m_impl->type = type;
|
||||
|
||||
NotifyCreated();
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzAnimation::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
NotifyDestroy();
|
||||
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int NzAnimation::GetFrameCount() const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->frameCount;
|
||||
}
|
||||
|
||||
NzSequence* NzAnimation::GetSequence(const NzString& sequenceName)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto it = m_impl->sequenceMap.find(sequenceName);
|
||||
if (it == m_impl->sequenceMap.end())
|
||||
{
|
||||
NazaraError("Sequence not found");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &m_impl->sequences[it->second];
|
||||
#else
|
||||
return &m_impl->sequences[m_impl->sequenceMap[sequenceName]];
|
||||
#endif
|
||||
}
|
||||
|
||||
NzSequence* NzAnimation::GetSequence(unsigned int index)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (index >= m_impl->sequences.size())
|
||||
{
|
||||
NazaraError("Sequence index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->sequences.size()) + ')');
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return &m_impl->sequences[index];
|
||||
}
|
||||
|
||||
const NzSequence* NzAnimation::GetSequence(const NzString& sequenceName) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto it = m_impl->sequenceMap.find(sequenceName);
|
||||
if (it == m_impl->sequenceMap.end())
|
||||
{
|
||||
NazaraError("Sequence not found");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &m_impl->sequences[it->second];
|
||||
#else
|
||||
return &m_impl->sequences[m_impl->sequenceMap[sequenceName]];
|
||||
#endif
|
||||
}
|
||||
|
||||
const NzSequence* NzAnimation::GetSequence(unsigned int index) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (index >= m_impl->sequences.size())
|
||||
{
|
||||
NazaraError("Sequence index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->sequences.size()) + ')');
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return &m_impl->sequences[index];
|
||||
}
|
||||
|
||||
unsigned int NzAnimation::GetSequenceCount() const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->sequences.size();
|
||||
}
|
||||
|
||||
int NzAnimation::GetSequenceIndex(const NzString& sequenceName) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto it = m_impl->sequenceMap.find(sequenceName);
|
||||
if (it == m_impl->sequenceMap.end())
|
||||
{
|
||||
NazaraError("Sequence not found");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
#else
|
||||
return m_impl->sequenceMap[sequenceName];
|
||||
#endif
|
||||
}
|
||||
|
||||
nzAnimationType NzAnimation::GetType() const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return nzAnimationType_Static; // Ce qui est une valeur invalide pour NzAnimation
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->type;
|
||||
}
|
||||
|
||||
bool NzAnimation::HasSequence(const NzString& sequenceName) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->sequenceMap.find(sequenceName) != m_impl->sequenceMap.end();
|
||||
}
|
||||
|
||||
bool NzAnimation::HasSequence(unsigned int index) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return index >= m_impl->sequences.size();
|
||||
}
|
||||
|
||||
bool NzAnimation::IsValid() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
bool NzAnimation::LoadFromFile(const NzString& filePath, const NzAnimationParams& params)
|
||||
{
|
||||
return NzAnimationLoader::LoadFromFile(this, filePath, params);
|
||||
}
|
||||
|
||||
bool NzAnimation::LoadFromMemory(const void* data, std::size_t size, const NzAnimationParams& params)
|
||||
{
|
||||
return NzAnimationLoader::LoadFromMemory(this, data, size, params);
|
||||
}
|
||||
|
||||
bool NzAnimation::LoadFromStream(NzInputStream& stream, const NzAnimationParams& params)
|
||||
{
|
||||
return NzAnimationLoader::LoadFromStream(this, stream, params);
|
||||
}
|
||||
|
||||
void NzAnimation::RemoveSequence(const NzString& identifier)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = m_impl->sequenceMap.find(identifier);
|
||||
if (it == m_impl->sequenceMap.end())
|
||||
{
|
||||
NazaraError("Sequence not found");
|
||||
return;
|
||||
}
|
||||
|
||||
int index = it->second;
|
||||
#else
|
||||
int index = m_impl->sequenceMap[identifier];
|
||||
#endif
|
||||
|
||||
auto it2 = m_impl->sequences.begin();
|
||||
std::advance(it2, index);
|
||||
|
||||
m_impl->sequences.erase(it2);
|
||||
}
|
||||
|
||||
void NzAnimation::RemoveSequence(unsigned int index)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Animation not created");
|
||||
return;
|
||||
}
|
||||
|
||||
if (index >= m_impl->sequences.size())
|
||||
{
|
||||
NazaraError("Sequence index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->sequences.size()) + ')');
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto it = m_impl->sequences.begin();
|
||||
std::advance(it, index);
|
||||
|
||||
m_impl->sequences.erase(it);
|
||||
}
|
||||
|
||||
NzAnimationLoader::LoaderList NzAnimation::s_loaders;
|
||||
|
||||
@@ -1,337 +1,339 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Buffer.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Utility/BufferImpl.hpp>
|
||||
#include <Nazara/Utility/Config.hpp>
|
||||
#include <Nazara/Utility/SoftwareBuffer.hpp>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
NzBufferImpl* SoftwareBufferFunction(NzBuffer* parent, nzBufferType type)
|
||||
{
|
||||
return new NzSoftwareBuffer(parent, type);
|
||||
}
|
||||
}
|
||||
|
||||
NzBuffer::NzBuffer(nzBufferType type) :
|
||||
m_type(type),
|
||||
m_typeSize(0),
|
||||
m_impl(nullptr),
|
||||
m_length(0)
|
||||
{
|
||||
}
|
||||
|
||||
NzBuffer::NzBuffer(nzBufferType type, unsigned int length, nzUInt8 typeSize, nzBufferStorage storage, nzBufferUsage usage) :
|
||||
m_type(type),
|
||||
m_impl(nullptr)
|
||||
{
|
||||
Create(length, typeSize, storage, usage);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Failed to create buffer");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NzBuffer::~NzBuffer()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzBuffer::CopyContent(NzBuffer& buffer)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Buffer must be valid");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!buffer.IsValid())
|
||||
{
|
||||
NazaraError("Source buffer must be valid");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!buffer.GetTypeSize() != m_typeSize)
|
||||
{
|
||||
NazaraError("Source buffer type size does not match buffer type size");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void* ptr = buffer.Map(nzBufferAccess_ReadOnly);
|
||||
if (!ptr)
|
||||
{
|
||||
NazaraError("Failed to map source buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool r = Fill(ptr, 0, buffer.GetLength());
|
||||
|
||||
if (!buffer.Unmap())
|
||||
NazaraWarning("Failed to unmap source buffer");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool NzBuffer::Create(unsigned int length, nzUInt8 typeSize, nzBufferStorage storage, nzBufferUsage usage)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
// On tente d'abord de faire un buffer hardware, si supporté
|
||||
if (s_bufferFunctions[storage])
|
||||
{
|
||||
NzBufferImpl* impl = s_bufferFunctions[storage](this, m_type);
|
||||
if (!impl->Create(length*typeSize, usage))
|
||||
{
|
||||
NazaraError("Failed to create buffer");
|
||||
delete impl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = impl;
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraError("Buffer storage not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_length = length;
|
||||
m_typeSize = typeSize;
|
||||
m_storage = storage;
|
||||
m_usage = usage;
|
||||
|
||||
// Si on arrive ici c'est que tout s'est bien passé.
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzBuffer::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
m_impl->Destroy();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool NzBuffer::Fill(const void* data, unsigned int offset, unsigned int length)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Buffer not valid");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offset+length > m_length)
|
||||
{
|
||||
NazaraError("Exceeding buffer size");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->Fill(data, offset*m_typeSize, ((length == 0) ? m_length-offset : length)*m_typeSize);
|
||||
}
|
||||
|
||||
NzBufferImpl* NzBuffer::GetImpl() const
|
||||
{
|
||||
return m_impl;
|
||||
}
|
||||
|
||||
unsigned int NzBuffer::GetLength() const
|
||||
{
|
||||
return m_length;
|
||||
}
|
||||
|
||||
void* NzBuffer::GetPointer()
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Buffer not valid");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetPointer();
|
||||
}
|
||||
|
||||
const void* NzBuffer::GetPointer() const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Buffer not valid");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetPointer();
|
||||
}
|
||||
|
||||
unsigned int NzBuffer::GetSize() const
|
||||
{
|
||||
return m_length*m_typeSize;
|
||||
}
|
||||
|
||||
nzBufferStorage NzBuffer::GetStorage() const
|
||||
{
|
||||
return m_storage;
|
||||
}
|
||||
|
||||
nzBufferType NzBuffer::GetType() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
nzUInt8 NzBuffer::GetTypeSize() const
|
||||
{
|
||||
return m_typeSize;
|
||||
}
|
||||
|
||||
nzBufferUsage NzBuffer::GetUsage() const
|
||||
{
|
||||
return m_usage;
|
||||
}
|
||||
|
||||
bool NzBuffer::IsHardware() const
|
||||
{
|
||||
return m_storage == nzBufferStorage_Hardware;
|
||||
}
|
||||
|
||||
bool NzBuffer::IsValid() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
void* NzBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned int length)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Buffer not valid");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (offset+length > m_length)
|
||||
{
|
||||
NazaraError("Exceeding buffer size");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->Map(access, offset*m_typeSize, ((length == 0) ? m_length-offset : length)*m_typeSize);
|
||||
}
|
||||
|
||||
bool NzBuffer::SetStorage(nzBufferStorage storage)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Buffer not valid");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_storage == storage)
|
||||
return true;
|
||||
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!IsSupported(storage))
|
||||
{
|
||||
NazaraError("Storage not supported");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void* ptr = m_impl->Map(nzBufferAccess_ReadOnly, 0, m_length*m_typeSize);
|
||||
if (!ptr)
|
||||
{
|
||||
NazaraError("Failed to map buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
NzBufferImpl* impl = s_bufferFunctions[storage](this, m_type);
|
||||
if (!impl->Create(m_length*m_typeSize, m_usage))
|
||||
{
|
||||
NazaraError("Failed to create buffer");
|
||||
delete impl;
|
||||
|
||||
if (!m_impl->Unmap())
|
||||
NazaraWarning("Failed to unmap buffer");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!impl->Fill(ptr, 0, m_length*m_typeSize))
|
||||
{
|
||||
NazaraError("Failed to fill buffer");
|
||||
impl->Destroy();
|
||||
delete impl;
|
||||
|
||||
if (!m_impl->Unmap())
|
||||
NazaraWarning("Failed to unmap buffer");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl->Unmap();
|
||||
m_impl->Destroy();
|
||||
|
||||
delete m_impl;
|
||||
m_impl = impl;
|
||||
|
||||
m_storage = storage;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzBuffer::Unmap()
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Buffer not valid");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->Unmap();
|
||||
}
|
||||
|
||||
bool NzBuffer::IsSupported(nzBufferStorage storage)
|
||||
{
|
||||
return s_bufferFunctions[storage] != nullptr;
|
||||
}
|
||||
|
||||
void NzBuffer::SetBufferFunction(nzBufferStorage storage, BufferFunction func)
|
||||
{
|
||||
s_bufferFunctions[storage] = func;
|
||||
}
|
||||
|
||||
bool NzBuffer::Initialize()
|
||||
{
|
||||
s_bufferFunctions[nzBufferStorage_Software] = SoftwareBufferFunction;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzBuffer::Uninitialize()
|
||||
{
|
||||
std::memset(s_bufferFunctions, 0, (nzBufferStorage_Max+1)*sizeof(NzBuffer::BufferFunction));
|
||||
}
|
||||
|
||||
NzBuffer::BufferFunction NzBuffer::s_bufferFunctions[nzBufferStorage_Max+1] = {0};
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Buffer.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Utility/BufferImpl.hpp>
|
||||
#include <Nazara/Utility/Config.hpp>
|
||||
#include <Nazara/Utility/SoftwareBuffer.hpp>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
NzBufferImpl* SoftwareBufferFunction(NzBuffer* parent, nzBufferType type)
|
||||
{
|
||||
return new NzSoftwareBuffer(parent, type);
|
||||
}
|
||||
}
|
||||
|
||||
NzBuffer::NzBuffer(nzBufferType type) :
|
||||
m_type(type),
|
||||
m_typeSize(0),
|
||||
m_impl(nullptr),
|
||||
m_length(0)
|
||||
{
|
||||
}
|
||||
|
||||
NzBuffer::NzBuffer(nzBufferType type, unsigned int length, nzUInt8 typeSize, nzBufferStorage storage, nzBufferUsage usage) :
|
||||
m_type(type),
|
||||
m_impl(nullptr)
|
||||
{
|
||||
Create(length, typeSize, storage, usage);
|
||||
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Failed to create buffer");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
NzBuffer::~NzBuffer()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzBuffer::CopyContent(NzBuffer& buffer)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Buffer must be valid");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!buffer.IsValid())
|
||||
{
|
||||
NazaraError("Source buffer must be valid");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!buffer.GetTypeSize() != m_typeSize)
|
||||
{
|
||||
NazaraError("Source buffer type size does not match buffer type size");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void* ptr = buffer.Map(nzBufferAccess_ReadOnly);
|
||||
if (!ptr)
|
||||
{
|
||||
NazaraError("Failed to map source buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool r = Fill(ptr, 0, buffer.GetLength());
|
||||
|
||||
if (!buffer.Unmap())
|
||||
NazaraWarning("Failed to unmap source buffer");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool NzBuffer::Create(unsigned int length, nzUInt8 typeSize, nzBufferStorage storage, nzBufferUsage usage)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
// On tente d'abord de faire un buffer hardware, si supporté
|
||||
if (s_bufferFunctions[storage])
|
||||
{
|
||||
NzBufferImpl* impl = s_bufferFunctions[storage](this, m_type);
|
||||
if (!impl->Create(length*typeSize, usage))
|
||||
{
|
||||
NazaraError("Failed to create buffer");
|
||||
delete impl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl = impl;
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraError("Buffer storage not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_length = length;
|
||||
m_typeSize = typeSize;
|
||||
m_storage = storage;
|
||||
m_usage = usage;
|
||||
|
||||
NotifyCreated();
|
||||
return true; // Si on arrive ici c'est que tout s'est bien passé.
|
||||
}
|
||||
|
||||
void NzBuffer::Destroy()
|
||||
{
|
||||
if (m_impl)
|
||||
{
|
||||
NotifyDestroy();
|
||||
|
||||
m_impl->Destroy();
|
||||
delete m_impl;
|
||||
m_impl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool NzBuffer::Fill(const void* data, unsigned int offset, unsigned int length)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Buffer not valid");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offset+length > m_length)
|
||||
{
|
||||
NazaraError("Exceeding buffer size");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->Fill(data, offset*m_typeSize, ((length == 0) ? m_length-offset : length)*m_typeSize);
|
||||
}
|
||||
|
||||
NzBufferImpl* NzBuffer::GetImpl() const
|
||||
{
|
||||
return m_impl;
|
||||
}
|
||||
|
||||
unsigned int NzBuffer::GetLength() const
|
||||
{
|
||||
return m_length;
|
||||
}
|
||||
|
||||
void* NzBuffer::GetPointer()
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Buffer not valid");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetPointer();
|
||||
}
|
||||
|
||||
const void* NzBuffer::GetPointer() const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Buffer not valid");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->GetPointer();
|
||||
}
|
||||
|
||||
unsigned int NzBuffer::GetSize() const
|
||||
{
|
||||
return m_length*m_typeSize;
|
||||
}
|
||||
|
||||
nzBufferStorage NzBuffer::GetStorage() const
|
||||
{
|
||||
return m_storage;
|
||||
}
|
||||
|
||||
nzBufferType NzBuffer::GetType() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
nzUInt8 NzBuffer::GetTypeSize() const
|
||||
{
|
||||
return m_typeSize;
|
||||
}
|
||||
|
||||
nzBufferUsage NzBuffer::GetUsage() const
|
||||
{
|
||||
return m_usage;
|
||||
}
|
||||
|
||||
bool NzBuffer::IsHardware() const
|
||||
{
|
||||
return m_storage == nzBufferStorage_Hardware;
|
||||
}
|
||||
|
||||
bool NzBuffer::IsValid() const
|
||||
{
|
||||
return m_impl != nullptr;
|
||||
}
|
||||
|
||||
void* NzBuffer::Map(nzBufferAccess access, unsigned int offset, unsigned int length)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Buffer not valid");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (offset+length > m_length)
|
||||
{
|
||||
NazaraError("Exceeding buffer size");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->Map(access, offset*m_typeSize, ((length == 0) ? m_length-offset : length)*m_typeSize);
|
||||
}
|
||||
|
||||
bool NzBuffer::SetStorage(nzBufferStorage storage)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Buffer not valid");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_storage == storage)
|
||||
return true;
|
||||
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!IsSupported(storage))
|
||||
{
|
||||
NazaraError("Storage not supported");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void* ptr = m_impl->Map(nzBufferAccess_ReadOnly, 0, m_length*m_typeSize);
|
||||
if (!ptr)
|
||||
{
|
||||
NazaraError("Failed to map buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
NzBufferImpl* impl = s_bufferFunctions[storage](this, m_type);
|
||||
if (!impl->Create(m_length*m_typeSize, m_usage))
|
||||
{
|
||||
NazaraError("Failed to create buffer");
|
||||
delete impl;
|
||||
|
||||
if (!m_impl->Unmap())
|
||||
NazaraWarning("Failed to unmap buffer");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!impl->Fill(ptr, 0, m_length*m_typeSize))
|
||||
{
|
||||
NazaraError("Failed to fill buffer");
|
||||
impl->Destroy();
|
||||
delete impl;
|
||||
|
||||
if (!m_impl->Unmap())
|
||||
NazaraWarning("Failed to unmap buffer");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_impl->Unmap();
|
||||
m_impl->Destroy();
|
||||
|
||||
delete m_impl;
|
||||
m_impl = impl;
|
||||
|
||||
m_storage = storage;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NzBuffer::Unmap()
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_impl)
|
||||
{
|
||||
NazaraError("Buffer not valid");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_impl->Unmap();
|
||||
}
|
||||
|
||||
bool NzBuffer::IsSupported(nzBufferStorage storage)
|
||||
{
|
||||
return s_bufferFunctions[storage] != nullptr;
|
||||
}
|
||||
|
||||
void NzBuffer::SetBufferFunction(nzBufferStorage storage, BufferFunction func)
|
||||
{
|
||||
s_bufferFunctions[storage] = func;
|
||||
}
|
||||
|
||||
bool NzBuffer::Initialize()
|
||||
{
|
||||
s_bufferFunctions[nzBufferStorage_Software] = SoftwareBufferFunction;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzBuffer::Uninitialize()
|
||||
{
|
||||
std::memset(s_bufferFunctions, 0, (nzBufferStorage_Max+1)*sizeof(NzBuffer::BufferFunction));
|
||||
}
|
||||
|
||||
NzBuffer::BufferFunction NzBuffer::s_bufferFunctions[nzBufferStorage_Max+1] = {0};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,221 +1,200 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Loaders/MD2.hpp>
|
||||
#include <Nazara/Core/Endianness.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Core/InputStream.hpp>
|
||||
#include <Nazara/Core/MemoryStream.hpp>
|
||||
#include <Nazara/Math/Basic.hpp>
|
||||
#include <Nazara/Utility/Mesh.hpp>
|
||||
#include <Nazara/Utility/Loaders/MD2/Constants.hpp>
|
||||
#include <Nazara/Utility/Loaders/MD2/Mesh.hpp>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
bool NzLoader_MD2_Check(NzInputStream& stream, const NzMeshParams& parameters)
|
||||
{
|
||||
NazaraUnused(parameters);
|
||||
|
||||
nzUInt32 magic[2];
|
||||
if (stream.Read(&magic[0], 2*sizeof(nzUInt32)) != 2*sizeof(nzUInt32))
|
||||
return false;
|
||||
|
||||
#if defined(NAZARA_BIG_ENDIAN)
|
||||
NzByteSwap(&magic[0], sizeof(nzUInt32));
|
||||
NzByteSwap(&magic[1], sizeof(nzUInt32));
|
||||
#endif
|
||||
|
||||
return magic[0] == md2Ident && magic[1] == 8;
|
||||
}
|
||||
|
||||
bool NzLoader_MD2_Load(NzMesh* mesh, NzInputStream& stream, const NzMeshParams& parameters)
|
||||
{
|
||||
md2_header header;
|
||||
if (stream.Read(&header, sizeof(md2_header)) != sizeof(md2_header))
|
||||
{
|
||||
NazaraError("Failed to read header");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Les fichiers MD2 sont en little endian
|
||||
#if defined(NAZARA_BIG_ENDIAN)
|
||||
NzByteSwap(&header.ident, sizeof(nzUInt32));
|
||||
#endif
|
||||
|
||||
if (header.ident != md2Ident)
|
||||
{
|
||||
NazaraError("Invalid MD2 file");
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(NAZARA_BIG_ENDIAN)
|
||||
NzByteSwap(&header.version, sizeof(nzUInt32));
|
||||
#endif
|
||||
|
||||
if (header.version != 8)
|
||||
{
|
||||
NazaraError("Bad version number (" + NzString::Number(header.version) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(NAZARA_BIG_ENDIAN)
|
||||
NzByteSwap(&header.skinwidth, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.skinheight, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.framesize, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.num_skins, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.num_vertices, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.num_st, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.num_tris, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.num_glcmds, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.num_frames, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.offset_skins, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.offset_st, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.offset_tris, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.offset_frames, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.offset_glcmds, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.offset_end, sizeof(nzUInt32));
|
||||
#endif
|
||||
|
||||
if (stream.GetSize() < header.offset_end)
|
||||
{
|
||||
NazaraError("Incomplete MD2 file");
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Création du mesh
|
||||
// Animé ou statique, c'est la question
|
||||
bool animated;
|
||||
unsigned int startFrame = NzClamp(parameters.animation.startFrame, 0U, static_cast<unsigned int>(header.num_frames-1));
|
||||
unsigned int endFrame = NzClamp(parameters.animation.endFrame, 0U, static_cast<unsigned int>(header.num_frames-1));
|
||||
|
||||
if (parameters.loadAnimations && startFrame != endFrame)
|
||||
animated = true;
|
||||
else
|
||||
animated = false;
|
||||
|
||||
if (!mesh->Create((animated) ? nzAnimationType_Keyframe : nzAnimationType_Static)) // Ne devrait pas échouer
|
||||
{
|
||||
NazaraInternalError("Failed to create mesh");
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Chargement des skins
|
||||
if (header.num_skins > 0)
|
||||
{
|
||||
stream.SetCursorPos(header.offset_skins);
|
||||
{
|
||||
char skin[68];
|
||||
for (unsigned int i = 0; i < header.num_skins; ++i)
|
||||
{
|
||||
stream.Read(skin, 68*sizeof(char));
|
||||
mesh->AddSkin(skin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Chargement des animmations
|
||||
if (animated)
|
||||
{
|
||||
NzAnimation* animation = new NzAnimation;
|
||||
if (animation->Create(nzAnimationType_Keyframe, endFrame-startFrame+1))
|
||||
{
|
||||
// Décodage des séquences
|
||||
NzString frameName;
|
||||
|
||||
NzSequence sequence;
|
||||
sequence.framePerSecond = 10; // Par défaut pour les animations MD2
|
||||
|
||||
char name[16], last[16];
|
||||
stream.SetCursorPos(header.offset_frames + startFrame*header.framesize + offsetof(md2_frame, name));
|
||||
stream.Read(last, 16*sizeof(char));
|
||||
|
||||
int pos = std::strlen(last)-1;
|
||||
for (unsigned int j = 0; j < 2; ++j)
|
||||
{
|
||||
if (!std::isdigit(last[pos]))
|
||||
break;
|
||||
|
||||
pos--;
|
||||
}
|
||||
last[pos+1] = '\0';
|
||||
|
||||
unsigned int numFrames = 0;
|
||||
for (unsigned int i = startFrame; i <= endFrame; ++i)
|
||||
{
|
||||
stream.SetCursorPos(header.offset_frames + i*header.framesize + offsetof(md2_frame, name));
|
||||
stream.Read(name, 16*sizeof(char));
|
||||
|
||||
pos = std::strlen(name)-1;
|
||||
for (unsigned int j = 0; j < 2; ++j)
|
||||
{
|
||||
if (!std::isdigit(name[pos]))
|
||||
break;
|
||||
|
||||
pos--;
|
||||
}
|
||||
name[pos+1] = '\0';
|
||||
|
||||
if (std::strcmp(name, last) != 0) // Si les deux frames n'ont pas le même nom
|
||||
{
|
||||
// Alors on enregistre la séquence
|
||||
sequence.firstFrame = i-numFrames;
|
||||
sequence.lastFrame = i-1;
|
||||
sequence.name = last;
|
||||
animation->AddSequence(sequence);
|
||||
|
||||
std::strcpy(last, name);
|
||||
|
||||
numFrames = 0;
|
||||
}
|
||||
|
||||
numFrames++;
|
||||
}
|
||||
|
||||
// On ajoute la dernière frame (Qui n'a pas été traitée par la boucle)
|
||||
sequence.firstFrame = endFrame-numFrames;
|
||||
sequence.lastFrame = endFrame;
|
||||
sequence.name = last;
|
||||
animation->AddSequence(sequence);
|
||||
|
||||
mesh->SetAnimation(animation);
|
||||
animation->SetPersistent(false);
|
||||
}
|
||||
else
|
||||
NazaraInternalError("Failed to create animaton");
|
||||
}
|
||||
|
||||
/// Chargement des submesh
|
||||
// Actuellement le loader ne charge qu'un submesh
|
||||
// TODO: Utiliser les commandes OpenGL pour accélérer le rendu
|
||||
NzMD2Mesh* subMesh = new NzMD2Mesh(mesh);
|
||||
if (!subMesh->Create(header, stream, parameters))
|
||||
{
|
||||
NazaraError("Failed to create MD2 mesh");
|
||||
return false;
|
||||
}
|
||||
|
||||
mesh->AddSubMesh(subMesh);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void NzLoaders_MD2_Register()
|
||||
{
|
||||
NzMD2Mesh::Initialize();
|
||||
|
||||
NzMeshLoader::RegisterLoader("md2", NzLoader_MD2_Check, NzLoader_MD2_Load);
|
||||
}
|
||||
|
||||
void NzLoaders_MD2_Unregister()
|
||||
{
|
||||
NzMeshLoader::UnregisterLoader("md2", NzLoader_MD2_Check, NzLoader_MD2_Load);
|
||||
|
||||
NzMD2Mesh::Uninitialize();
|
||||
}
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Loaders/MD2.hpp>
|
||||
#include <Nazara/Core/Endianness.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Core/InputStream.hpp>
|
||||
#include <Nazara/Core/MemoryStream.hpp>
|
||||
#include <Nazara/Math/Basic.hpp>
|
||||
#include <Nazara/Utility/Mesh.hpp>
|
||||
#include <Nazara/Utility/Loaders/MD2/Constants.hpp>
|
||||
#include <Nazara/Utility/Loaders/MD2/Mesh.hpp>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
bool NzLoader_MD2_Check(NzInputStream& stream, const NzMeshParams& parameters)
|
||||
{
|
||||
NazaraUnused(parameters);
|
||||
|
||||
nzUInt32 magic[2];
|
||||
if (stream.Read(&magic[0], 2*sizeof(nzUInt32)) != 2*sizeof(nzUInt32))
|
||||
return false;
|
||||
|
||||
#if defined(NAZARA_BIG_ENDIAN)
|
||||
NzByteSwap(&magic[0], sizeof(nzUInt32));
|
||||
NzByteSwap(&magic[1], sizeof(nzUInt32));
|
||||
#endif
|
||||
|
||||
return magic[0] == md2Ident && magic[1] == 8;
|
||||
}
|
||||
|
||||
bool NzLoader_MD2_Load(NzMesh* mesh, NzInputStream& stream, const NzMeshParams& parameters)
|
||||
{
|
||||
md2_header header;
|
||||
if (stream.Read(&header, sizeof(md2_header)) != sizeof(md2_header))
|
||||
{
|
||||
NazaraError("Failed to read header");
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(NAZARA_BIG_ENDIAN)
|
||||
NzByteSwap(&header.skinwidth, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.skinheight, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.framesize, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.num_skins, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.num_vertices, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.num_st, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.num_tris, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.num_glcmds, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.num_frames, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.offset_skins, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.offset_st, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.offset_tris, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.offset_frames, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.offset_glcmds, sizeof(nzUInt32));
|
||||
NzByteSwap(&header.offset_end, sizeof(nzUInt32));
|
||||
#endif
|
||||
|
||||
if (stream.GetSize() < header.offset_end)
|
||||
{
|
||||
NazaraError("Incomplete MD2 file");
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Création du mesh
|
||||
// Animé ou statique, c'est la question
|
||||
bool animated;
|
||||
unsigned int startFrame = NzClamp(parameters.animation.startFrame, 0U, static_cast<unsigned int>(header.num_frames-1));
|
||||
unsigned int endFrame = NzClamp(parameters.animation.endFrame, 0U, static_cast<unsigned int>(header.num_frames-1));
|
||||
|
||||
if (parameters.loadAnimations && startFrame != endFrame)
|
||||
animated = true;
|
||||
else
|
||||
animated = false;
|
||||
|
||||
if (!mesh->Create((animated) ? nzAnimationType_Keyframe : nzAnimationType_Static)) // Ne devrait jamais échouer
|
||||
{
|
||||
NazaraInternalError("Failed to create mesh");
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Chargement des skins
|
||||
if (header.num_skins > 0)
|
||||
{
|
||||
stream.SetCursorPos(header.offset_skins);
|
||||
{
|
||||
char skin[68];
|
||||
for (unsigned int i = 0; i < header.num_skins; ++i)
|
||||
{
|
||||
stream.Read(skin, 68*sizeof(char));
|
||||
mesh->AddSkin(skin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Chargement des animmations
|
||||
if (animated)
|
||||
{
|
||||
NzAnimation* animation = new NzAnimation;
|
||||
if (animation->Create(nzAnimationType_Keyframe, endFrame-startFrame+1))
|
||||
{
|
||||
// Décodage des séquences
|
||||
NzString frameName;
|
||||
|
||||
NzSequence sequence;
|
||||
sequence.framePerSecond = 10; // Par défaut pour les animations MD2
|
||||
|
||||
char name[16], last[16];
|
||||
stream.SetCursorPos(header.offset_frames + startFrame*header.framesize + offsetof(md2_frame, name));
|
||||
stream.Read(last, 16*sizeof(char));
|
||||
|
||||
int pos = std::strlen(last)-1;
|
||||
for (unsigned int j = 0; j < 2; ++j)
|
||||
{
|
||||
if (!std::isdigit(last[pos]))
|
||||
break;
|
||||
|
||||
pos--;
|
||||
}
|
||||
last[pos+1] = '\0';
|
||||
|
||||
unsigned int numFrames = 0;
|
||||
for (unsigned int i = startFrame; i <= endFrame; ++i)
|
||||
{
|
||||
stream.SetCursorPos(header.offset_frames + i*header.framesize + offsetof(md2_frame, name));
|
||||
stream.Read(name, 16*sizeof(char));
|
||||
|
||||
pos = std::strlen(name)-1;
|
||||
for (unsigned int j = 0; j < 2; ++j)
|
||||
{
|
||||
if (!std::isdigit(name[pos]))
|
||||
break;
|
||||
|
||||
pos--;
|
||||
}
|
||||
name[pos+1] = '\0';
|
||||
|
||||
if (std::strcmp(name, last) != 0) // Si les deux frames n'ont pas le même nom
|
||||
{
|
||||
// Alors on enregistre la séquence
|
||||
sequence.firstFrame = i-numFrames;
|
||||
sequence.lastFrame = i-1;
|
||||
sequence.name = last;
|
||||
animation->AddSequence(sequence);
|
||||
|
||||
std::strcpy(last, name);
|
||||
|
||||
numFrames = 0;
|
||||
}
|
||||
|
||||
numFrames++;
|
||||
}
|
||||
|
||||
// On ajoute la dernière frame (Qui n'a pas été traitée par la boucle)
|
||||
sequence.firstFrame = endFrame-numFrames;
|
||||
sequence.lastFrame = endFrame;
|
||||
sequence.name = last;
|
||||
animation->AddSequence(sequence);
|
||||
|
||||
mesh->SetAnimation(animation);
|
||||
animation->SetPersistent(false);
|
||||
}
|
||||
else
|
||||
NazaraInternalError("Failed to create animaton");
|
||||
}
|
||||
|
||||
/// Chargement des submesh
|
||||
// Actuellement le loader ne charge qu'un submesh
|
||||
// TODO: Utiliser les commandes OpenGL pour accélérer le rendu
|
||||
NzMD2Mesh* subMesh = new NzMD2Mesh(mesh);
|
||||
if (!subMesh->Create(header, stream, parameters))
|
||||
{
|
||||
NazaraError("Failed to create MD2 mesh");
|
||||
return false;
|
||||
}
|
||||
|
||||
mesh->AddSubMesh(subMesh);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void NzLoaders_MD2_Register()
|
||||
{
|
||||
NzMD2Mesh::Initialize();
|
||||
|
||||
NzMeshLoader::RegisterLoader("md2", NzLoader_MD2_Check, NzLoader_MD2_Load);
|
||||
}
|
||||
|
||||
void NzLoaders_MD2_Unregister()
|
||||
{
|
||||
NzMeshLoader::UnregisterLoader("md2", NzLoader_MD2_Check, NzLoader_MD2_Load);
|
||||
|
||||
NzMD2Mesh::Uninitialize();
|
||||
}
|
||||
|
||||
@@ -1,287 +1,292 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Loaders/MD2/Mesh.hpp>
|
||||
#include <Nazara/Core/InputStream.hpp>
|
||||
#include <Nazara/Math/Matrix4.hpp>
|
||||
#include <Nazara/Utility/IndexBuffer.hpp>
|
||||
#include <Nazara/Utility/Mesh.hpp>
|
||||
#include <Nazara/Utility/VertexBuffer.hpp>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
NzMD2Mesh::NzMD2Mesh(const NzMesh* parent) :
|
||||
NzKeyframeMesh(parent),
|
||||
m_frames(nullptr),
|
||||
m_indexBuffer(nullptr),
|
||||
m_vertexBuffer(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
NzMD2Mesh::~NzMD2Mesh()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzMD2Mesh::Create(const md2_header& header, NzInputStream& stream, const NzMeshParams& parameters)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
unsigned int startFrame = NzClamp(parameters.animation.startFrame, 0U, static_cast<unsigned int>(header.num_frames-1));
|
||||
unsigned int endFrame = NzClamp(parameters.animation.endFrame, 0U, static_cast<unsigned int>(header.num_frames-1));
|
||||
|
||||
m_frameCount = endFrame - startFrame + 1;
|
||||
m_vertexCount = header.num_tris*3;
|
||||
|
||||
/// Chargement des vertices
|
||||
std::vector<md2_texCoord> texCoords(header.num_st);
|
||||
std::vector<md2_triangle> triangles(header.num_tris);
|
||||
|
||||
// Lecture des coordonnées de texture
|
||||
stream.SetCursorPos(header.offset_st);
|
||||
stream.Read(&texCoords[0], header.num_st*sizeof(md2_texCoord));
|
||||
|
||||
#if defined(NAZARA_BIG_ENDIAN)
|
||||
for (unsigned int i = 0; i < header.num_st; ++i)
|
||||
{
|
||||
NzByteSwap(&texCoords[i].u, sizeof(nzInt16));
|
||||
NzByteSwap(&texCoords[i].v, sizeof(nzInt16));
|
||||
}
|
||||
#endif
|
||||
|
||||
stream.SetCursorPos(header.offset_tris);
|
||||
stream.Read(&triangles[0], header.num_tris*sizeof(md2_triangle));
|
||||
|
||||
#if defined(NAZARA_BIG_ENDIAN)
|
||||
for (unsigned int i = 0; i < header.num_tris; ++i)
|
||||
{
|
||||
NzByteSwap(&triangles[i].vertices[0], sizeof(nzUInt16));
|
||||
NzByteSwap(&texCoords[i].texCoords[0], sizeof(nzUInt16));
|
||||
|
||||
NzByteSwap(&triangles[i].vertices[1], sizeof(nzUInt16));
|
||||
NzByteSwap(&texCoords[i].texCoords[1], sizeof(nzUInt16));
|
||||
|
||||
NzByteSwap(&triangles[i].vertices[2], sizeof(nzUInt16));
|
||||
NzByteSwap(&texCoords[i].texCoords[2], sizeof(nzUInt16));
|
||||
}
|
||||
#endif
|
||||
|
||||
stream.SetCursorPos(header.offset_frames + header.framesize*startFrame);
|
||||
|
||||
md2_frame frame;
|
||||
frame.vertices.resize(header.num_vertices);
|
||||
|
||||
// Pour que le modèle soit correctement aligné, on génère une matrice de rotation que nous appliquerons à chacune des vertices
|
||||
NzMatrix4f rotationMatrix = NzMatrix4f::Rotate(NzEulerAnglesf(90.f, -90.f, 0.f));
|
||||
|
||||
unsigned int stride = s_declaration.GetStride(nzElementStream_VertexData);
|
||||
|
||||
m_frames = new Frame[m_frameCount];
|
||||
for (unsigned int i = 0; i < m_frameCount; ++i)
|
||||
{
|
||||
stream.Read(&frame.scale, sizeof(NzVector3f));
|
||||
stream.Read(&frame.translate, sizeof(NzVector3f));
|
||||
stream.Read(&frame.name, 16*sizeof(char));
|
||||
stream.Read(&frame.vertices[0], header.num_vertices*sizeof(md2_vertex));
|
||||
|
||||
#if defined(NAZARA_BIG_ENDIAN)
|
||||
NzByteSwap(&frame.scale.x, sizeof(float));
|
||||
NzByteSwap(&frame.scale.y, sizeof(float));
|
||||
NzByteSwap(&frame.scale.z, sizeof(float));
|
||||
|
||||
NzByteSwap(&frame.translate.x, sizeof(float));
|
||||
NzByteSwap(&frame.translate.y, sizeof(float));
|
||||
NzByteSwap(&frame.translate.z, sizeof(float));
|
||||
#endif
|
||||
|
||||
m_frames[i].normal = new nzUInt8[m_vertexCount]; // Nous stockons l'indice de la normale plutôt que la normale (gain d'espace)
|
||||
m_frames[i].vertices = new NzVector3f[m_vertexCount];
|
||||
|
||||
NzVector3f max, min;
|
||||
for (unsigned int t = 0; t < header.num_tris; ++t)
|
||||
{
|
||||
for (unsigned int v = 0; v < 3; ++v)
|
||||
{
|
||||
const md2_vertex& vert = frame.vertices[triangles[t].vertices[v]];
|
||||
|
||||
NzVector3f vertex = rotationMatrix * NzVector3f(vert.x * frame.scale.x + frame.translate.x, vert.y * frame.scale.y + frame.translate.y, vert.z * frame.scale.z + frame.translate.z);
|
||||
max.MakeCeil(vertex);
|
||||
min.MakeFloor(vertex);
|
||||
|
||||
m_frames[i].normal[t*3+v] = vert.n;
|
||||
m_frames[i].vertices[t*3+v] = vertex;
|
||||
}
|
||||
}
|
||||
|
||||
m_frames[i].aabb.SetExtends(min, max);
|
||||
}
|
||||
|
||||
m_indexBuffer = nullptr; // Pas d'indexbuffer pour l'instant
|
||||
m_vertexBuffer = new NzVertexBuffer(m_vertexCount, (3+3+2)*sizeof(float), parameters.storage, nzBufferUsage_Dynamic);
|
||||
|
||||
nzUInt8* ptr = reinterpret_cast<nzUInt8*>(m_vertexBuffer->Map(nzBufferAccess_WriteOnly));
|
||||
if (!ptr)
|
||||
{
|
||||
NazaraError("Failed to map vertex buffer");
|
||||
Destroy();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// On avance jusqu'aux premières coordonnées de texture
|
||||
ptr += s_declaration.GetElement(nzElementStream_VertexData, nzElementUsage_TexCoord)->offset;
|
||||
for (unsigned int t = 0; t < header.num_tris; ++t)
|
||||
{
|
||||
for (unsigned int v = 0; v < 3; ++v)
|
||||
{
|
||||
const md2_texCoord& texC = texCoords[triangles[t].texCoords[v]];
|
||||
|
||||
NzVector2f* coords = reinterpret_cast<NzVector2f*>(ptr);
|
||||
coords->x = texC.u / static_cast<float>(header.skinwidth);
|
||||
coords->y = 1.f - texC.v / static_cast<float>(header.skinheight);
|
||||
|
||||
ptr += stride;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_vertexBuffer->Unmap())
|
||||
{
|
||||
NazaraError("Failed to unmap buffer");
|
||||
Destroy();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_vertexBuffer->AddResourceReference();
|
||||
m_vertexBuffer->SetPersistent(false);
|
||||
|
||||
AnimateImpl(0, 0, 0.f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzMD2Mesh::Destroy()
|
||||
{
|
||||
if (m_frames)
|
||||
{
|
||||
for (unsigned int i = 0; i < m_frameCount; ++i)
|
||||
{
|
||||
delete[] m_frames[i].normal;
|
||||
delete[] m_frames[i].vertices;
|
||||
}
|
||||
|
||||
delete[] m_frames;
|
||||
m_frames = nullptr;
|
||||
}
|
||||
|
||||
if (m_indexBuffer)
|
||||
{
|
||||
m_indexBuffer->RemoveResourceReference();
|
||||
m_indexBuffer = nullptr;
|
||||
}
|
||||
|
||||
if (m_vertexBuffer)
|
||||
{
|
||||
m_vertexBuffer->RemoveResourceReference();
|
||||
m_vertexBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const NzAxisAlignedBox& NzMD2Mesh::GetAABB() const
|
||||
{
|
||||
return m_aabb;
|
||||
}
|
||||
|
||||
nzAnimationType NzMD2Mesh::GetAnimationType() const
|
||||
{
|
||||
if (m_frameCount > 1)
|
||||
return nzAnimationType_Keyframe;
|
||||
else
|
||||
return nzAnimationType_Static;
|
||||
}
|
||||
|
||||
unsigned int NzMD2Mesh::GetFrameCount() const
|
||||
{
|
||||
return m_frameCount;
|
||||
}
|
||||
|
||||
const NzIndexBuffer* NzMD2Mesh::GetIndexBuffer() const
|
||||
{
|
||||
return nullptr;
|
||||
//return m_indexBuffer;
|
||||
}
|
||||
|
||||
nzPrimitiveType NzMD2Mesh::GetPrimitiveType() const
|
||||
{
|
||||
return nzPrimitiveType_TriangleList;
|
||||
}
|
||||
|
||||
const NzVertexBuffer* NzMD2Mesh::GetVertexBuffer() const
|
||||
{
|
||||
return m_vertexBuffer;
|
||||
}
|
||||
|
||||
const NzVertexDeclaration* NzMD2Mesh::GetVertexDeclaration() const
|
||||
{
|
||||
return &s_declaration;
|
||||
}
|
||||
|
||||
void NzMD2Mesh::Initialize()
|
||||
{
|
||||
NzVertexElement elements[3];
|
||||
elements[0].offset = 0;
|
||||
elements[0].type = nzElementType_Float3;
|
||||
elements[0].usage = nzElementUsage_Position;
|
||||
|
||||
elements[1].offset = 3*sizeof(float);
|
||||
elements[1].type = nzElementType_Float3;
|
||||
elements[1].usage = nzElementUsage_Normal;
|
||||
|
||||
elements[2].offset = 3*sizeof(float) + 3*sizeof(float);
|
||||
elements[2].type = nzElementType_Float2;
|
||||
elements[2].usage = nzElementUsage_TexCoord;
|
||||
|
||||
s_declaration.Create(elements, 3);
|
||||
}
|
||||
|
||||
void NzMD2Mesh::Uninitialize()
|
||||
{
|
||||
s_declaration.Destroy();
|
||||
}
|
||||
|
||||
void NzMD2Mesh::AnimateImpl(unsigned int frameA, unsigned int frameB, float interpolation)
|
||||
{
|
||||
nzUInt8* ptr = reinterpret_cast<nzUInt8*>(m_vertexBuffer->Map(nzBufferAccess_WriteOnly));
|
||||
if (!ptr)
|
||||
{
|
||||
NazaraError("Failed to map vertex buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int stride = s_declaration.GetStride(nzElementStream_VertexData);
|
||||
unsigned int positionOffset = s_declaration.GetElement(nzElementStream_VertexData, nzElementUsage_Position)->offset;
|
||||
unsigned int normalOffset = s_declaration.GetElement(nzElementStream_VertexData, nzElementUsage_Normal)->offset;
|
||||
|
||||
Frame* fA = &m_frames[frameA];
|
||||
Frame* fB = &m_frames[frameB];
|
||||
for (unsigned int i = 0; i < m_vertexCount; ++i)
|
||||
{
|
||||
NzVector3f* position = reinterpret_cast<NzVector3f*>(ptr + positionOffset);
|
||||
NzVector3f* normal = reinterpret_cast<NzVector3f*>(ptr + normalOffset);
|
||||
|
||||
*position = fA->vertices[i] + interpolation * (fB->vertices[i] - fA->vertices[i]);
|
||||
*normal = md2Normals[fA->normal[i]] + interpolation * (md2Normals[fB->normal[i]] - md2Normals[fA->normal[i]]);
|
||||
|
||||
ptr += stride;
|
||||
}
|
||||
|
||||
if (!m_vertexBuffer->Unmap())
|
||||
NazaraWarning("Failed to unmap vertex buffer, expect mesh corruption");
|
||||
|
||||
// Interpolation de l'AABB
|
||||
NzVector3f max1 = fA->aabb.GetMaximum();
|
||||
NzVector3f min1 = fA->aabb.GetMinimum();
|
||||
m_aabb.SetExtends(min1 + interpolation * (fB->aabb.GetMinimum() - min1), max1 + interpolation * (fB->aabb.GetMaximum() - max1));
|
||||
}
|
||||
|
||||
NzVertexDeclaration NzMD2Mesh::s_declaration;
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Loaders/MD2/Mesh.hpp>
|
||||
#include <Nazara/Core/InputStream.hpp>
|
||||
#include <Nazara/Math/Matrix4.hpp>
|
||||
#include <Nazara/Utility/IndexBuffer.hpp>
|
||||
#include <Nazara/Utility/Mesh.hpp>
|
||||
#include <Nazara/Utility/VertexBuffer.hpp>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
NzMD2Mesh::NzMD2Mesh(const NzMesh* parent) :
|
||||
NzKeyframeMesh(parent),
|
||||
m_frames(nullptr),
|
||||
m_indexBuffer(nullptr),
|
||||
m_vertexBuffer(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
NzMD2Mesh::~NzMD2Mesh()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzMD2Mesh::Create(const md2_header& header, NzInputStream& stream, const NzMeshParams& parameters)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
unsigned int startFrame = NzClamp(parameters.animation.startFrame, 0U, static_cast<unsigned int>(header.num_frames-1));
|
||||
unsigned int endFrame = NzClamp(parameters.animation.endFrame, 0U, static_cast<unsigned int>(header.num_frames-1));
|
||||
|
||||
m_frameCount = endFrame - startFrame + 1;
|
||||
m_vertexCount = header.num_tris * 3;
|
||||
|
||||
/// Chargement des vertices
|
||||
std::vector<md2_texCoord> texCoords(header.num_st);
|
||||
std::vector<md2_triangle> triangles(header.num_tris);
|
||||
|
||||
// Lecture des coordonnées de texture
|
||||
stream.SetCursorPos(header.offset_st);
|
||||
stream.Read(&texCoords[0], header.num_st*sizeof(md2_texCoord));
|
||||
|
||||
#if defined(NAZARA_BIG_ENDIAN)
|
||||
for (unsigned int i = 0; i < header.num_st; ++i)
|
||||
{
|
||||
NzByteSwap(&texCoords[i].u, sizeof(nzInt16));
|
||||
NzByteSwap(&texCoords[i].v, sizeof(nzInt16));
|
||||
}
|
||||
#endif
|
||||
|
||||
stream.SetCursorPos(header.offset_tris);
|
||||
stream.Read(&triangles[0], header.num_tris*sizeof(md2_triangle));
|
||||
|
||||
#if defined(NAZARA_BIG_ENDIAN)
|
||||
for (unsigned int i = 0; i < header.num_tris; ++i)
|
||||
{
|
||||
NzByteSwap(&triangles[i].vertices[0], sizeof(nzUInt16));
|
||||
NzByteSwap(&texCoords[i].texCoords[0], sizeof(nzUInt16));
|
||||
|
||||
NzByteSwap(&triangles[i].vertices[1], sizeof(nzUInt16));
|
||||
NzByteSwap(&texCoords[i].texCoords[1], sizeof(nzUInt16));
|
||||
|
||||
NzByteSwap(&triangles[i].vertices[2], sizeof(nzUInt16));
|
||||
NzByteSwap(&texCoords[i].texCoords[2], sizeof(nzUInt16));
|
||||
}
|
||||
#endif
|
||||
|
||||
stream.SetCursorPos(header.offset_frames + header.framesize*startFrame);
|
||||
|
||||
md2_frame frame;
|
||||
frame.vertices.resize(header.num_vertices);
|
||||
|
||||
// Pour que le modèle soit correctement aligné, on génère un quaternion que nous appliquerons à chacune des vertices
|
||||
NzQuaternionf rotationQuat = NzEulerAnglesf(-90.f, 90.f, 0.f);
|
||||
//NzMatrix4f rotationMatrix = NzMatrix4f::Rotate(NzEulerAnglesf(-90.f, -90.f, 0.f));
|
||||
|
||||
unsigned int stride = s_declaration.GetStride(nzElementStream_VertexData);
|
||||
|
||||
m_frames = new Frame[m_frameCount];
|
||||
for (unsigned int i = 0; i < m_frameCount; ++i)
|
||||
{
|
||||
stream.Read(&frame.scale, sizeof(NzVector3f));
|
||||
stream.Read(&frame.translate, sizeof(NzVector3f));
|
||||
stream.Read(&frame.name, 16*sizeof(char));
|
||||
stream.Read(&frame.vertices[0], header.num_vertices*sizeof(md2_vertex));
|
||||
|
||||
#if defined(NAZARA_BIG_ENDIAN)
|
||||
NzByteSwap(&frame.scale.x, sizeof(float));
|
||||
NzByteSwap(&frame.scale.y, sizeof(float));
|
||||
NzByteSwap(&frame.scale.z, sizeof(float));
|
||||
|
||||
NzByteSwap(&frame.translate.x, sizeof(float));
|
||||
NzByteSwap(&frame.translate.y, sizeof(float));
|
||||
NzByteSwap(&frame.translate.z, sizeof(float));
|
||||
#endif
|
||||
|
||||
m_frames[i].normal = new nzUInt8[m_vertexCount]; // Nous stockons l'indice MD2 de la normale plutôt que la normale (gain d'espace)
|
||||
m_frames[i].vertices = new NzVector3f[m_vertexCount];
|
||||
|
||||
NzVector3f max, min;
|
||||
for (unsigned int t = 0; t < header.num_tris; ++t)
|
||||
{
|
||||
for (unsigned int v = 0; v < 3; ++v)
|
||||
{
|
||||
const md2_vertex& vert = frame.vertices[triangles[t].vertices[v]];
|
||||
|
||||
NzVector3f vertex = rotationQuat * NzVector3f(vert.x * frame.scale.x + frame.translate.x, vert.y * frame.scale.y + frame.translate.y, vert.z * frame.scale.z + frame.translate.z);
|
||||
|
||||
// On fait en sorte d'avoir deux vertices de délimitation, définissant un rectangle dans l'espace
|
||||
max.Maximize(vertex);
|
||||
min.Minimize(vertex);
|
||||
|
||||
// Le MD2 ne définit pas ses vertices dans le bon ordre, il nous faut donc les ajouter dans l'ordre inverse
|
||||
unsigned int index = m_vertexCount - (t*3 + v) - 1;
|
||||
m_frames[i].normal[index] = vert.n;
|
||||
m_frames[i].vertices[index] = vertex;
|
||||
}
|
||||
}
|
||||
|
||||
m_frames[i].aabb.SetExtends(min, max);
|
||||
}
|
||||
|
||||
m_indexBuffer = nullptr; // Pas d'indexbuffer pour l'instant
|
||||
m_vertexBuffer = new NzVertexBuffer(m_vertexCount, (3+3+2)*sizeof(float), parameters.storage, nzBufferUsage_Dynamic);
|
||||
|
||||
nzUInt8* ptr = reinterpret_cast<nzUInt8*>(m_vertexBuffer->Map(nzBufferAccess_WriteOnly));
|
||||
if (!ptr)
|
||||
{
|
||||
NazaraError("Failed to map vertex buffer");
|
||||
Destroy();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// On avance jusqu'aux dernières coordonnées de texture et on les définit dans l'ordre inverse
|
||||
ptr += s_declaration.GetElement(nzElementStream_VertexData, nzElementUsage_TexCoord)->offset + stride * (m_vertexCount-1);
|
||||
for (unsigned int t = 0; t < header.num_tris; ++t)
|
||||
{
|
||||
for (unsigned int v = 0; v < 3; ++v)
|
||||
{
|
||||
const md2_texCoord& texC = texCoords[triangles[t].texCoords[v]];
|
||||
|
||||
NzVector2f* coords = reinterpret_cast<NzVector2f*>(ptr);
|
||||
coords->x = texC.u / static_cast<float>(header.skinwidth);
|
||||
coords->y = 1.f - texC.v / static_cast<float>(header.skinheight);
|
||||
|
||||
ptr -= stride;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_vertexBuffer->Unmap())
|
||||
{
|
||||
NazaraError("Failed to unmap buffer");
|
||||
Destroy();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_vertexBuffer->AddResourceReference();
|
||||
m_vertexBuffer->SetPersistent(false);
|
||||
|
||||
AnimateImpl(0, 0, 0.f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzMD2Mesh::Destroy()
|
||||
{
|
||||
if (m_frames)
|
||||
{
|
||||
for (unsigned int i = 0; i < m_frameCount; ++i)
|
||||
{
|
||||
delete[] m_frames[i].normal;
|
||||
delete[] m_frames[i].vertices;
|
||||
}
|
||||
|
||||
delete[] m_frames;
|
||||
m_frames = nullptr;
|
||||
}
|
||||
|
||||
if (m_indexBuffer)
|
||||
{
|
||||
m_indexBuffer->RemoveResourceReference();
|
||||
m_indexBuffer = nullptr;
|
||||
}
|
||||
|
||||
if (m_vertexBuffer)
|
||||
{
|
||||
m_vertexBuffer->RemoveResourceReference();
|
||||
m_vertexBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const NzAxisAlignedBox& NzMD2Mesh::GetAABB() const
|
||||
{
|
||||
return m_aabb;
|
||||
}
|
||||
|
||||
nzAnimationType NzMD2Mesh::GetAnimationType() const
|
||||
{
|
||||
if (m_frameCount > 1)
|
||||
return nzAnimationType_Keyframe;
|
||||
else
|
||||
return nzAnimationType_Static;
|
||||
}
|
||||
|
||||
unsigned int NzMD2Mesh::GetFrameCount() const
|
||||
{
|
||||
return m_frameCount;
|
||||
}
|
||||
|
||||
const NzIndexBuffer* NzMD2Mesh::GetIndexBuffer() const
|
||||
{
|
||||
return nullptr;
|
||||
//return m_indexBuffer;
|
||||
}
|
||||
|
||||
nzPrimitiveType NzMD2Mesh::GetPrimitiveType() const
|
||||
{
|
||||
return nzPrimitiveType_TriangleList;
|
||||
}
|
||||
|
||||
const NzVertexBuffer* NzMD2Mesh::GetVertexBuffer() const
|
||||
{
|
||||
return m_vertexBuffer;
|
||||
}
|
||||
|
||||
const NzVertexDeclaration* NzMD2Mesh::GetVertexDeclaration() const
|
||||
{
|
||||
return &s_declaration;
|
||||
}
|
||||
|
||||
void NzMD2Mesh::Initialize()
|
||||
{
|
||||
NzVertexElement elements[3];
|
||||
elements[0].offset = 0;
|
||||
elements[0].type = nzElementType_Float3;
|
||||
elements[0].usage = nzElementUsage_Position;
|
||||
|
||||
elements[1].offset = 3*sizeof(float);
|
||||
elements[1].type = nzElementType_Float3;
|
||||
elements[1].usage = nzElementUsage_Normal;
|
||||
|
||||
elements[2].offset = 3*sizeof(float) + 3*sizeof(float);
|
||||
elements[2].type = nzElementType_Float2;
|
||||
elements[2].usage = nzElementUsage_TexCoord;
|
||||
|
||||
s_declaration.Create(elements, 3);
|
||||
}
|
||||
|
||||
void NzMD2Mesh::Uninitialize()
|
||||
{
|
||||
s_declaration.Destroy();
|
||||
}
|
||||
|
||||
void NzMD2Mesh::AnimateImpl(unsigned int frameA, unsigned int frameB, float interpolation)
|
||||
{
|
||||
nzUInt8* ptr = reinterpret_cast<nzUInt8*>(m_vertexBuffer->Map(nzBufferAccess_WriteOnly));
|
||||
if (!ptr)
|
||||
{
|
||||
NazaraError("Failed to map vertex buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int stride = s_declaration.GetStride(nzElementStream_VertexData);
|
||||
unsigned int positionOffset = s_declaration.GetElement(nzElementStream_VertexData, nzElementUsage_Position)->offset;
|
||||
unsigned int normalOffset = s_declaration.GetElement(nzElementStream_VertexData, nzElementUsage_Normal)->offset;
|
||||
|
||||
Frame* fA = &m_frames[frameA];
|
||||
Frame* fB = &m_frames[frameB];
|
||||
for (unsigned int i = 0; i < m_vertexCount; ++i)
|
||||
{
|
||||
NzVector3f* position = reinterpret_cast<NzVector3f*>(ptr + positionOffset);
|
||||
NzVector3f* normal = reinterpret_cast<NzVector3f*>(ptr + normalOffset);
|
||||
|
||||
*position = fA->vertices[i] + interpolation * (fB->vertices[i] - fA->vertices[i]);
|
||||
*normal = md2Normals[fA->normal[i]] + interpolation * (md2Normals[fB->normal[i]] - md2Normals[fA->normal[i]]);
|
||||
|
||||
ptr += stride;
|
||||
}
|
||||
|
||||
if (!m_vertexBuffer->Unmap())
|
||||
NazaraWarning("Failed to unmap vertex buffer, expect mesh corruption");
|
||||
|
||||
// Interpolation de l'AABB
|
||||
NzVector3f max1 = fA->aabb.GetMaximum();
|
||||
NzVector3f min1 = fA->aabb.GetMinimum();
|
||||
m_aabb.SetExtends(min1 + interpolation * (fB->aabb.GetMinimum() - min1), max1 + interpolation * (fB->aabb.GetMaximum() - max1));
|
||||
}
|
||||
|
||||
NzVertexDeclaration NzMD2Mesh::s_declaration;
|
||||
|
||||
@@ -1,352 +1,346 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Loaders/PCX.hpp>
|
||||
#include <Nazara/Core/Endianness.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Core/InputStream.hpp>
|
||||
#include <Nazara/Core/MemoryStream.hpp>
|
||||
#include <Nazara/Utility/Image.hpp>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
// Auteur du loader original : David Henry
|
||||
|
||||
namespace
|
||||
{
|
||||
struct pcx_header
|
||||
{
|
||||
nzUInt8 manufacturer;
|
||||
nzUInt8 version;
|
||||
nzUInt8 encoding;
|
||||
nzUInt8 bitsPerPixel;
|
||||
|
||||
nzUInt16 xmin, ymin;
|
||||
nzUInt16 xmax, ymax;
|
||||
nzUInt16 horzRes, vertRes;
|
||||
|
||||
nzUInt8 palette[48];
|
||||
nzUInt8 reserved;
|
||||
nzUInt8 numColorPlanes;
|
||||
|
||||
nzUInt16 bytesPerScanLine;
|
||||
nzUInt16 paletteType;
|
||||
nzUInt16 horzSize, vertSize;
|
||||
|
||||
nzUInt8 padding[54];
|
||||
};
|
||||
|
||||
bool NzLoader_PCX_Check(NzInputStream& stream, const NzImageParams& parameters)
|
||||
{
|
||||
NazaraUnused(parameters);
|
||||
|
||||
nzUInt8 manufacturer;
|
||||
if (stream.Read(&manufacturer, 1) != 1)
|
||||
return false;
|
||||
|
||||
return manufacturer == 0x0a;
|
||||
}
|
||||
|
||||
bool NzLoader_PCX_Load(NzImage* image, NzInputStream& stream, const NzImageParams& parameters)
|
||||
{
|
||||
NazaraUnused(parameters);
|
||||
|
||||
pcx_header header;
|
||||
if (stream.Read(&header, sizeof(pcx_header)) != sizeof(pcx_header))
|
||||
{
|
||||
NazaraError("Failed to read header");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.manufacturer != 0x0a)
|
||||
{
|
||||
NazaraError("Bad version number (" + NzString::Number(header.manufacturer) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(NAZARA_BIG_ENDIAN)
|
||||
// Les fichiers PCX sont en little endian
|
||||
NzByteSwap(&header.xmin, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.ymin, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.xmax, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.ymax, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.horzRes, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.vertRes, sizeof(nzUInt16));
|
||||
|
||||
NzByteSwap(&header.bytesPerScanLine, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.paletteType, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.horzSize, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.vertSize, sizeof(nzUInt16));
|
||||
#endif
|
||||
|
||||
unsigned int bitCount = header.bitsPerPixel * header.numColorPlanes;
|
||||
unsigned int width = header.xmax - header.xmin+1;
|
||||
unsigned int height = header.ymax - header.ymin+1;
|
||||
|
||||
if (!image->Create(nzImageType_2D, nzPixelFormat_RGB8, width, height, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1))
|
||||
{
|
||||
NazaraError("Failed to create image");
|
||||
return false;
|
||||
}
|
||||
|
||||
nzUInt8* pixels = image->GetPixels();
|
||||
|
||||
int rle_value = 0;
|
||||
unsigned int rle_count = 0;
|
||||
|
||||
switch (bitCount)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
nzUInt8* ptr = &pixels[y * width * 3];
|
||||
int bytes = header.bytesPerScanLine;
|
||||
|
||||
/* decode line number y */
|
||||
while (bytes--)
|
||||
{
|
||||
if (rle_count == 0)
|
||||
{
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rle_value < 0xc0)
|
||||
rle_count = 1;
|
||||
else
|
||||
{
|
||||
rle_count = rle_value - 0xc0;
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rle_count--;
|
||||
|
||||
for (int i = 7; i >= 0; --i)
|
||||
{
|
||||
int colorIndex = ((rle_value & (1 << i)) > 0);
|
||||
|
||||
*ptr++ = header.palette[colorIndex * 3 + 0];
|
||||
*ptr++ = header.palette[colorIndex * 3 + 1];
|
||||
*ptr++ = header.palette[colorIndex * 3 + 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
nzUInt8* colorIndex = new nzUInt8[width];
|
||||
nzUInt8* line = new nzUInt8[header.bytesPerScanLine];
|
||||
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
nzUInt8* ptr = &pixels[y * width * 3];
|
||||
|
||||
std::memset(colorIndex, 0, width);
|
||||
|
||||
for (unsigned int c = 0; c < 4; ++c)
|
||||
{
|
||||
nzUInt8* pLine = line;
|
||||
int bytes = header.bytesPerScanLine;
|
||||
|
||||
/* decode line number y */
|
||||
while (bytes--)
|
||||
{
|
||||
if (rle_count == 0)
|
||||
{
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
delete[] colorIndex;
|
||||
delete[] line;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rle_value < 0xc0)
|
||||
rle_count = 1;
|
||||
else
|
||||
{
|
||||
rle_count = rle_value - 0xc0;
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
delete[] colorIndex;
|
||||
delete[] line;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rle_count--;
|
||||
*(pLine++) = rle_value;
|
||||
}
|
||||
|
||||
/* compute line's color indexes */
|
||||
for (unsigned int x = 0; x < width; ++x)
|
||||
{
|
||||
if (line[x / 8] & (128 >> (x % 8)))
|
||||
colorIndex[x] += (1 << c);
|
||||
}
|
||||
}
|
||||
|
||||
/* decode scan line. color index => rgb */
|
||||
for (unsigned int x = 0; x < width; ++x)
|
||||
{
|
||||
*ptr++ = header.palette[colorIndex[x] * 3 + 0];
|
||||
*ptr++ = header.palette[colorIndex[x] * 3 + 1];
|
||||
*ptr++ = header.palette[colorIndex[x] * 3 + 2];
|
||||
}
|
||||
}
|
||||
|
||||
/* release memory */
|
||||
delete[] colorIndex;
|
||||
delete[] line;
|
||||
break;
|
||||
}
|
||||
|
||||
case 8:
|
||||
{
|
||||
nzUInt8 palette[768];
|
||||
|
||||
/* the palette is contained in the last 769 bytes of the file */
|
||||
unsigned int curPos = stream.GetCursorPos();
|
||||
stream.SetCursorPos(stream.GetSize()-769);
|
||||
nzUInt8 magic;
|
||||
if (!stream.Read(&magic, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
/* first byte must be equal to 0x0c (12) */
|
||||
if (magic != 0x0c)
|
||||
{
|
||||
NazaraError("Colormap's first byte must be 0x0c (0x" + NzString::Number(magic, 16) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
/* read palette */
|
||||
if (stream.Read(palette, 768) != 768)
|
||||
{
|
||||
NazaraError("Failed to read palette");
|
||||
return false;
|
||||
}
|
||||
|
||||
stream.SetCursorPos(curPos);
|
||||
|
||||
/* read pixel data */
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
nzUInt8* ptr = &pixels[y * width * 3];
|
||||
int bytes = header.bytesPerScanLine;
|
||||
|
||||
/* decode line number y */
|
||||
while (bytes--)
|
||||
{
|
||||
if (rle_count == 0)
|
||||
{
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rle_value < 0xc0)
|
||||
rle_count = 1;
|
||||
else
|
||||
{
|
||||
rle_count = rle_value - 0xc0;
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rle_count--;
|
||||
|
||||
*ptr++ = palette[rle_value * 3 + 0];
|
||||
*ptr++ = palette[rle_value * 3 + 1];
|
||||
*ptr++ = palette[rle_value * 3 + 2];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 24:
|
||||
{
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
/* for each color plane */
|
||||
for (int c = 0; c < 3; ++c)
|
||||
{
|
||||
nzUInt8* ptr = &pixels[y * width * 4];
|
||||
int bytes = header.bytesPerScanLine;
|
||||
|
||||
/* decode line number y */
|
||||
while (bytes--)
|
||||
{
|
||||
if (rle_count == 0)
|
||||
{
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rle_value < 0xc0)
|
||||
rle_count = 1;
|
||||
else
|
||||
{
|
||||
rle_count = rle_value - 0xc0;
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rle_count--;
|
||||
ptr[c] = static_cast<nzUInt8>(rle_value);
|
||||
ptr += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
NazaraError("Failed to load " + NzString::Number(bitCount) + " bitcount pcx files");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parameters.loadFormat != nzPixelFormat_Undefined)
|
||||
image->Convert(parameters.loadFormat);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void NzLoaders_PCX_Register()
|
||||
{
|
||||
NzImageLoader::RegisterLoader("pcx", NzLoader_PCX_Check, NzLoader_PCX_Load);
|
||||
}
|
||||
|
||||
void NzLoaders_PCX_Unregister()
|
||||
{
|
||||
NzImageLoader::UnregisterLoader("pcx", NzLoader_PCX_Check, NzLoader_PCX_Load);
|
||||
}
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/Loaders/PCX.hpp>
|
||||
#include <Nazara/Core/Endianness.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Core/InputStream.hpp>
|
||||
#include <Nazara/Core/MemoryStream.hpp>
|
||||
#include <Nazara/Utility/Image.hpp>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
// Auteur du loader original : David Henry
|
||||
|
||||
namespace
|
||||
{
|
||||
struct pcx_header
|
||||
{
|
||||
nzUInt8 manufacturer;
|
||||
nzUInt8 version;
|
||||
nzUInt8 encoding;
|
||||
nzUInt8 bitsPerPixel;
|
||||
|
||||
nzUInt16 xmin, ymin;
|
||||
nzUInt16 xmax, ymax;
|
||||
nzUInt16 horzRes, vertRes;
|
||||
|
||||
nzUInt8 palette[48];
|
||||
nzUInt8 reserved;
|
||||
nzUInt8 numColorPlanes;
|
||||
|
||||
nzUInt16 bytesPerScanLine;
|
||||
nzUInt16 paletteType;
|
||||
nzUInt16 horzSize, vertSize;
|
||||
|
||||
nzUInt8 padding[54];
|
||||
};
|
||||
|
||||
bool NzLoader_PCX_Check(NzInputStream& stream, const NzImageParams& parameters)
|
||||
{
|
||||
NazaraUnused(parameters);
|
||||
|
||||
nzUInt8 manufacturer;
|
||||
if (stream.Read(&manufacturer, 1) != 1)
|
||||
return false;
|
||||
|
||||
return manufacturer == 0x0a;
|
||||
}
|
||||
|
||||
bool NzLoader_PCX_Load(NzImage* image, NzInputStream& stream, const NzImageParams& parameters)
|
||||
{
|
||||
NazaraUnused(parameters);
|
||||
|
||||
pcx_header header;
|
||||
if (stream.Read(&header, sizeof(pcx_header)) != sizeof(pcx_header))
|
||||
{
|
||||
NazaraError("Failed to read header");
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(NAZARA_BIG_ENDIAN)
|
||||
// Les fichiers PCX sont en little endian
|
||||
NzByteSwap(&header.xmin, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.ymin, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.xmax, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.ymax, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.horzRes, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.vertRes, sizeof(nzUInt16));
|
||||
|
||||
NzByteSwap(&header.bytesPerScanLine, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.paletteType, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.horzSize, sizeof(nzUInt16));
|
||||
NzByteSwap(&header.vertSize, sizeof(nzUInt16));
|
||||
#endif
|
||||
|
||||
unsigned int bitCount = header.bitsPerPixel * header.numColorPlanes;
|
||||
unsigned int width = header.xmax - header.xmin+1;
|
||||
unsigned int height = header.ymax - header.ymin+1;
|
||||
|
||||
if (!image->Create(nzImageType_2D, nzPixelFormat_RGB8, width, height, 1, (parameters.levelCount > 0) ? parameters.levelCount : 1))
|
||||
{
|
||||
NazaraError("Failed to create image");
|
||||
return false;
|
||||
}
|
||||
|
||||
nzUInt8* pixels = image->GetPixels();
|
||||
|
||||
int rle_value = 0;
|
||||
unsigned int rle_count = 0;
|
||||
|
||||
switch (bitCount)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
nzUInt8* ptr = &pixels[y * width * 3];
|
||||
int bytes = header.bytesPerScanLine;
|
||||
|
||||
/* decode line number y */
|
||||
while (bytes--)
|
||||
{
|
||||
if (rle_count == 0)
|
||||
{
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rle_value < 0xc0)
|
||||
rle_count = 1;
|
||||
else
|
||||
{
|
||||
rle_count = rle_value - 0xc0;
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rle_count--;
|
||||
|
||||
for (int i = 7; i >= 0; --i)
|
||||
{
|
||||
int colorIndex = ((rle_value & (1 << i)) > 0);
|
||||
|
||||
*ptr++ = header.palette[colorIndex * 3 + 0];
|
||||
*ptr++ = header.palette[colorIndex * 3 + 1];
|
||||
*ptr++ = header.palette[colorIndex * 3 + 2];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
nzUInt8* colorIndex = new nzUInt8[width];
|
||||
nzUInt8* line = new nzUInt8[header.bytesPerScanLine];
|
||||
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
nzUInt8* ptr = &pixels[y * width * 3];
|
||||
|
||||
std::memset(colorIndex, 0, width);
|
||||
|
||||
for (unsigned int c = 0; c < 4; ++c)
|
||||
{
|
||||
nzUInt8* pLine = line;
|
||||
int bytes = header.bytesPerScanLine;
|
||||
|
||||
/* decode line number y */
|
||||
while (bytes--)
|
||||
{
|
||||
if (rle_count == 0)
|
||||
{
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
delete[] colorIndex;
|
||||
delete[] line;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rle_value < 0xc0)
|
||||
rle_count = 1;
|
||||
else
|
||||
{
|
||||
rle_count = rle_value - 0xc0;
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
delete[] colorIndex;
|
||||
delete[] line;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rle_count--;
|
||||
*(pLine++) = rle_value;
|
||||
}
|
||||
|
||||
/* compute line's color indexes */
|
||||
for (unsigned int x = 0; x < width; ++x)
|
||||
{
|
||||
if (line[x / 8] & (128 >> (x % 8)))
|
||||
colorIndex[x] += (1 << c);
|
||||
}
|
||||
}
|
||||
|
||||
/* decode scan line. color index => rgb */
|
||||
for (unsigned int x = 0; x < width; ++x)
|
||||
{
|
||||
*ptr++ = header.palette[colorIndex[x] * 3 + 0];
|
||||
*ptr++ = header.palette[colorIndex[x] * 3 + 1];
|
||||
*ptr++ = header.palette[colorIndex[x] * 3 + 2];
|
||||
}
|
||||
}
|
||||
|
||||
/* release memory */
|
||||
delete[] colorIndex;
|
||||
delete[] line;
|
||||
break;
|
||||
}
|
||||
|
||||
case 8:
|
||||
{
|
||||
nzUInt8 palette[768];
|
||||
|
||||
/* the palette is contained in the last 769 bytes of the file */
|
||||
unsigned int curPos = stream.GetCursorPos();
|
||||
stream.SetCursorPos(stream.GetSize()-769);
|
||||
nzUInt8 magic;
|
||||
if (!stream.Read(&magic, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
/* first byte must be equal to 0x0c (12) */
|
||||
if (magic != 0x0c)
|
||||
{
|
||||
NazaraError("Colormap's first byte must be 0x0c (0x" + NzString::Number(magic, 16) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
/* read palette */
|
||||
if (stream.Read(palette, 768) != 768)
|
||||
{
|
||||
NazaraError("Failed to read palette");
|
||||
return false;
|
||||
}
|
||||
|
||||
stream.SetCursorPos(curPos);
|
||||
|
||||
/* read pixel data */
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
nzUInt8* ptr = &pixels[y * width * 3];
|
||||
int bytes = header.bytesPerScanLine;
|
||||
|
||||
/* decode line number y */
|
||||
while (bytes--)
|
||||
{
|
||||
if (rle_count == 0)
|
||||
{
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rle_value < 0xc0)
|
||||
rle_count = 1;
|
||||
else
|
||||
{
|
||||
rle_count = rle_value - 0xc0;
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rle_count--;
|
||||
|
||||
*ptr++ = palette[rle_value * 3 + 0];
|
||||
*ptr++ = palette[rle_value * 3 + 1];
|
||||
*ptr++ = palette[rle_value * 3 + 2];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 24:
|
||||
{
|
||||
for (unsigned int y = 0; y < height; ++y)
|
||||
{
|
||||
/* for each color plane */
|
||||
for (int c = 0; c < 3; ++c)
|
||||
{
|
||||
nzUInt8* ptr = &pixels[y * width * 4];
|
||||
int bytes = header.bytesPerScanLine;
|
||||
|
||||
/* decode line number y */
|
||||
while (bytes--)
|
||||
{
|
||||
if (rle_count == 0)
|
||||
{
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (rle_value < 0xc0)
|
||||
rle_count = 1;
|
||||
else
|
||||
{
|
||||
rle_count = rle_value - 0xc0;
|
||||
if (!stream.Read(&rle_value, 1))
|
||||
{
|
||||
NazaraError("Failed to read stream (byte " + NzString::Number(stream.GetCursorPos()) + ')');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rle_count--;
|
||||
ptr[c] = static_cast<nzUInt8>(rle_value);
|
||||
ptr += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
NazaraError("Failed to load " + NzString::Number(bitCount) + " bitcount pcx files");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parameters.loadFormat != nzPixelFormat_Undefined)
|
||||
image->Convert(parameters.loadFormat);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void NzLoaders_PCX_Register()
|
||||
{
|
||||
NzImageLoader::RegisterLoader("pcx", NzLoader_PCX_Check, NzLoader_PCX_Load);
|
||||
}
|
||||
|
||||
void NzLoaders_PCX_Unregister()
|
||||
{
|
||||
NzImageLoader::UnregisterLoader("pcx", NzLoader_PCX_Check, NzLoader_PCX_Load);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,186 +1,199 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/StaticMesh.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
NzStaticMesh::NzStaticMesh(const NzMesh* parent) :
|
||||
NzSubMesh(parent)
|
||||
{
|
||||
}
|
||||
|
||||
NzStaticMesh::NzStaticMesh(const NzMesh* parent, const NzVertexDeclaration* vertexDeclaration, NzVertexBuffer* vertexBuffer, NzIndexBuffer* indexBuffer) :
|
||||
NzSubMesh(parent)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!Create(vertexDeclaration, vertexBuffer, indexBuffer))
|
||||
{
|
||||
NazaraError("Failed to create mesh");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#else
|
||||
Create(vertexDeclaration, vertexBuffer, indexBuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
NzStaticMesh::~NzStaticMesh()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzStaticMesh::Create(const NzVertexDeclaration* vertexDeclaration, NzVertexBuffer* vertexBuffer, NzIndexBuffer* indexBuffer)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!vertexDeclaration)
|
||||
{
|
||||
NazaraError("Vertex declaration is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vertexBuffer)
|
||||
{
|
||||
NazaraError("Vertex buffer is null");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (indexBuffer)
|
||||
{
|
||||
m_indexBuffer = indexBuffer;
|
||||
m_indexBuffer->AddResourceReference();
|
||||
}
|
||||
|
||||
m_vertexBuffer = vertexBuffer;
|
||||
m_vertexBuffer->AddResourceReference();
|
||||
|
||||
m_vertexDeclaration = vertexDeclaration;
|
||||
m_vertexDeclaration->AddResourceReference();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzStaticMesh::Destroy()
|
||||
{
|
||||
m_aabb.SetNull();
|
||||
|
||||
if (m_indexBuffer)
|
||||
{
|
||||
m_indexBuffer->RemoveResourceReference();
|
||||
m_indexBuffer = nullptr;
|
||||
}
|
||||
|
||||
if (m_vertexBuffer)
|
||||
{
|
||||
m_vertexBuffer->RemoveResourceReference();
|
||||
m_vertexBuffer = nullptr;
|
||||
}
|
||||
|
||||
if (m_vertexDeclaration)
|
||||
{
|
||||
m_vertexDeclaration->RemoveResourceReference();
|
||||
m_vertexDeclaration = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool NzStaticMesh::GenerateAABB()
|
||||
{
|
||||
if (!m_aabb.IsNull())
|
||||
return true;
|
||||
|
||||
const NzVertexElement* position = m_vertexDeclaration->GetElement(nzElementStream_VertexData, nzElementUsage_Position);
|
||||
if (position && position->type == nzElementType_Float3) // Si nous avons des positions du type Vec3
|
||||
{
|
||||
// On lock le buffer pour itérer sur toutes les positions et composer notre AABB
|
||||
nzUInt8* buffer = reinterpret_cast<nzUInt8*>(m_vertexBuffer->Map(nzBufferAccess_ReadOnly));
|
||||
if (!buffer)
|
||||
{
|
||||
NazaraWarning("Failed to lock vertex buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer += position->offset;
|
||||
unsigned int stride = m_vertexDeclaration->GetStride(nzElementStream_VertexData);
|
||||
unsigned int vertexCount = m_vertexBuffer->GetVertexCount();
|
||||
for (unsigned int i = 0; i < vertexCount; ++i)
|
||||
{
|
||||
m_aabb.ExtendTo(*reinterpret_cast<NzVector3f*>(buffer));
|
||||
|
||||
buffer += stride;
|
||||
}
|
||||
|
||||
if (!m_vertexBuffer->Unmap())
|
||||
NazaraWarning("Failed to unmap vertex buffer");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const NzAxisAlignedBox& NzStaticMesh::GetAABB() const
|
||||
{
|
||||
return m_aabb;
|
||||
}
|
||||
|
||||
nzAnimationType NzStaticMesh::GetAnimationType() const
|
||||
{
|
||||
return nzAnimationType_Static;
|
||||
}
|
||||
|
||||
unsigned int NzStaticMesh::GetFrameCount() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const NzIndexBuffer* NzStaticMesh::GetIndexBuffer() const
|
||||
{
|
||||
return m_indexBuffer;
|
||||
}
|
||||
|
||||
nzPrimitiveType NzStaticMesh::GetPrimitiveType() const
|
||||
{
|
||||
return m_primitiveType;
|
||||
}
|
||||
|
||||
const NzVertexBuffer* NzStaticMesh::GetVertexBuffer() const
|
||||
{
|
||||
return m_vertexBuffer;
|
||||
}
|
||||
|
||||
const NzVertexDeclaration* NzStaticMesh::GetVertexDeclaration() const
|
||||
{
|
||||
return m_vertexDeclaration;
|
||||
}
|
||||
|
||||
bool NzStaticMesh::IsAnimated() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NzStaticMesh::IsValid() const
|
||||
{
|
||||
return m_vertexBuffer != nullptr && m_vertexDeclaration != nullptr;
|
||||
}
|
||||
|
||||
void NzStaticMesh::SetAABB(const NzAxisAlignedBox& aabb)
|
||||
{
|
||||
m_aabb = aabb;
|
||||
}
|
||||
|
||||
void NzStaticMesh::SetPrimitiveType(nzPrimitiveType primitiveType)
|
||||
{
|
||||
m_primitiveType = primitiveType;
|
||||
}
|
||||
|
||||
void NzStaticMesh::AnimateImpl(unsigned int frameA, unsigned int frameB, float interpolation)
|
||||
{
|
||||
NazaraUnused(frameA);
|
||||
NazaraUnused(frameB);
|
||||
NazaraUnused(interpolation);
|
||||
|
||||
// Le safe mode est censé nous protéger de cet appel
|
||||
NazaraError("Static mesh have no animation, please enable safe mode");
|
||||
}
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/StaticMesh.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <stdexcept>
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
NzStaticMesh::NzStaticMesh(const NzMesh* parent) :
|
||||
NzSubMesh(parent)
|
||||
{
|
||||
}
|
||||
|
||||
NzStaticMesh::NzStaticMesh(const NzMesh* parent, const NzVertexDeclaration* vertexDeclaration, NzVertexBuffer* vertexBuffer, NzIndexBuffer* indexBuffer) :
|
||||
NzSubMesh(parent)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!Create(vertexDeclaration, vertexBuffer, indexBuffer))
|
||||
{
|
||||
NazaraError("Failed to create mesh");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#else
|
||||
Create(vertexDeclaration, vertexBuffer, indexBuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
NzStaticMesh::~NzStaticMesh()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzStaticMesh::Create(const NzVertexDeclaration* vertexDeclaration, NzVertexBuffer* vertexBuffer, NzIndexBuffer* indexBuffer)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!vertexDeclaration)
|
||||
{
|
||||
NazaraError("Invalid vertex declaration");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vertexBuffer)
|
||||
{
|
||||
NazaraError("Invalid vertex buffer");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (indexBuffer)
|
||||
indexBuffer->AddResourceListener(this);
|
||||
|
||||
m_indexBuffer = indexBuffer;
|
||||
|
||||
m_vertexBuffer = vertexBuffer;
|
||||
m_vertexBuffer->AddResourceListener(this);
|
||||
|
||||
m_vertexDeclaration = vertexDeclaration;
|
||||
m_vertexDeclaration->AddResourceListener(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzStaticMesh::Destroy()
|
||||
{
|
||||
m_aabb.SetNull();
|
||||
|
||||
if (m_indexBuffer)
|
||||
{
|
||||
m_indexBuffer->RemoveResourceListener(this);
|
||||
m_indexBuffer = nullptr;
|
||||
}
|
||||
|
||||
if (m_vertexBuffer)
|
||||
{
|
||||
m_vertexBuffer->RemoveResourceListener(this);
|
||||
m_vertexBuffer = nullptr;
|
||||
}
|
||||
|
||||
if (m_vertexDeclaration)
|
||||
{
|
||||
m_vertexDeclaration->RemoveResourceListener(this);
|
||||
m_vertexDeclaration = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool NzStaticMesh::GenerateAABB()
|
||||
{
|
||||
if (!m_aabb.IsNull())
|
||||
return true;
|
||||
|
||||
const NzVertexElement* position = m_vertexDeclaration->GetElement(nzElementStream_VertexData, nzElementUsage_Position);
|
||||
if (position && position->type == nzElementType_Float3) // Si nous avons des positions du type Vec3
|
||||
{
|
||||
// On lock le buffer pour itérer sur toutes les positions et composer notre AABB
|
||||
nzUInt8* buffer = reinterpret_cast<nzUInt8*>(m_vertexBuffer->Map(nzBufferAccess_ReadOnly));
|
||||
if (!buffer)
|
||||
{
|
||||
NazaraWarning("Failed to lock vertex buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer += position->offset;
|
||||
unsigned int stride = m_vertexDeclaration->GetStride(nzElementStream_VertexData);
|
||||
unsigned int vertexCount = m_vertexBuffer->GetVertexCount();
|
||||
for (unsigned int i = 0; i < vertexCount; ++i)
|
||||
{
|
||||
m_aabb.ExtendTo(*reinterpret_cast<NzVector3f*>(buffer));
|
||||
|
||||
buffer += stride;
|
||||
}
|
||||
|
||||
if (!m_vertexBuffer->Unmap())
|
||||
NazaraWarning("Failed to unmap vertex buffer");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const NzAxisAlignedBox& NzStaticMesh::GetAABB() const
|
||||
{
|
||||
return m_aabb;
|
||||
}
|
||||
|
||||
nzAnimationType NzStaticMesh::GetAnimationType() const
|
||||
{
|
||||
return nzAnimationType_Static;
|
||||
}
|
||||
|
||||
unsigned int NzStaticMesh::GetFrameCount() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const NzIndexBuffer* NzStaticMesh::GetIndexBuffer() const
|
||||
{
|
||||
return m_indexBuffer;
|
||||
}
|
||||
|
||||
nzPrimitiveType NzStaticMesh::GetPrimitiveType() const
|
||||
{
|
||||
return m_primitiveType;
|
||||
}
|
||||
|
||||
const NzVertexBuffer* NzStaticMesh::GetVertexBuffer() const
|
||||
{
|
||||
return m_vertexBuffer;
|
||||
}
|
||||
|
||||
const NzVertexDeclaration* NzStaticMesh::GetVertexDeclaration() const
|
||||
{
|
||||
return m_vertexDeclaration;
|
||||
}
|
||||
|
||||
bool NzStaticMesh::IsAnimated() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NzStaticMesh::IsValid() const
|
||||
{
|
||||
return m_vertexBuffer != nullptr && m_vertexDeclaration != nullptr;
|
||||
}
|
||||
|
||||
void NzStaticMesh::SetAABB(const NzAxisAlignedBox& aabb)
|
||||
{
|
||||
m_aabb = aabb;
|
||||
}
|
||||
|
||||
void NzStaticMesh::SetPrimitiveType(nzPrimitiveType primitiveType)
|
||||
{
|
||||
m_primitiveType = primitiveType;
|
||||
}
|
||||
|
||||
void NzStaticMesh::AnimateImpl(unsigned int frameA, unsigned int frameB, float interpolation)
|
||||
{
|
||||
NazaraUnused(frameA);
|
||||
NazaraUnused(frameB);
|
||||
NazaraUnused(interpolation);
|
||||
|
||||
// Le safe mode est censé nous protéger de cet appel
|
||||
NazaraError("Static mesh have no animation, please enable safe mode");
|
||||
}
|
||||
|
||||
void NzStaticMesh::OnResourceReleased(const NzResource* resource, int index)
|
||||
{
|
||||
NazaraUnused(index);
|
||||
|
||||
if (resource == m_indexBuffer)
|
||||
m_indexBuffer = nullptr;
|
||||
else if (resource == m_vertexBuffer)
|
||||
m_vertexBuffer = nullptr;
|
||||
else if (resource == m_vertexDeclaration)
|
||||
m_vertexDeclaration = nullptr;
|
||||
else
|
||||
NazaraInternalError("Not listening to " + NzString::Pointer(resource));
|
||||
}
|
||||
|
||||
@@ -1,346 +1,372 @@
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/VertexDeclaration.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Utility/Config.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#if NAZARA_UTILITY_THREADSAFE && NAZARA_THREADSAFETY_VERTEXDECLARATION
|
||||
#include <Nazara/Core/ThreadSafety.hpp>
|
||||
#else
|
||||
#include <Nazara/Core/ThreadSafetyOff.hpp>
|
||||
#endif
|
||||
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
const unsigned int size[] =
|
||||
{
|
||||
sizeof(nzUInt32), // nzElementType_Color
|
||||
1*sizeof(double), // nzElementType_Double1
|
||||
2*sizeof(double), // nzElementType_Double2
|
||||
3*sizeof(double), // nzElementType_Double3
|
||||
4*sizeof(double), // nzElementType_Double4
|
||||
1*sizeof(float), // nzElementType_Float1
|
||||
2*sizeof(float), // nzElementType_Float2
|
||||
3*sizeof(float), // nzElementType_Float3
|
||||
4*sizeof(float) // nzElementType_Float4
|
||||
};
|
||||
|
||||
bool VertexElementCompare(const NzVertexElement& elementA, const NzVertexElement& elementB)
|
||||
{
|
||||
// Nous classons d'abord par stream
|
||||
if (elementA.stream == elementB.stream)
|
||||
{
|
||||
// Ensuite par usage
|
||||
if (elementA.usage == elementB.usage)
|
||||
// Et finalement par usageIndex
|
||||
return elementA.usageIndex < elementB.usageIndex;
|
||||
else
|
||||
return elementA.usage < elementB.usage;
|
||||
}
|
||||
else
|
||||
return elementA.stream < elementB.stream;
|
||||
}
|
||||
}
|
||||
|
||||
struct NzVertexDeclarationImpl
|
||||
{
|
||||
std::vector<NzVertexElement> elements;
|
||||
int elementPos[nzElementStream_Max+1][nzElementUsage_Max+1];
|
||||
int streamPos[nzElementStream_Max+1];
|
||||
unsigned int stride[nzElementStream_Max+1] = {0};
|
||||
|
||||
unsigned short refCount = 1;
|
||||
NazaraMutex(mutex)
|
||||
};
|
||||
|
||||
NzVertexDeclaration::NzVertexDeclaration(const NzVertexElement* elements, unsigned int elementCount)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!Create(elements, elementCount))
|
||||
{
|
||||
NazaraError("Failed to create declaration");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#else
|
||||
Create(elements, elementCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
NzVertexDeclaration::NzVertexDeclaration(const NzVertexDeclaration& declaration) :
|
||||
NzResource(),
|
||||
m_sharedImpl(declaration.m_sharedImpl)
|
||||
{
|
||||
if (m_sharedImpl)
|
||||
{
|
||||
NazaraMutexLock(m_sharedImpl->mutex);
|
||||
m_sharedImpl->refCount++;
|
||||
NazaraMutexUnlock(m_sharedImpl->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
NzVertexDeclaration::NzVertexDeclaration(NzVertexDeclaration&& declaration) noexcept :
|
||||
m_sharedImpl(declaration.m_sharedImpl)
|
||||
{
|
||||
declaration.m_sharedImpl = nullptr;
|
||||
}
|
||||
|
||||
NzVertexDeclaration::~NzVertexDeclaration()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzVertexDeclaration::Create(const NzVertexElement* elements, unsigned int elementCount)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!elements || elementCount == 0)
|
||||
{
|
||||
NazaraError("No element");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
NzVertexDeclarationImpl* impl = new NzVertexDeclarationImpl;
|
||||
std::memset(&impl->elementPos, -1, (nzElementStream_Max+1)*(nzElementUsage_Max+1)*sizeof(int));
|
||||
std::memset(&impl->streamPos, -1, (nzElementStream_Max+1)*sizeof(int));
|
||||
|
||||
// On copie et trie les éléments
|
||||
impl->elements.resize(elementCount);
|
||||
std::memcpy(&impl->elements[0], elements, elementCount*sizeof(NzVertexElement));
|
||||
std::sort(impl->elements.begin(), impl->elements.end(), VertexElementCompare);
|
||||
|
||||
for (unsigned int i = 0; i < elementCount; ++i)
|
||||
{
|
||||
NzVertexElement& current = impl->elements[i];
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
// Notre tableau étant trié, s'il y a collision, les deux éléments identiques se suivent...
|
||||
if (i > 0)
|
||||
{
|
||||
NzVertexElement& previous = impl->elements[i-1]; // On accède à l'élément précédent
|
||||
if (previous.usage == current.usage && previous.usageIndex == current.usageIndex && previous.stream == current.stream)
|
||||
{
|
||||
// Les deux éléments sont identiques là où ils ne devraient pas, nous avons une collision...
|
||||
NazaraError("Element usage 0x" + NzString::Number(current.usage, 16) + " collision with usage index " + NzString::Number(current.usageIndex) + " on stream 0x" + NzString::Number(current.stream, 16));
|
||||
delete impl;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (current.usageIndex == 0)
|
||||
impl->elementPos[current.stream][current.usage] = i;
|
||||
|
||||
if (impl->streamPos[current.stream] == -1)
|
||||
impl->streamPos[current.stream] = i; // Premier élément du stream (via le triage)
|
||||
|
||||
impl->stride[current.stream] += size[current.type];
|
||||
}
|
||||
|
||||
#if NAZARA_UTILITY_FORCE_DECLARATION_STRIDE_MULTIPLE_OF_32
|
||||
for (unsigned int& stride : impl->stride)
|
||||
stride = ((static_cast<int>(stride)-1)/32+1)*32;
|
||||
#endif
|
||||
|
||||
m_sharedImpl = impl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzVertexDeclaration::Destroy()
|
||||
{
|
||||
if (!m_sharedImpl)
|
||||
return;
|
||||
|
||||
NazaraMutexLock(m_sharedImpl->mutex);
|
||||
bool freeSharedImpl = (--m_sharedImpl->refCount == 0);
|
||||
NazaraMutexUnlock(m_sharedImpl->mutex);
|
||||
|
||||
if (freeSharedImpl)
|
||||
delete m_sharedImpl;
|
||||
|
||||
m_sharedImpl = nullptr;
|
||||
}
|
||||
|
||||
const NzVertexElement* NzVertexDeclaration::GetElement(unsigned int i) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Declaration not created");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (i >= m_sharedImpl->elements.size())
|
||||
{
|
||||
NazaraError("Element index out of range (" + NzString::Number(i) + " >= " + NzString::Number(m_sharedImpl->elements.size()) + ')');
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return &m_sharedImpl->elements[i];
|
||||
}
|
||||
|
||||
const NzVertexElement* NzVertexDeclaration::GetElement(nzElementStream stream, unsigned int i) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Declaration not created");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int streamPos = m_sharedImpl->streamPos[stream];
|
||||
if (streamPos == -1)
|
||||
{
|
||||
NazaraError("Declaration has no stream 0x" + NzString::Number(stream, 16));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned int upperLimit = GetElementCount(stream);
|
||||
if (i >= upperLimit)
|
||||
{
|
||||
NazaraError("Element index out of range (" + NzString::Number(i) + " >= " + NzString::Number(upperLimit) + ')');
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return &m_sharedImpl->elements[m_sharedImpl->streamPos[stream]+i];
|
||||
}
|
||||
|
||||
const NzVertexElement* NzVertexDeclaration::GetElement(nzElementStream stream, nzElementUsage usage, unsigned int usageIndex) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Declaration not created");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
int elementPos = m_sharedImpl->elementPos[stream][usage];
|
||||
if (elementPos == -1)
|
||||
return nullptr;
|
||||
|
||||
elementPos += usageIndex;
|
||||
if (static_cast<unsigned int>(elementPos) >= m_sharedImpl->elements.size())
|
||||
return nullptr;
|
||||
|
||||
NzVertexElement& element = m_sharedImpl->elements[elementPos];
|
||||
if (element.stream != stream || element.usage != usage || element.usageIndex != usageIndex)
|
||||
return nullptr;
|
||||
|
||||
return &element;
|
||||
}
|
||||
|
||||
unsigned int NzVertexDeclaration::GetElementCount() const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Declaration not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_sharedImpl->elements.size();
|
||||
}
|
||||
|
||||
unsigned int NzVertexDeclaration::GetElementCount(nzElementStream stream) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Declaration not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int streamPos = m_sharedImpl->streamPos[stream];
|
||||
if (streamPos == -1)
|
||||
return 0;
|
||||
|
||||
unsigned int upperLimit = 0;
|
||||
if (stream == nzElementStream_Max)
|
||||
upperLimit = m_sharedImpl->elements.size();
|
||||
else
|
||||
{
|
||||
for (unsigned int upperStream = stream+1; upperStream <= nzElementStream_Max; ++upperStream)
|
||||
{
|
||||
if (m_sharedImpl->streamPos[upperStream] != -1)
|
||||
{
|
||||
upperLimit = m_sharedImpl->streamPos[upperStream];
|
||||
break;
|
||||
}
|
||||
else if (upperStream == nzElementStream_Max) // Dernier stream, toujours pas de limite
|
||||
upperLimit = m_sharedImpl->elements.size();
|
||||
}
|
||||
}
|
||||
|
||||
return upperLimit-streamPos;
|
||||
}
|
||||
|
||||
unsigned int NzVertexDeclaration::GetStride(nzElementStream stream) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Declaration not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_sharedImpl->stride[stream];
|
||||
}
|
||||
|
||||
bool NzVertexDeclaration::HasStream(nzElementStream stream) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Declaration not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_sharedImpl->streamPos[stream] != -1;
|
||||
}
|
||||
|
||||
bool NzVertexDeclaration::IsValid() const
|
||||
{
|
||||
return m_sharedImpl != nullptr;
|
||||
}
|
||||
|
||||
NzVertexDeclaration& NzVertexDeclaration::operator=(const NzVertexDeclaration& declaration)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
m_sharedImpl = declaration.m_sharedImpl;
|
||||
if (m_sharedImpl)
|
||||
{
|
||||
NazaraMutexLock(m_sharedImpl->mutex);
|
||||
m_sharedImpl->refCount++;
|
||||
NazaraMutexUnlock(m_sharedImpl->mutex);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzVertexDeclaration& NzVertexDeclaration::operator=(NzVertexDeclaration&& declaration) noexcept
|
||||
{
|
||||
Destroy();
|
||||
|
||||
m_sharedImpl = declaration.m_sharedImpl;
|
||||
declaration.m_sharedImpl = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
// Copyright (C) 2012 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Engine - Utility module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Utility/VertexDeclaration.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Utility/Config.hpp>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#if NAZARA_UTILITY_THREADSAFE && NAZARA_THREADSAFETY_VERTEXDECLARATION
|
||||
#include <Nazara/Core/ThreadSafety.hpp>
|
||||
#else
|
||||
#include <Nazara/Core/ThreadSafetyOff.hpp>
|
||||
#endif
|
||||
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
const unsigned int elementCount[] =
|
||||
{
|
||||
4, // nzElementType_Color
|
||||
1, // nzElementType_Double1
|
||||
2, // nzElementType_Double2
|
||||
3, // nzElementType_Double3
|
||||
4, // nzElementType_Double4
|
||||
1, // nzElementType_Float1
|
||||
2, // nzElementType_Float2
|
||||
3, // nzElementType_Float3
|
||||
4 // nzElementType_Float4
|
||||
};
|
||||
|
||||
const unsigned int elementSize[] =
|
||||
{
|
||||
4*sizeof(nzUInt8), // nzElementType_Color
|
||||
1*sizeof(double), // nzElementType_Double1
|
||||
2*sizeof(double), // nzElementType_Double2
|
||||
3*sizeof(double), // nzElementType_Double3
|
||||
4*sizeof(double), // nzElementType_Double4
|
||||
1*sizeof(float), // nzElementType_Float1
|
||||
2*sizeof(float), // nzElementType_Float2
|
||||
3*sizeof(float), // nzElementType_Float3
|
||||
4*sizeof(float) // nzElementType_Float4
|
||||
};
|
||||
|
||||
bool VertexElementCompare(const NzVertexElement& elementA, const NzVertexElement& elementB)
|
||||
{
|
||||
// Nous classons d'abord par stream
|
||||
if (elementA.stream == elementB.stream)
|
||||
{
|
||||
// Ensuite par usage
|
||||
if (elementA.usage == elementB.usage)
|
||||
// Et finalement par usageIndex
|
||||
return elementA.usageIndex < elementB.usageIndex;
|
||||
else
|
||||
return elementA.usage < elementB.usage;
|
||||
}
|
||||
else
|
||||
return elementA.stream < elementB.stream;
|
||||
}
|
||||
}
|
||||
|
||||
struct NzVertexDeclarationImpl
|
||||
{
|
||||
std::vector<NzVertexElement> elements;
|
||||
int elementPos[nzElementStream_Max+1][nzElementUsage_Max+1];
|
||||
int streamPos[nzElementStream_Max+1];
|
||||
unsigned int stride[nzElementStream_Max+1] = {0};
|
||||
|
||||
unsigned short refCount = 1;
|
||||
NazaraMutex(mutex)
|
||||
};
|
||||
|
||||
NzVertexDeclaration::NzVertexDeclaration(const NzVertexElement* elements, unsigned int elementCount)
|
||||
{
|
||||
#ifdef NAZARA_DEBUG
|
||||
if (!Create(elements, elementCount))
|
||||
{
|
||||
NazaraError("Failed to create declaration");
|
||||
throw std::runtime_error("Constructor failed");
|
||||
}
|
||||
#else
|
||||
Create(elements, elementCount);
|
||||
#endif
|
||||
}
|
||||
|
||||
NzVertexDeclaration::NzVertexDeclaration(const NzVertexDeclaration& declaration) :
|
||||
NzResource(),
|
||||
m_sharedImpl(declaration.m_sharedImpl)
|
||||
{
|
||||
if (m_sharedImpl)
|
||||
{
|
||||
NazaraMutexLock(m_sharedImpl->mutex);
|
||||
m_sharedImpl->refCount++;
|
||||
NazaraMutexUnlock(m_sharedImpl->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
NzVertexDeclaration::NzVertexDeclaration(NzVertexDeclaration&& declaration) noexcept :
|
||||
m_sharedImpl(declaration.m_sharedImpl)
|
||||
{
|
||||
declaration.m_sharedImpl = nullptr;
|
||||
}
|
||||
|
||||
NzVertexDeclaration::~NzVertexDeclaration()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool NzVertexDeclaration::Create(const NzVertexElement* elements, unsigned int elementCount)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!elements || elementCount == 0)
|
||||
{
|
||||
NazaraError("No element");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
NzVertexDeclarationImpl* impl = new NzVertexDeclarationImpl;
|
||||
std::memset(&impl->elementPos, -1, (nzElementStream_Max+1)*(nzElementUsage_Max+1)*sizeof(int));
|
||||
std::memset(&impl->streamPos, -1, (nzElementStream_Max+1)*sizeof(int));
|
||||
|
||||
// On copie et trie les éléments
|
||||
impl->elements.resize(elementCount);
|
||||
std::memcpy(&impl->elements[0], elements, elementCount*sizeof(NzVertexElement));
|
||||
std::sort(impl->elements.begin(), impl->elements.end(), VertexElementCompare);
|
||||
|
||||
for (unsigned int i = 0; i < elementCount; ++i)
|
||||
{
|
||||
NzVertexElement& current = impl->elements[i];
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
// Notre tableau étant trié, s'il y a collision, les deux éléments identiques se suivent...
|
||||
if (i > 0)
|
||||
{
|
||||
NzVertexElement& previous = impl->elements[i-1]; // On accède à l'élément précédent
|
||||
if (previous.usage == current.usage && previous.usageIndex == current.usageIndex && previous.stream == current.stream)
|
||||
{
|
||||
// Les deux éléments sont identiques là où ils ne devraient pas, nous avons une collision...
|
||||
NazaraError("Element usage 0x" + NzString::Number(current.usage, 16) + " collision with usage index " + NzString::Number(current.usageIndex) + " on stream 0x" + NzString::Number(current.stream, 16));
|
||||
delete impl;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (current.usageIndex == 0)
|
||||
impl->elementPos[current.stream][current.usage] = i;
|
||||
|
||||
if (impl->streamPos[current.stream] == -1)
|
||||
impl->streamPos[current.stream] = i; // Premier élément du stream (via le triage)
|
||||
|
||||
impl->stride[current.stream] += elementSize[current.type];
|
||||
}
|
||||
|
||||
#if NAZARA_UTILITY_FORCE_DECLARATION_STRIDE_MULTIPLE_OF_32
|
||||
for (unsigned int& stride : impl->stride)
|
||||
stride = ((static_cast<int>(stride)-1)/32+1)*32;
|
||||
#endif
|
||||
|
||||
m_sharedImpl = impl;
|
||||
|
||||
NotifyCreated();
|
||||
return true;
|
||||
}
|
||||
|
||||
void NzVertexDeclaration::Destroy()
|
||||
{
|
||||
if (!m_sharedImpl)
|
||||
return;
|
||||
|
||||
NotifyDestroy();
|
||||
|
||||
NazaraMutexLock(m_sharedImpl->mutex);
|
||||
bool freeSharedImpl = (--m_sharedImpl->refCount == 0);
|
||||
NazaraMutexUnlock(m_sharedImpl->mutex);
|
||||
|
||||
if (freeSharedImpl)
|
||||
delete m_sharedImpl;
|
||||
|
||||
m_sharedImpl = nullptr;
|
||||
}
|
||||
|
||||
const NzVertexElement* NzVertexDeclaration::GetElement(unsigned int i) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Declaration not created");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (i >= m_sharedImpl->elements.size())
|
||||
{
|
||||
NazaraError("Element index out of range (" + NzString::Number(i) + " >= " + NzString::Number(m_sharedImpl->elements.size()) + ')');
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return &m_sharedImpl->elements[i];
|
||||
}
|
||||
|
||||
const NzVertexElement* NzVertexDeclaration::GetElement(nzElementStream stream, unsigned int i) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Declaration not created");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int streamPos = m_sharedImpl->streamPos[stream];
|
||||
if (streamPos == -1)
|
||||
{
|
||||
NazaraError("Declaration has no stream 0x" + NzString::Number(stream, 16));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned int upperLimit = GetElementCount(stream);
|
||||
if (i >= upperLimit)
|
||||
{
|
||||
NazaraError("Element index out of range (" + NzString::Number(i) + " >= " + NzString::Number(upperLimit) + ')');
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return &m_sharedImpl->elements[m_sharedImpl->streamPos[stream]+i];
|
||||
}
|
||||
|
||||
const NzVertexElement* NzVertexDeclaration::GetElement(nzElementStream stream, nzElementUsage usage, unsigned int usageIndex) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Declaration not created");
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
int elementPos = m_sharedImpl->elementPos[stream][usage];
|
||||
if (elementPos == -1)
|
||||
return nullptr;
|
||||
|
||||
elementPos += usageIndex;
|
||||
if (static_cast<unsigned int>(elementPos) >= m_sharedImpl->elements.size())
|
||||
return nullptr;
|
||||
|
||||
NzVertexElement& element = m_sharedImpl->elements[elementPos];
|
||||
if (element.stream != stream || element.usage != usage || element.usageIndex != usageIndex)
|
||||
return nullptr;
|
||||
|
||||
return &element;
|
||||
}
|
||||
|
||||
unsigned int NzVertexDeclaration::GetElementCount() const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Declaration not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_sharedImpl->elements.size();
|
||||
}
|
||||
|
||||
unsigned int NzVertexDeclaration::GetElementCount(nzElementStream stream) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Declaration not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int streamPos = m_sharedImpl->streamPos[stream];
|
||||
if (streamPos == -1)
|
||||
return 0;
|
||||
|
||||
unsigned int upperLimit = 0;
|
||||
if (stream == nzElementStream_Max)
|
||||
upperLimit = m_sharedImpl->elements.size();
|
||||
else
|
||||
{
|
||||
for (unsigned int upperStream = stream+1; upperStream <= nzElementStream_Max; ++upperStream)
|
||||
{
|
||||
if (m_sharedImpl->streamPos[upperStream] != -1)
|
||||
{
|
||||
upperLimit = m_sharedImpl->streamPos[upperStream];
|
||||
break;
|
||||
}
|
||||
else if (upperStream == nzElementStream_Max) // Dernier stream, toujours pas de limite
|
||||
upperLimit = m_sharedImpl->elements.size();
|
||||
}
|
||||
}
|
||||
|
||||
return upperLimit-streamPos;
|
||||
}
|
||||
|
||||
unsigned int NzVertexDeclaration::GetStride(nzElementStream stream) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Declaration not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_sharedImpl->stride[stream];
|
||||
}
|
||||
|
||||
bool NzVertexDeclaration::HasStream(nzElementStream stream) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Declaration not created");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_sharedImpl->streamPos[stream] != -1;
|
||||
}
|
||||
|
||||
bool NzVertexDeclaration::IsValid() const
|
||||
{
|
||||
return m_sharedImpl != nullptr;
|
||||
}
|
||||
|
||||
NzVertexDeclaration& NzVertexDeclaration::operator=(const NzVertexDeclaration& declaration)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
m_sharedImpl = declaration.m_sharedImpl;
|
||||
if (m_sharedImpl)
|
||||
{
|
||||
NazaraMutexLock(m_sharedImpl->mutex);
|
||||
m_sharedImpl->refCount++;
|
||||
NazaraMutexUnlock(m_sharedImpl->mutex);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
NzVertexDeclaration& NzVertexDeclaration::operator=(NzVertexDeclaration&& declaration) noexcept
|
||||
{
|
||||
Destroy();
|
||||
|
||||
m_sharedImpl = declaration.m_sharedImpl;
|
||||
declaration.m_sharedImpl = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
unsigned int NzVertexDeclaration::GetElementCount(nzElementType type)
|
||||
{
|
||||
return elementCount[type];
|
||||
}
|
||||
|
||||
unsigned int NzVertexDeclaration::GetElementSize(nzElementType type)
|
||||
{
|
||||
return elementSize[type];
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user