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:
Jérôme Leclercq
2012-09-20 22:07:30 +02:00
parent a6ed70123b
commit cd5a1b7a5e
65 changed files with 24385 additions and 22703 deletions

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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