Added Meshes and Animations (And many more)
Added NzTexture::IsMipmappingSupported Color::(FromTo)HSV now takes hue and saturation in degrees Fixed Context::EnsureContext Fixed COW thread-safety (String, Image, Matrix4) Fixed Quatenion<T>::operator*(const Vector3<T>&) Fixed ResourceLoader Fixed String::Resize with a size of 0 Fixed Texture mipmapping crash Fixed per-class thread-safety IndexBuffer and VertexBuffer are now resources It is now possible to use more than 8 texcoords per shader Moved all enumerations into separate files (Core/Enums.hpp, Utility/Enums.hpp, ..) Removed NzContextParameters::defaultWindow VertexDeclaration has been rewritten (New interface/COW)
This commit is contained in:
@@ -5,6 +5,17 @@
|
||||
#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_THREADSAFETY_VERTEXDECLARATION
|
||||
#include <Nazara/Core/ThreadSafety.hpp>
|
||||
#else
|
||||
#include <Nazara/Core/ThreadSafetyOff.hpp>
|
||||
#endif
|
||||
|
||||
#include <Nazara/Utility/Debug.hpp>
|
||||
|
||||
namespace
|
||||
@@ -21,99 +32,315 @@ namespace
|
||||
12, // nzElementType_Float3
|
||||
16 // 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;
|
||||
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) :
|
||||
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)
|
||||
{
|
||||
unsigned int stream = elements[i].stream;
|
||||
|
||||
if (stream >= m_streams.size())
|
||||
m_streams.resize(stream+1);
|
||||
NzVertexElement& current = impl->elements[i];
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
else // Seulement si le stream ne vient pas d'être créé (Autrement c'est inutile)
|
||||
// Notre tableau étant trié, s'il y a collision, les deux éléments identiques se suivent...
|
||||
if (i > 0)
|
||||
{
|
||||
for (unsigned int j = 0; j < i; ++j)
|
||||
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)
|
||||
{
|
||||
if (elements[j].stream == stream && elements[j].usage == elements[i].usage && elements[j].usageIndex == elements[i].usageIndex)
|
||||
{
|
||||
NazaraError("Element usage (" + NzString::Number(elements[j].usage, 16) + ") collision on stream " + NzString::Number(stream) + " with usage index " + NzString::Number(elements[j].usageIndex));
|
||||
return false;
|
||||
}
|
||||
// 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
|
||||
|
||||
Element element;
|
||||
element.offset = elements[i].offset;
|
||||
element.type = elements[i].type;
|
||||
element.usage = elements[i].usage;
|
||||
element.usageIndex = elements[i].usageIndex;
|
||||
if (current.usageIndex == 0)
|
||||
impl->elementPos[current.stream][current.usage] = i;
|
||||
|
||||
m_streams[stream].elements.push_back(element);
|
||||
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];
|
||||
}
|
||||
|
||||
for (Stream& stream : m_streams)
|
||||
{
|
||||
stream.stride = 0;
|
||||
for (const Element& element : stream.elements)
|
||||
stream.stride += size[element.type];
|
||||
#if NAZARA_RENDERER_FORCE_DECLARATION_STRIDE_MULTIPLE_OF_32
|
||||
for (unsigned int& stride : impl->stride)
|
||||
stride = ((static_cast<int>(stride)-1)/32+1)*32;
|
||||
#endif
|
||||
|
||||
#if NAZARA_RENDERER_FORCE_DECLARATION_STRIDE_MULTIPLE_OF_32
|
||||
stream.stride = ((static_cast<int>(stream.stride)-1)/32+1)*32;
|
||||
#endif
|
||||
}
|
||||
m_sharedImpl = impl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const NzVertexDeclaration::Element* NzVertexDeclaration::GetElement(unsigned int i, unsigned int stream) const
|
||||
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 (stream >= m_streams.size())
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Stream out of range");
|
||||
NazaraError("Declaration not created");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (i >= m_streams[stream].elements.size())
|
||||
if (i >= m_sharedImpl->elements.size())
|
||||
{
|
||||
NazaraError("Index out of range");
|
||||
NazaraError("Element index out of range (" + NzString::Number(i) + " >= " + NzString::Number(m_sharedImpl->elements.size()) + ')');
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return &m_streams[stream].elements[i];
|
||||
return &m_sharedImpl->elements[i];
|
||||
}
|
||||
|
||||
unsigned int NzVertexDeclaration::GetElementCount(unsigned int stream) const
|
||||
const NzVertexElement* NzVertexDeclaration::GetElement(nzElementStream stream, unsigned int i) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (stream >= m_streams.size())
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Stream out of range");
|
||||
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_streams[stream].elements.size();
|
||||
return m_sharedImpl->elements.size();
|
||||
}
|
||||
|
||||
unsigned int NzVertexDeclaration::GetStreamCount() const
|
||||
{
|
||||
return m_streams.size();
|
||||
}
|
||||
|
||||
unsigned int NzVertexDeclaration::GetStride(unsigned int stream) const
|
||||
unsigned int NzVertexDeclaration::GetElementCount(nzElementStream stream) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (stream >= m_streams.size())
|
||||
if (!m_sharedImpl)
|
||||
{
|
||||
NazaraError("Stream out of range");
|
||||
NazaraError("Declaration not created");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_streams[stream].stride;
|
||||
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)
|
||||
{
|
||||
Destroy();
|
||||
|
||||
m_sharedImpl = declaration.m_sharedImpl;
|
||||
declaration.m_sharedImpl = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user