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:
Lynix
2012-07-13 15:22:14 +02:00
parent 5f95f0b677
commit 06eda4eba9
75 changed files with 3385 additions and 861 deletions

View File

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