Browse Source

Initial freeform vertex declarations for D3D9.

Lasse Öörni 9 years ago
parent
commit
a458d30fd5

+ 2 - 5
Source/Urho3D/AngelScript/GraphicsAPI.cpp

@@ -750,7 +750,6 @@ static void RegisterBuffers(asIScriptEngine* engine)
     engine->RegisterGlobalProperty("const uint MASK_INSTANCEMATRIX2", (void*)&MASK_INSTANCEMATRIX2);
     engine->RegisterGlobalProperty("const uint MASK_INSTANCEMATRIX3", (void*)&MASK_INSTANCEMATRIX3);
     engine->RegisterGlobalProperty("const uint MASK_OBJECTINDEX", (void*)&MASK_OBJECTINDEX);
-    engine->RegisterGlobalProperty("const uint MASK_DEFAULT", (void*)&MASK_DEFAULT);
 
     engine->RegisterEnum("PrimitiveType");
     engine->RegisterEnumValue("PrimitiveType", "TRIANGLE_LIST", TRIANGLE_LIST);
@@ -762,7 +761,7 @@ static void RegisterBuffers(asIScriptEngine* engine)
 
     RegisterObject<VertexBuffer>(engine, "VertexBuffer");
     RegisterObjectConstructor<VertexBuffer>(engine, "VertexBuffer");
-    engine->RegisterObjectMethod("VertexBuffer", "void SetSize(uint, uint, bool dynamic = false)", asMETHOD(VertexBuffer, SetSize), asCALL_THISCALL);
+//    engine->RegisterObjectMethod("VertexBuffer", "void SetSize(uint, uint, bool dynamic = false)", asMETHOD(VertexBuffer, SetSize), asCALL_THISCALL);
     engine->RegisterObjectMethod("VertexBuffer", "bool SetData(VectorBuffer&)", asFUNCTION(VertexBufferSetData), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("VertexBuffer", "bool SetDataRange(VectorBuffer&, uint, uint, bool discard = false)", asFUNCTION(VertexBufferSetDataRange), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("VertexBuffer", "VectorBuffer GetData()", asFUNCTION(VertexBufferGetData), asCALL_CDECL_OBJLAST);
@@ -771,7 +770,6 @@ static void RegisterBuffers(asIScriptEngine* engine)
     engine->RegisterObjectMethod("VertexBuffer", "bool get_dynamic() const", asMETHOD(VertexBuffer, IsDynamic), asCALL_THISCALL);
     engine->RegisterObjectMethod("VertexBuffer", "uint get_vertexCount() const", asMETHOD(VertexBuffer, GetVertexCount), asCALL_THISCALL);
     engine->RegisterObjectMethod("VertexBuffer", "uint get_vertexSize() const", asMETHODPR(VertexBuffer, GetVertexSize, () const, unsigned), asCALL_THISCALL);
-    engine->RegisterObjectMethod("VertexBuffer", "uint get_elementMask() const", asMETHOD(VertexBuffer, GetElementMask), asCALL_THISCALL);
 
     RegisterObject<IndexBuffer>(engine, "IndexBuffer");
     RegisterObjectConstructor<IndexBuffer>(engine, "IndexBuffer");
@@ -789,12 +787,11 @@ static void RegisterBuffers(asIScriptEngine* engine)
     RegisterObjectConstructor<Geometry>(engine, "Geometry");
     engine->RegisterObjectMethod("Geometry", "void set_numVertexBuffers(uint)", asMETHOD(Geometry, SetNumVertexBuffers), asCALL_THISCALL);
     engine->RegisterObjectMethod("Geometry", "uint get_numVertexBuffers() const", asMETHOD(Geometry, GetNumVertexBuffers), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Geometry", "bool SetVertexBuffer(uint, VertexBuffer@+, uint elementMask = MASK_DEFAULT)", asMETHOD(Geometry, SetVertexBuffer), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Geometry", "bool SetVertexBuffer(uint, VertexBuffer@+)", asMETHOD(Geometry, SetVertexBuffer), asCALL_THISCALL);
     engine->RegisterObjectMethod("Geometry", "void SetIndexBuffer(IndexBuffer@+)", asMETHOD(Geometry, SetIndexBuffer), asCALL_THISCALL);
     engine->RegisterObjectMethod("Geometry", "bool SetDrawRange(PrimitiveType, uint, uint, bool getUsedVertexRange = true)", asMETHODPR(Geometry, SetDrawRange, (PrimitiveType, unsigned, unsigned, bool), bool),asCALL_THISCALL);
     engine->RegisterObjectMethod("Geometry", "bool SetDrawRange(PrimitiveType, uint, uint, uint, uint, bool checkIllegal = true)", asMETHODPR(Geometry, SetDrawRange, (PrimitiveType, unsigned, unsigned, unsigned, unsigned, bool), bool), asCALL_THISCALL);
     engine->RegisterObjectMethod("Geometry", "VertexBuffer@+ get_vertexBuffers(uint) const", asMETHOD(Geometry, GetVertexBuffer), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Geometry", "uint get_vertexElementMasks(uint) const", asMETHOD(Geometry, GetVertexElementMask), asCALL_THISCALL);
     engine->RegisterObjectMethod("Geometry", "void set_indexBuffer(IndexBuffer@+)", asMETHOD(Geometry, SetIndexBuffer), asCALL_THISCALL);
     engine->RegisterObjectMethod("Geometry", "IndexBuffer@+ get_indexBuffer() const", asMETHOD(Geometry, GetIndexBuffer), asCALL_THISCALL);
     engine->RegisterObjectMethod("Geometry", "PrimitiveType get_primitiveType() const", asMETHOD(Geometry, GetPrimitiveType), asCALL_THISCALL);

+ 8 - 8
Source/Urho3D/Graphics/AnimatedModel.cpp

@@ -1137,16 +1137,16 @@ void AnimatedModel::CloneGeometries()
             for (unsigned k = 0; k < originalBuffers.Size(); ++k)
             {
                 VertexBuffer* originalBuffer = originalBuffers[k];
-                unsigned originalMask = original->GetVertexElementMask(k);
 
                 if (clonedVertexBuffers.Contains(originalBuffer))
                 {
                     VertexBuffer* clonedBuffer = clonedVertexBuffers[originalBuffer];
-                    clone->SetVertexBuffer(l++, originalBuffer, originalMask & ~clonedBuffer->GetElementMask());
-                    clone->SetVertexBuffer(l++, clonedBuffer, originalMask & clonedBuffer->GetElementMask());
+                    clone->SetVertexBuffer(l++, originalBuffer);
+                    // Specify the morph buffer at a greater index to override the model's original positions/normals/tangents
+                    clone->SetVertexBuffer(l++, clonedBuffer);
                 }
                 else
-                    clone->SetVertexBuffer(l++, originalBuffer, originalMask);
+                    clone->SetVertexBuffer(l++, originalBuffer);
             }
 
             clone->SetIndexBuffer(original->GetIndexBuffer());
@@ -1166,8 +1166,8 @@ void AnimatedModel::CopyMorphVertices(void* destVertexData, void* srcVertexData,
     VertexBuffer* srcBuffer)
 {
     unsigned mask = destBuffer->GetElementMask() & srcBuffer->GetElementMask();
-    unsigned normalOffset = srcBuffer->GetElementOffset(ELEMENT_NORMAL);
-    unsigned tangentOffset = srcBuffer->GetElementOffset(ELEMENT_TANGENT);
+    unsigned normalOffset = srcBuffer->GetElementOffset(SEM_NORMAL);
+    unsigned tangentOffset = srcBuffer->GetElementOffset(SEM_TANGENT);
     unsigned vertexSize = srcBuffer->GetVertexSize();
     float* dest = (float*)destVertexData;
     unsigned char* src = (unsigned char*)srcVertexData;
@@ -1367,8 +1367,8 @@ void AnimatedModel::ApplyMorph(VertexBuffer* buffer, void* destVertexData, unsig
 {
     unsigned elementMask = morph.elementMask_ & buffer->GetElementMask();
     unsigned vertexCount = morph.vertexCount_;
-    unsigned normalOffset = buffer->GetElementOffset(ELEMENT_NORMAL);
-    unsigned tangentOffset = buffer->GetElementOffset(ELEMENT_TANGENT);
+    unsigned normalOffset = buffer->GetElementOffset(SEM_NORMAL);
+    unsigned tangentOffset = buffer->GetElementOffset(SEM_TANGENT);
     unsigned vertexSize = buffer->GetVertexSize();
 
     unsigned char* srcData = morph.morphData_;

+ 2 - 5
Source/Urho3D/Graphics/Batch.cpp

@@ -646,7 +646,7 @@ void BatchGroup::Draw(View* view, Camera* camera, bool allowDepthWrite) const
             Batch::Prepare(view, camera, false, allowDepthWrite);
 
             graphics->SetIndexBuffer(geometry_->GetIndexBuffer());
-            graphics->SetVertexBuffers(geometry_->GetVertexBuffers(), geometry_->GetVertexElementMasks());
+            graphics->SetVertexBuffers(geometry_->GetVertexBuffers());
 
             for (unsigned i = 0; i < instances_.Size(); ++i)
             {
@@ -665,18 +665,15 @@ void BatchGroup::Draw(View* view, Camera* camera, bool allowDepthWrite) const
             // Hack: use a const_cast to avoid dynamic allocation of new temp vectors
             Vector<SharedPtr<VertexBuffer> >& vertexBuffers = const_cast<Vector<SharedPtr<VertexBuffer> >&>(
                 geometry_->GetVertexBuffers());
-            PODVector<unsigned>& elementMasks = const_cast<PODVector<unsigned>&>(geometry_->GetVertexElementMasks());
             vertexBuffers.Push(SharedPtr<VertexBuffer>(instanceBuffer));
-            elementMasks.Push(instanceBuffer->GetElementMask());
 
             graphics->SetIndexBuffer(geometry_->GetIndexBuffer());
-            graphics->SetVertexBuffers(vertexBuffers, elementMasks, startIndex_);
+            graphics->SetVertexBuffers(vertexBuffers, startIndex_);
             graphics->DrawInstanced(geometry_->GetPrimitiveType(), geometry_->GetIndexStart(), geometry_->GetIndexCount(),
                 geometry_->GetVertexStart(), geometry_->GetVertexCount(), instances_.Size());
 
             // Remove the instancing buffer & element mask now
             vertexBuffers.Pop();
-            elementMasks.Pop();
         }
     }
 }

+ 1 - 2
Source/Urho3D/Graphics/BillboardSet.cpp

@@ -81,8 +81,7 @@ BillboardSet::BillboardSet(Context* context) :
     sortFrameNumber_(0),
     previousOffset_(Vector3::ZERO)
 {
-    // Vertex buffer doesn't have its format defined yet, so manually define the elements into Geometry now
-    geometry_->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1 | MASK_TEXCOORD2);
+    geometry_->SetVertexBuffer(0, vertexBuffer_);
     geometry_->SetIndexBuffer(indexBuffer_);
 
     batches_.Resize(1);

+ 5 - 5
Source/Urho3D/Graphics/CustomGeometry.cpp

@@ -188,11 +188,11 @@ bool CustomGeometry::DrawOcclusion(OcclusionBuffer* buffer)
         unsigned vertexSize;
         const unsigned char* indexData;
         unsigned indexSize;
-        unsigned elementMask;
+        const PODVector<VertexElement>* elements;
 
-        geometry->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
+        geometry->GetRawData(vertexData, vertexSize, indexData, indexSize, elements);
         // Check for valid geometry data
-        if (!vertexData)
+        if (!vertexData || !elements || VertexBuffer::GetElementOffset(*elements, TYPE_VECTOR3, SEM_POSITION) != 0)
             continue;
 
         // Draw and check for running out of triangles
@@ -389,7 +389,7 @@ void CustomGeometry::Commit()
                     ++vertexCount;
                 }
 
-                geometries_[i]->SetVertexBuffer(0, vertexBuffer_, elementMask_);
+                geometries_[i]->SetVertexBuffer(0, vertexBuffer_);
                 geometries_[i]->SetDrawRange(primitiveTypes_[i], 0, 0, vertexStart, vertexCount);
                 vertexStart += vertexCount;
             }
@@ -403,7 +403,7 @@ void CustomGeometry::Commit()
     {
         for (unsigned i = 0; i < geometries_.Size(); ++i)
         {
-            geometries_[i]->SetVertexBuffer(0, vertexBuffer_, elementMask_);
+            geometries_[i]->SetVertexBuffer(0, vertexBuffer_);
             geometries_[i]->SetDrawRange(primitiveTypes_[i], 0, 0, 0, 0);
         }
     }

+ 5 - 5
Source/Urho3D/Graphics/DecalSet.cpp

@@ -717,7 +717,7 @@ void DecalSet::GetFaces(Vector<PODVector<DecalVertex> >& faces, Drawable* target
         if (!vb)
             continue;
 
-        unsigned elementMask = geometry->GetVertexElementMask(i);
+        unsigned elementMask = vb->GetElementMask();
         unsigned char* data = vb->GetShadowData();
         if (!data)
             continue;
@@ -729,12 +729,12 @@ void DecalSet::GetFaces(Vector<PODVector<DecalVertex> >& faces, Drawable* target
         }
         if (elementMask & MASK_NORMAL)
         {
-            normalData = data + vb->GetElementOffset(ELEMENT_NORMAL);
+            normalData = data + vb->GetElementOffset(SEM_NORMAL);
             normalStride = vb->GetVertexSize();
         }
         if (elementMask & MASK_BLENDWEIGHTS)
         {
-            skinningData = data + vb->GetElementOffset(ELEMENT_BLENDWEIGHTS);
+            skinningData = data + vb->GetElementOffset(SEM_BLENDWEIGHTS);
             skinningStride = vb->GetVertexSize();
         }
     }
@@ -743,8 +743,8 @@ void DecalSet::GetFaces(Vector<PODVector<DecalVertex> >& faces, Drawable* target
     if (!positionData)
     {
         // As a fallback, try to get the geometry's raw vertex/index data
-        unsigned elementMask;
-        geometry->GetRawData(positionData, positionStride, indexData, indexStride, elementMask);
+        const PODVector<VertexElement>* elements;
+        geometry->GetRawData(positionData, positionStride, indexData, indexStride, elements);
         if (!positionData)
         {
             URHO3D_LOGWARNING("Can not add decal, target drawable has no CPU-side geometry data");

+ 14 - 19
Source/Urho3D/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -913,7 +913,9 @@ void Graphics::DrawInstanced(PrimitiveType type, unsigned indexStart, unsigned i
         VertexBuffer* buffer = vertexBuffers_[i];
         if (buffer)
         {
-            if (buffer->GetElementMask() & MASK_INSTANCEMATRIX1)
+            const PODVector<VertexElement>& elements = buffer->GetElements();
+            // Check if buffer has per-instance data
+            if (elements.Size() && elements[0].perInstance_)
                 SetStreamFrequency(i, D3DSTREAMSOURCE_INSTANCEDATA | 1u);
             else
                 SetStreamFrequency(i, D3DSTREAMSOURCE_INDEXEDDATA | instanceCount);
@@ -934,34 +936,26 @@ void Graphics::SetVertexBuffer(VertexBuffer* buffer)
 {
     // Note: this is not multi-instance safe
     static PODVector<VertexBuffer*> vertexBuffers(1);
-    static PODVector<unsigned> elementMasks(1);
     vertexBuffers[0] = buffer;
-    elementMasks[0] = MASK_DEFAULT;
-    SetVertexBuffers(vertexBuffers, elementMasks);
+    SetVertexBuffers(vertexBuffers);
 }
 
-bool Graphics::SetVertexBuffers(const PODVector<VertexBuffer*>& buffers, const PODVector<unsigned>& elementMasks,
-    unsigned instanceOffset)
+bool Graphics::SetVertexBuffers(const PODVector<VertexBuffer*>& buffers, unsigned instanceOffset)
 {
     if (buffers.Size() > MAX_VERTEX_STREAMS)
     {
         URHO3D_LOGERROR("Too many vertex buffers");
         return false;
     }
-    if (buffers.Size() != elementMasks.Size())
-    {
-        URHO3D_LOGERROR("Amount of element masks and vertex buffers does not match");
-        return false;
-    }
 
-    // Build vertex declaration hash code out of the buffers & masks
+    // Build vertex declaration hash code out of the buffers
     unsigned long long hash = 0;
     for (unsigned i = 0; i < buffers.Size(); ++i)
     {
         if (!buffers[i])
             continue;
 
-        hash |= buffers[i]->GetBufferHash(i, elementMasks[i]);
+        hash |= buffers[i]->GetBufferHash(i);
     }
 
     if (hash)
@@ -969,7 +963,7 @@ bool Graphics::SetVertexBuffers(const PODVector<VertexBuffer*>& buffers, const P
         // If no previous vertex declaration for that hash, create new
         if (!vertexDeclarations_.Contains(hash))
         {
-            SharedPtr<VertexDeclaration> newDeclaration(new VertexDeclaration(this, buffers, elementMasks));
+            SharedPtr<VertexDeclaration> newDeclaration(new VertexDeclaration(this, buffers));
             if (!newDeclaration->GetDeclaration())
                 return false;
 
@@ -989,10 +983,12 @@ bool Graphics::SetVertexBuffers(const PODVector<VertexBuffer*>& buffers, const P
         VertexBuffer* buffer = 0;
         unsigned offset = 0;
 
-        if (i < buffers.Size())
+        if (i < buffers.Size() && buffers[i])
         {
             buffer = buffers[i];
-            if (buffer && buffer->GetElementMask() & MASK_INSTANCEMATRIX1)
+            const PODVector<VertexElement>& elements = buffer->GetElements();
+            // Check if buffer has per-instance data; add instance offset in that case
+            if (elements.Size() && elements[0].perInstance_)
                 offset = instanceOffset * buffer->GetVertexSize();
         }
 
@@ -1012,10 +1008,9 @@ bool Graphics::SetVertexBuffers(const PODVector<VertexBuffer*>& buffers, const P
     return true;
 }
 
-bool Graphics::SetVertexBuffers(const Vector<SharedPtr<VertexBuffer> >& buffers, const PODVector<unsigned>& elementMasks,
-    unsigned instanceOffset)
+bool Graphics::SetVertexBuffers(const Vector<SharedPtr<VertexBuffer> >& buffers, unsigned instanceOffset)
 {
-    return SetVertexBuffers(reinterpret_cast<const PODVector<VertexBuffer*>&>(buffers), elementMasks, instanceOffset);
+    return SetVertexBuffers(reinterpret_cast<const PODVector<VertexBuffer*>&>(buffers), instanceOffset);
 }
 
 void Graphics::SetIndexBuffer(IndexBuffer* buffer)

+ 2 - 4
Source/Urho3D/Graphics/Direct3D9/D3D9Graphics.h

@@ -130,11 +130,9 @@ public:
     /// Set vertex buffer.
     void SetVertexBuffer(VertexBuffer* buffer);
     /// Set multiple vertex buffers.
-    bool SetVertexBuffers
-        (const PODVector<VertexBuffer*>& buffers, const PODVector<unsigned>& elementMasks, unsigned instanceOffset = 0);
+    bool SetVertexBuffers(const PODVector<VertexBuffer*>& buffers, unsigned instanceOffset = 0);
     /// Set multiple vertex buffers.
-    bool SetVertexBuffers
-        (const Vector<SharedPtr<VertexBuffer> >& buffers, const PODVector<unsigned>& elementMasks, unsigned instanceOffset = 0);
+    bool SetVertexBuffers(const Vector<SharedPtr<VertexBuffer> >& buffers, unsigned instanceOffset = 0);
     /// Set index buffer.
     void SetIndexBuffer(IndexBuffer* buffer);
     /// Set shaders.

+ 147 - 51
Source/Urho3D/Graphics/Direct3D9/D3D9VertexBuffer.cpp

@@ -32,29 +32,40 @@
 namespace Urho3D
 {
 
-const unsigned VertexBuffer::elementSize[] =
+static const VertexElement legacyVertexElements[] =
 {
-    3 * sizeof(float), // Position
-    3 * sizeof(float), // Normal
-    4 * sizeof(unsigned char), // Color
-    2 * sizeof(float), // Texcoord1
-    2 * sizeof(float), // Texcoord2
-    3 * sizeof(float), // Cubetexcoord1
-    3 * sizeof(float), // Cubetexcoord2
-    4 * sizeof(float), // Tangent
-    4 * sizeof(float), // Blendweights
-    4 * sizeof(unsigned char), // Blendindices
-    4 * sizeof(float), // Instancematrix1
-    4 * sizeof(float), // Instancematrix2
-    4 * sizeof(float), // Instancematrix3
-    sizeof(int) // Object index, not supported on D3D9 but allowed for vertex data compatibility
+    {TYPE_VECTOR3, SEM_POSITION, 0, false},     // Position
+    {TYPE_VECTOR3, SEM_NORMAL, 0, false},       // Normal
+    {TYPE_UBYTE4_NORM, SEM_COLOR, 0, false},    // Color
+    {TYPE_VECTOR2, SEM_TEXCOORD, 0, false},     // Texcoord1
+    {TYPE_VECTOR2, SEM_TEXCOORD, 0, false},     // Texcoord2
+    {TYPE_VECTOR3, SEM_TEXCOORD, 0, false},     // Cubetexcoord1
+    {TYPE_VECTOR3, SEM_TEXCOORD, 1, false},     // Cubetexcoord2
+    {TYPE_VECTOR4, SEM_TANGENT, 0, false},      // Tangent
+    {TYPE_VECTOR4, SEM_BLENDWEIGHTS, 0, false}, // Blendweights
+    {TYPE_UBYTE4, SEM_BLENDINDICES, 0, false},  // Blendindices
+    {TYPE_VECTOR4, SEM_TEXCOORD, 4, true},      // Instancematrix1
+    {TYPE_VECTOR4, SEM_TEXCOORD, 5, true},      // Instancematrix2
+    {TYPE_VECTOR4, SEM_TEXCOORD, 6, true},      // Instancematrix3
+    {TYPE_INT, SEM_OBJECTINDEX, 0, false},      // Objectindex
+};
+
+static const unsigned elementTypeSize[] =
+{
+    sizeof(int),
+    sizeof(float),
+    2 * sizeof(float),
+    3 * sizeof(float),
+    4 * sizeof(float),
+    sizeof(unsigned),
+    sizeof(unsigned)
 };
 
 VertexBuffer::VertexBuffer(Context* context, bool forceHeadless) :
     Object(context),
     GPUObject(forceHeadless ? (Graphics*)0 : GetSubsystem<Graphics>()),
     vertexCount_(0),
-    elementMask_(0),
+    elementHash_(0),
     pool_(D3DPOOL_MANAGED),
     usage_(0),
     lockState_(LOCK_NONE),
@@ -63,8 +74,6 @@ VertexBuffer::VertexBuffer(Context* context, bool forceHeadless) :
     lockScratchData_(0),
     shadowed_(false)
 {
-    UpdateOffsets();
-
     // Force shadowing mode if graphics subsystem does not exist
     if (!graphics_)
         shadowed_ = true;
@@ -128,6 +137,11 @@ void VertexBuffer::SetShadowed(bool enable)
 }
 
 bool VertexBuffer::SetSize(unsigned vertexCount, unsigned elementMask, bool dynamic)
+{
+    return SetSize(vertexCount, GetElements(elementMask), dynamic);
+}
+
+bool VertexBuffer::SetSize(unsigned vertexCount, const PODVector<VertexElement>& elements, bool dynamic)
 {
     Unlock();
 
@@ -143,7 +157,7 @@ bool VertexBuffer::SetSize(unsigned vertexCount, unsigned elementMask, bool dyna
     }
 
     vertexCount_ = vertexCount;
-    elementMask_ = elementMask;
+    elements_ = elements;
 
     UpdateOffsets();
 
@@ -323,68 +337,150 @@ bool VertexBuffer::IsDynamic() const
 void VertexBuffer::UpdateOffsets()
 {
     unsigned elementOffset = 0;
-    for (unsigned i = 0; i < MAX_VERTEX_ELEMENTS; ++i)
+    elementHash_ = 0;
+
+    for (PODVector<VertexElement>::Iterator i = elements_.Begin(); i != elements_.End(); ++i)
     {
-        if (elementMask_ & (1 << i))
-        {
-            elementOffset_[i] = elementOffset;
-            elementOffset += elementSize[i];
-        }
-        else
-            elementOffset_[i] = NO_ELEMENT;
+        i->offset_ = elementOffset;
+        elementOffset += elementTypeSize[i->type_];
+        elementHash_ <<= 6;
+        elementHash_ += (((int)i->type_ + 1) * ((int)i->semantic_ + 1) + i->index_);
     }
+
     vertexSize_ = elementOffset;
 }
 
-unsigned long long VertexBuffer::GetBufferHash(unsigned streamIndex, unsigned useMask)
+const VertexElement* VertexBuffer::GetElement(VertexElementSemantic semantic, unsigned char index) const
 {
-    unsigned long long bufferHash = elementMask_;
-    unsigned long long maskHash;
-    if (useMask == MASK_DEFAULT)
-        maskHash = ((unsigned long long)elementMask_) * 0x100000000ULL;
-    else
-        maskHash = ((unsigned long long)useMask) * 0x100000000ULL;
+    for (PODVector<VertexElement>::ConstIterator i = elements_.Begin(); i != elements_.End(); ++i)
+    {
+        if (i->semantic_ == semantic && i->index_ == index)
+            return &(*i);
+    }
+
+    return 0;
+}
 
-    bufferHash |= maskHash;
-    bufferHash <<= streamIndex * MAX_VERTEX_ELEMENTS;
+const VertexElement* VertexBuffer::GetElement(VertexElementType type, VertexElementSemantic semantic, unsigned char index) const
+{
+    for (PODVector<VertexElement>::ConstIterator i = elements_.Begin(); i != elements_.End(); ++i)
+    {
+        if (i->type_ == type && i->semantic_ == semantic && i->index_ == index)
+            return &(*i);
+    }
 
-    return bufferHash;
+    return 0;
 }
 
-unsigned VertexBuffer::GetVertexSize(unsigned elementMask)
+const VertexElement* VertexBuffer::GetElement(const PODVector<VertexElement>& elements, VertexElementType type, VertexElementSemantic semantic, unsigned char index)
+{
+    for (PODVector<VertexElement>::ConstIterator i = elements.Begin(); i != elements.End(); ++i)
+    {
+        if (i->type_ == type && i->semantic_ == semantic && i->index_ == index)
+            return &(*i);
+    }
+
+    return 0;
+}
+
+bool VertexBuffer::HasElement(const PODVector<VertexElement>& elements, VertexElementType type, VertexElementSemantic semantic, unsigned char index)
+{
+    return GetElement(elements, type, semantic, index) != 0;
+}
+
+unsigned VertexBuffer::GetElementMask() const
 {
-    unsigned vertexSize = 0;
+    unsigned mask = 0;
 
-    for (unsigned i = 0; i < MAX_VERTEX_ELEMENTS; ++i)
+    for (PODVector<VertexElement>::ConstIterator i = elements_.Begin(); i != elements_.End(); ++i)
     {
-        if (elementMask & (1 << i))
-            vertexSize += elementSize[i];
+        if (i->type_ == TYPE_VECTOR2 && i->semantic_ == SEM_TEXCOORD)
+        {
+            if (i->index_ == 0)
+                mask |= MASK_TEXCOORD1;
+            else if (i->index_ == 1)
+                mask |= MASK_TEXCOORD2;
+            else if (i->index_ == 4)
+                mask |= MASK_INSTANCEMATRIX1;
+            else if (i->index_ == 5)
+                mask |= MASK_INSTANCEMATRIX2;
+            else if (i->index_ == 6)
+                mask |= MASK_INSTANCEMATRIX3;
+        }
+        else if (i->type_ == TYPE_VECTOR3)
+        {
+            if (i->semantic_ == SEM_POSITION)
+                mask |= MASK_POSITION;
+            else if (i->semantic_ == SEM_NORMAL)
+                mask |= MASK_NORMAL;
+            else if (i->semantic_ == SEM_TEXCOORD && i->index_ == 0)
+                mask |= MASK_CUBETEXCOORD1;
+            else if (i->semantic_ == SEM_TEXCOORD && i->index_ == 1)
+                mask |= MASK_CUBETEXCOORD2;
+        }
+        else if (i->type_ == TYPE_VECTOR4)
+        {
+            if (i->semantic_ == SEM_TANGENT)
+                mask |= MASK_TANGENT;
+            else if (i->semantic_ == SEM_BLENDWEIGHTS)
+                mask |= MASK_BLENDWEIGHTS;
+        }
+        else if (i->type_ == TYPE_UBYTE4 && i->semantic_ == SEM_BLENDINDICES)
+            mask |= MASK_BLENDINDICES;
+        else if (i->type_ == TYPE_UBYTE4_NORM && i->semantic_ == SEM_COLOR)
+            mask |= MASK_COLOR;
     }
 
-    return vertexSize;
+    return mask;
+}
+
+unsigned VertexBuffer::GetElementOffset(const PODVector<VertexElement>& elements, VertexElementType type, VertexElementSemantic semantic, unsigned char index)
+{
+    const VertexElement* element = GetElement(elements, type, semantic, index);
+    return element ? element->offset_ : M_MAX_UNSIGNED;
 }
 
-unsigned VertexBuffer::GetElementOffset(unsigned elementMask, VertexElement element)
+PODVector<VertexElement> VertexBuffer::GetElements(unsigned elementMask)
 {
-    unsigned offset = 0;
+    PODVector<VertexElement> ret;
 
-    for (unsigned i = 0; i < MAX_VERTEX_ELEMENTS; ++i)
+    for (unsigned i = 0; i < MAX_LEGACY_VERTEX_ELEMENTS; ++i)
     {
-        if (i == element)
-            break;
+        if (elementMask & (1 << i))
+            ret.Push(legacyVertexElements[i]);
+    }
+
+    return ret;
+}
+
+unsigned VertexBuffer::GetVertexSize(const PODVector<VertexElement>& elements)
+{
+    unsigned size = 0;
+
+    for (unsigned i = 0; i < elements.Size(); ++i)
+        size += elementTypeSize[elements[i].type_];
 
+    return size;
+}
+
+unsigned VertexBuffer::GetVertexSize(unsigned elementMask)
+{
+    unsigned size = 0;
+
+    for (unsigned i = 0; i < MAX_LEGACY_VERTEX_ELEMENTS; ++i)
+    {
         if (elementMask & (1 << i))
-            offset += elementSize[i];
+            size += elementTypeSize[legacyVertexElements[i].type_];
     }
 
-    return offset;
+    return size;
 }
 
 bool VertexBuffer::Create()
 {
     Release();
 
-    if (!vertexCount_ || !elementMask_)
+    if (!vertexCount_ || elements_.Empty())
         return true;
 
     if (graphics_)

+ 47 - 17
Source/Urho3D/Graphics/Direct3D9/D3D9VertexBuffer.h

@@ -49,7 +49,9 @@ public:
 
     /// Enable shadowing in CPU memory. Shadowing is forced on if the graphics subsystem does not exist.
     void SetShadowed(bool enable);
-    /// Set size and vertex elements and dynamic mode. Previous data will be lost.
+    /// Set size, vertex elements and dynamic mode. Previous data will be lost.
+    bool SetSize(unsigned vertexCount, const PODVector<VertexElement>& elements, bool dynamic = false);
+    /// Set size and vertex elements and dynamic mode using legacy element bitmask. Previous data will be lost.
     bool SetSize(unsigned vertexCount, unsigned elementMask, bool dynamic = false);
     /// Set all data in the buffer.
     bool SetData(const void* data);
@@ -75,14 +77,32 @@ public:
     /// Return vertex size.
     unsigned GetVertexSize() const { return vertexSize_; }
 
-    /// Return bitmask of vertex elements.
-    unsigned GetElementMask() const { return elementMask_; }
+    /// Return vertex elements.
+    const PODVector<VertexElement>& GetElements() const { return elements_; }
 
-    /// Return offset of a specified element within a vertex.
-    unsigned GetElementOffset(VertexElement element) const { return elementOffset_[element]; }
+    /// Return vertex element, or null if does not exist.
+    const VertexElement* GetElement(VertexElementSemantic semantic, unsigned char index = 0) const;
+
+    /// Return vertex element with specific type, or null if does not exist.
+    const VertexElement* GetElement(VertexElementType type, VertexElementSemantic semantic, unsigned char index = 0) const;
+
+    /// Return whether has a specified element semantic.
+    bool HasElement(VertexElementSemantic semantic, unsigned char index = 0) const { return GetElement(semantic, index) != 0; }
+
+    /// Return whether has an element semantic with specific type.
+    bool HasElement(VertexElementType type, VertexElementSemantic semantic, unsigned char index = 0) const { return GetElement(type, semantic, index) != 0; }
+
+    /// Return offset of a element within vertex, or M_MAX_UNSIGNED if does not exist.
+    unsigned GetElementOffset(VertexElementSemantic semantic, unsigned char index = 0) const { const VertexElement* element = GetElement(semantic, index); return element ? element->offset_ : M_MAX_UNSIGNED; }
+
+    /// Return offset of a element with specific type within vertex, or M_MAX_UNSIGNED if element does not exist.
+    unsigned GetElementOffset(VertexElementType type, VertexElementSemantic semantic, unsigned char index = 0) const { const VertexElement* element = GetElement(type, semantic, index); return element ? element->offset_ : M_MAX_UNSIGNED; }
 
     /// Return buffer hash for building vertex declarations.
-    unsigned long long GetBufferHash(unsigned streamIndex, unsigned useMask);
+    unsigned long long GetBufferHash(unsigned streamIndex) { return elementHash_ << (streamIndex * 16); }
+
+    /// Return legacy vertex element mask.
+    unsigned GetElementMask() const;
 
     /// Return CPU memory shadow data.
     unsigned char* GetShadowData() const { return shadowData_.Get(); }
@@ -90,16 +110,26 @@ public:
     /// Return shared array pointer to the CPU memory shadow data.
     SharedArrayPtr<unsigned char> GetShadowDataShared() const { return shadowData_; }
 
-    /// Return vertex size corresponding to a vertex element mask.
-    static unsigned GetVertexSize(unsigned elementMask);
-    /// Return element offset from an element mask.
-    static unsigned GetElementOffset(unsigned elementMask, VertexElement element);
+    /// Return element with specified type and semantic from a vertex element list, or null if does not exist.
+    static const VertexElement* GetElement(const PODVector<VertexElement>& elements, VertexElementType type, VertexElementSemantic semantic, unsigned char index = 0);
+
+    /// Return whether element list has a specified element type and semantic.
+    static bool HasElement(const PODVector<VertexElement>& elements, VertexElementType type, VertexElementSemantic semantic, unsigned char index = 0);
+
+    /// Return element offset for specified type and semantic from a vertex element list, or M_MAX_UNSIGNED if does not exist.
+    static unsigned GetElementOffset(const PODVector<VertexElement>& elements, VertexElementType type, VertexElementSemantic semantic, unsigned char index = 0);
 
-    /// Vertex element sizes.
-    static const unsigned elementSize[];
+    /// Return a vertex element list from a legacy element bitmask.
+    static PODVector<VertexElement> GetElements(unsigned elementMask);
+
+    /// Return vertex size from an element list.
+    static unsigned GetVertexSize(const PODVector<VertexElement>& elements);
+
+    /// Return vertex size for a legacy vertex element bitmask.
+    static unsigned GetVertexSize(unsigned elementMask);
 
 private:
-    /// Update offsets of vertex elements.
+    /// Update vertex size, offsets of vertex elements and the element hash.
     void UpdateOffsets();
     /// Create buffer.
     bool Create();
@@ -116,10 +146,10 @@ private:
     unsigned vertexCount_;
     /// Vertex size.
     unsigned vertexSize_;
-    /// Vertex element bitmask.
-    unsigned elementMask_;
-    /// Vertex element offsets.
-    unsigned elementOffset_[MAX_VERTEX_ELEMENTS];
+    /// Vertex elements.
+    PODVector<VertexElement> elements_;
+    /// Vertex element hash.
+    unsigned long long elementHash_;
     /// Memory pool.
     unsigned pool_;
     /// Usage type.

+ 94 - 110
Source/Urho3D/Graphics/Direct3D9/D3D9VertexDeclaration.cpp

@@ -35,121 +35,99 @@ namespace Urho3D
 
 const BYTE d3dElementType[] =
 {
-    D3DDECLTYPE_FLOAT3, // Position
-    D3DDECLTYPE_FLOAT3, // Normal
-    D3DDECLTYPE_UBYTE4N, // Color
-    D3DDECLTYPE_FLOAT2, // Texcoord1
-    D3DDECLTYPE_FLOAT2, // Texcoord2
-    D3DDECLTYPE_FLOAT3, // Cubetexcoord1
-    D3DDECLTYPE_FLOAT3, // Cubetexcoord2
-    D3DDECLTYPE_FLOAT4, // Tangent
-    D3DDECLTYPE_FLOAT4, // Blendweights
-    D3DDECLTYPE_UBYTE4, // Blendindices
-    D3DDECLTYPE_FLOAT4, // Instancematrix1
-    D3DDECLTYPE_FLOAT4, // Instancematrix2
-    D3DDECLTYPE_FLOAT4 // Instancematrix3
+    D3DDECLTYPE_UNUSED, // Int (not supported by D3D9)
+    D3DDECLTYPE_FLOAT1, // Float
+    D3DDECLTYPE_FLOAT2, // Vector2
+    D3DDECLTYPE_FLOAT3, // Vector3
+    D3DDECLTYPE_FLOAT4, // Vector4
+    D3DDECLTYPE_UBYTE4, // 4 bytes, not normalized
+    D3DDECLTYPE_UBYTE4N // 4 bytes, normalized
 };
 
 const BYTE d3dElementUsage[] =
 {
-    D3DDECLUSAGE_POSITION, // Position
-    D3DDECLUSAGE_NORMAL, // Normal
-    D3DDECLUSAGE_COLOR, // Color
-    D3DDECLUSAGE_TEXCOORD, // Texcoord1
-    D3DDECLUSAGE_TEXCOORD, // Texcoord2
-    D3DDECLUSAGE_TEXCOORD, // Cubetexcoord1
-    D3DDECLUSAGE_TEXCOORD, // Cubetexcoord2
-    D3DDECLUSAGE_TANGENT, // Tangent
-    D3DDECLUSAGE_BLENDWEIGHT, // Blendweights
-    D3DDECLUSAGE_BLENDINDICES, // Blendindices
-    D3DDECLUSAGE_TEXCOORD, // Instancematrix1
-    D3DDECLUSAGE_TEXCOORD, // Instancematrix2
-    D3DDECLUSAGE_TEXCOORD // Instancematrix3
+    D3DDECLUSAGE_POSITION,
+    D3DDECLUSAGE_NORMAL,
+    D3DDECLUSAGE_BINORMAL,
+    D3DDECLUSAGE_TANGENT,
+    D3DDECLUSAGE_TEXCOORD,
+    D3DDECLUSAGE_COLOR,
+    D3DDECLUSAGE_BLENDWEIGHT,
+    D3DDECLUSAGE_BLENDINDICES, 
+    D3DDECLUSAGE_TEXCOORD // Object index (not supported by D3D9)
 };
 
-const BYTE d3dElementUsageIndex[] =
-{
-    0, // Position
-    0, // Normal
-    0, // Color
-    0, // Texcoord1
-    1, // Texcoord2
-    0, // Cubetexcoord1
-    1, // Cubetexcoord2
-    0, // Tangent
-    0, // Blendweights
-    0, // Blendindices
-    2, // Instancematrix1
-    3, // Instancematrix2
-    4 // Instancematrix3
-};
-
-VertexDeclaration::VertexDeclaration(Graphics* graphics, unsigned elementMask) :
+VertexDeclaration::VertexDeclaration(Graphics* graphics, const PODVector<VertexElement>& srcElements) :
     declaration_(0)
 {
     PODVector<VertexDeclarationElement> elements;
-    unsigned offset = 0;
 
-    if (elementMask & MASK_OBJECTINDEX)
-        URHO3D_LOGWARNING("Object index attribute is not supported on Direct3D9 and will be ignored");
-
-    for (unsigned i = 0; i < ELEMENT_OBJECTINDEX; ++i)
+    for (unsigned i = 0; i < srcElements.Size(); ++i)
     {
-        VertexElement element = (VertexElement)i;
+        const VertexElement& srcElement = srcElements[i];
 
-        if (elementMask & (1 << i))
+        if (srcElement.semantic_ == SEM_OBJECTINDEX)
         {
-            VertexDeclarationElement newElement;
-            newElement.stream_ = 0;
-            newElement.element_ = element;
-            newElement.offset_ = offset;
-            offset += VertexBuffer::elementSize[i];
-
-            elements.Push(newElement);
+            URHO3D_LOGWARNING("Object index attribute is not supported on Direct3D9 and will be ignored");
+            continue;
         }
+
+        VertexDeclarationElement element;
+        element.semantic_ = srcElement.semantic_;
+        element.type_ = srcElement.type_;
+        element.index_ = srcElement.index_;
+        element.streamIndex_ = 0;
+        element.offset_ = srcElement.offset_;
+        elements.Push(element);
     }
 
     Create(graphics, elements);
 }
 
-VertexDeclaration::VertexDeclaration(Graphics* graphics, const PODVector<VertexBuffer*>& buffers,
-    const PODVector<unsigned>& elementMasks) :
+VertexDeclaration::VertexDeclaration(Graphics* graphics, const PODVector<VertexBuffer*>& buffers) :
     declaration_(0)
 {
-    unsigned usedElementMask = 0;
     PODVector<VertexDeclarationElement> elements;
 
     for (unsigned i = 0; i < buffers.Size(); ++i)
     {
         if (buffers[i])
         {
-            unsigned elementMask = elementMasks[i];
+            const PODVector<VertexElement>& srcElements = buffers[i]->GetElements();
+            bool isExisting = false;
 
-            if (elementMask == MASK_DEFAULT)
-                elementMask = buffers[i]->GetElementMask();
-            else
+            for (unsigned j = 0; j < srcElements.Size(); ++j)
             {
-                if ((buffers[i]->GetElementMask() & elementMask) != elementMask)
-                    return;
-            }
-
-            if (elementMask & MASK_OBJECTINDEX)
-                URHO3D_LOGWARNING("Object index attribute is not supported on Direct3D9 and will be ignored");
+                const VertexElement& srcElement = srcElements[j];
 
-            for (unsigned j = 0; j < ELEMENT_OBJECTINDEX; ++j)
-            {
-                VertexElement element = (VertexElement)j;
-
-                if (elementMask & (1 << j) && !(usedElementMask & (1 << j)))
+                if (srcElement.semantic_ == SEM_OBJECTINDEX)
                 {
-                    VertexDeclarationElement newElement;
-                    newElement.stream_ = i;
-                    newElement.element_ = element;
-                    newElement.offset_ = buffers[i]->GetElementOffset(element);
-                    usedElementMask |= 1 << j;
+                    URHO3D_LOGWARNING("Object index attribute is not supported on Direct3D9 and will be ignored");
+                    continue;
+                }
 
-                    elements.Push(newElement);
+                // Override existing element if necessary
+                for (unsigned k = 0; k < elements.Size(); ++k)
+                {
+                    if (elements[k].semantic_ == srcElements[j].semantic_ && elements[k].index_ == srcElements[j].index_)
+                    {
+                        isExisting = true;
+                        elements[k].streamIndex_ = i;
+                        elements[k].offset_ = srcElements[j].offset_;
+                        break;
+                    }
                 }
+
+                if (isExisting)
+                    continue;
+
+                VertexDeclarationElement element;
+                element.semantic_ = srcElement.semantic_;
+                element.type_ = srcElement.type_;
+                element.index_ = srcElement.index_;
+                element.streamIndex_ = i;
+                element.offset_ = srcElement.offset_;
+                elements.Push(element);
             }
         }
     }
@@ -157,44 +135,50 @@ VertexDeclaration::VertexDeclaration(Graphics* graphics, const PODVector<VertexB
     Create(graphics, elements);
 }
 
-VertexDeclaration::VertexDeclaration(Graphics* graphics, const Vector<SharedPtr<VertexBuffer> >& buffers,
-    const PODVector<unsigned>& elementMasks) :
+VertexDeclaration::VertexDeclaration(Graphics* graphics, const Vector<SharedPtr<VertexBuffer> >& buffers) :
     declaration_(0)
 {
-    unsigned usedElementMask = 0;
     PODVector<VertexDeclarationElement> elements;
 
     for (unsigned i = 0; i < buffers.Size(); ++i)
     {
         if (buffers[i])
         {
-            unsigned elementMask = elementMasks[i];
+            const PODVector<VertexElement>& srcElements = buffers[i]->GetElements();
+            bool isExisting = false;
 
-            if (elementMask == MASK_DEFAULT)
-                elementMask = buffers[i]->GetElementMask();
-            else
+            for (unsigned j = 0; j < srcElements.Size(); ++j)
             {
-                if ((buffers[i]->GetElementMask() & elementMask) != elementMask)
-                    return;
-            }
-
-            if (elementMask & MASK_OBJECTINDEX)
-                URHO3D_LOGWARNING("Object index attribute is not supported on Direct3D9 and will be ignored");
+                const VertexElement& srcElement = srcElements[j];
 
-            for (unsigned j = 0; j < MAX_VERTEX_ELEMENTS; ++j)
-            {
-                VertexElement element = (VertexElement)j;
-
-                if (elementMask & (1 << j) && !(usedElementMask & (1 << j)))
+                if (srcElement.semantic_ == SEM_OBJECTINDEX)
                 {
-                    VertexDeclarationElement newElement;
-                    newElement.stream_ = i;
-                    newElement.element_ = element;
-                    newElement.offset_ = buffers[i]->GetElementOffset(element);
-                    usedElementMask |= 1 << j;
+                    URHO3D_LOGWARNING("Object index attribute is not supported on Direct3D9 and will be ignored");
+                    continue;
+                }
 
-                    elements.Push(newElement);
+                // Override existing element if necessary
+                for (unsigned k = 0; k < elements.Size(); ++k)
+                {
+                    if (elements[k].semantic_ == srcElement.semantic_ && elements[k].index_ == srcElement.index_)
+                    {
+                        isExisting = true;
+                        elements[k].streamIndex_ = i;
+                        elements[k].offset_ = srcElement.offset_;
+                        break;
+                    }
                 }
+
+                if (isExisting)
+                    continue;
+
+                VertexDeclarationElement element;
+                element.semantic_ = srcElement.semantic_;
+                element.type_ = srcElement.type_;
+                element.index_ = srcElement.index_;
+                element.streamIndex_ = i;
+                element.offset_ = srcElement.offset_;
+                elements.Push(element);
             }
         }
     }
@@ -214,12 +198,12 @@ void VertexDeclaration::Create(Graphics* graphics, const PODVector<VertexDeclara
     D3DVERTEXELEMENT9* dest = elementArray;
     for (Vector<VertexDeclarationElement>::ConstIterator i = elements.Begin(); i != elements.End(); ++i)
     {
-        dest->Stream = (WORD)i->stream_;
+        dest->Stream = (WORD)i->streamIndex_;
         dest->Offset = (WORD)i->offset_;
-        dest->Type = d3dElementType[i->element_];
+        dest->Type = d3dElementType[i->type_];
         dest->Method = D3DDECLMETHOD_DEFAULT;
-        dest->Usage = d3dElementUsage[i->element_];
-        dest->UsageIndex = d3dElementUsageIndex[i->element_];
+        dest->Usage = d3dElementUsage[i->semantic_];
+        dest->UsageIndex = i->index_;
         dest++;
     }
 

+ 15 - 11
Source/Urho3D/Graphics/Direct3D9/D3D9VertexDeclaration.h

@@ -34,14 +34,18 @@ namespace Urho3D
 class Graphics;
 class VertexBuffer;
 
-/// Element in the vertex declaration.
+/// One element in a vertex declaration. In contrast to the VertexElement structure, takes into account the stream source index.
 struct VertexDeclarationElement
 {
-    /// Stream index.
-    unsigned stream_;
     /// Element type.
-    VertexElement element_;
-    /// Element offset.
+    VertexElementType type_;
+    /// Element semantic.
+    VertexElementSemantic semantic_;
+    /// Semantic index.
+    unsigned char index_;
+    /// Stream index.
+    unsigned char streamIndex_;
+    /// Byte offset.
     unsigned offset_;
 };
 
@@ -49,12 +53,12 @@ struct VertexDeclarationElement
 class URHO3D_API VertexDeclaration : public RefCounted
 {
 public:
-    /// Construct with vertex element mask.
-    VertexDeclaration(Graphics* graphics, unsigned elementMask);
-    /// Construct with vertex buffers and element masks to base declaration on.
-    VertexDeclaration(Graphics* graphics, const PODVector<VertexBuffer*>& buffers, const PODVector<unsigned>& elementMasks);
-    /// Construct with vertex buffers (shared pointer vector) and element masks to base declaration on.
-    VertexDeclaration(Graphics* graphics, const Vector<SharedPtr<VertexBuffer> >& buffers, const PODVector<unsigned>& elementMasks);
+    /// Construct with a single buffer's vertex element list.
+    VertexDeclaration(Graphics* graphics, const PODVector<VertexElement>& srcElements);
+    /// Construct with vertex buffers to base declaration on. Higher index buffers will override semantics on lower indices.
+    VertexDeclaration(Graphics* graphics, const PODVector<VertexBuffer*>& buffers);
+    /// Construct with vertex buffers (shared pointer vector) to base declaration on. Higher index buffers will override semantics on lower indices.
+    VertexDeclaration(Graphics* graphics, const Vector<SharedPtr<VertexBuffer> >& buffers);
     /// Destruct.
     ~VertexDeclaration();
 

+ 3 - 0
Source/Urho3D/Graphics/Drawable.cpp

@@ -447,6 +447,7 @@ void Drawable::RemoveFromOctree()
 
 bool WriteDrawablesToOBJ(PODVector<Drawable*> drawables, File* outputFile, bool asZUp, bool asRightHanded, bool writeLightmapUV)
 {
+/*
     // Must track indices independently to deal with potential mismatching of drawables vertex attributes (ie. one with UV, another without, then another with)
     unsigned currentPositionIndex = 1;
     unsigned currentUVIndex = 1;
@@ -642,6 +643,8 @@ bool WriteDrawablesToOBJ(PODVector<Drawable*> drawables, File* outputFile, bool
         }
     }
     return anythingWritten;
+*/
+    return true;
 }
 
 }

+ 51 - 110
Source/Urho3D/Graphics/Geometry.cpp

@@ -41,9 +41,7 @@ Geometry::Geometry(Context* context) :
     indexCount_(0),
     vertexStart_(0),
     vertexCount_(0),
-    positionBufferIndex_(M_MAX_UNSIGNED),
     rawVertexSize_(0),
-    rawElementMask_(0),
     rawIndexSize_(0),
     lodDistance_(0.0f)
 {
@@ -64,16 +62,11 @@ bool Geometry::SetNumVertexBuffers(unsigned num)
 
     unsigned oldSize = vertexBuffers_.Size();
     vertexBuffers_.Resize(num);
-    elementMasks_.Resize(num);
 
-    for (unsigned i = oldSize; i < num; ++i)
-        elementMasks_[i] = MASK_NONE;
-
-    GetPositionBufferIndex();
     return true;
 }
 
-bool Geometry::SetVertexBuffer(unsigned index, VertexBuffer* buffer, unsigned elementMask)
+bool Geometry::SetVertexBuffer(unsigned index, VertexBuffer* buffer)
 {
     if (index >= vertexBuffers_.Size())
     {
@@ -82,16 +75,6 @@ bool Geometry::SetVertexBuffer(unsigned index, VertexBuffer* buffer, unsigned el
     }
 
     vertexBuffers_[index] = buffer;
-
-    if (buffer)
-    {
-        if (elementMask == MASK_DEFAULT)
-            elementMasks_[index] = buffer->GetElementMask();
-        else
-            elementMasks_[index] = elementMask;
-    }
-
-    GetPositionBufferIndex();
     return true;
 }
 
@@ -172,11 +155,18 @@ void Geometry::SetLodDistance(float distance)
     lodDistance_ = distance;
 }
 
-void Geometry::SetRawVertexData(SharedArrayPtr<unsigned char> data, unsigned vertexSize, unsigned elementMask)
+void Geometry::SetRawVertexData(SharedArrayPtr<unsigned char> data, const PODVector<VertexElement>& elements)
 {
     rawVertexData_ = data;
-    rawVertexSize_ = vertexSize;
-    rawElementMask_ = elementMask;
+    rawVertexSize_ = VertexBuffer::GetVertexSize(elements);
+    rawElements_ = elements;
+}
+
+void Geometry::SetRawVertexData(SharedArrayPtr<unsigned char> data, unsigned elementMask)
+{
+    rawVertexData_ = data;
+    rawVertexSize_ = VertexBuffer::GetVertexSize(elementMask);
+    rawElements_ = VertexBuffer::GetElements(elementMask);
 }
 
 void Geometry::SetRawIndexData(SharedArrayPtr<unsigned char> data, unsigned indexSize)
@@ -190,12 +180,12 @@ void Geometry::Draw(Graphics* graphics)
     if (indexBuffer_ && indexCount_ > 0)
     {
         graphics->SetIndexBuffer(indexBuffer_);
-        graphics->SetVertexBuffers(vertexBuffers_, elementMasks_);
+        graphics->SetVertexBuffers(vertexBuffers_);
         graphics->Draw(primitiveType_, indexStart_, indexCount_, vertexStart_, vertexCount_);
     }
     else if (vertexCount_ > 0)
     {
-        graphics->SetVertexBuffers(vertexBuffers_, elementMasks_);
+        graphics->SetVertexBuffers(vertexBuffers_);
         graphics->Draw(primitiveType_, vertexStart_, vertexCount_);
     }
 }
@@ -205,11 +195,6 @@ VertexBuffer* Geometry::GetVertexBuffer(unsigned index) const
     return index < vertexBuffers_.Size() ? vertexBuffers_[index] : (VertexBuffer*)0;
 }
 
-unsigned Geometry::GetVertexElementMask(unsigned index) const
-{
-    return index < elementMasks_.Size() ? elementMasks_[index] : 0;
-}
-
 unsigned short Geometry::GetBufferHash() const
 {
     unsigned short hash = 0;
@@ -227,36 +212,25 @@ unsigned short Geometry::GetBufferHash() const
 }
 
 void Geometry::GetRawData(const unsigned char*& vertexData, unsigned& vertexSize, const unsigned char*& indexData,
-    unsigned& indexSize, unsigned& elementMask) const
+    unsigned& indexSize, const PODVector<VertexElement>*& elements) const
 {
     if (rawVertexData_)
     {
         vertexData = rawVertexData_;
         vertexSize = rawVertexSize_;
-        elementMask = rawElementMask_;
+        elements = &rawElements_;
+    }
+    else if (vertexBuffers_.Size() && vertexBuffers_[0])
+    {
+        vertexData = vertexBuffers_[0]->GetShadowData();
+        vertexSize = vertexBuffers_[0]->GetVertexSize();
+        elements = &vertexBuffers_[0]->GetElements();
     }
     else
     {
-        if (positionBufferIndex_ < vertexBuffers_.Size() && vertexBuffers_[positionBufferIndex_])
-        {
-            vertexData = vertexBuffers_[positionBufferIndex_]->GetShadowData();
-            if (vertexData)
-            {
-                vertexSize = vertexBuffers_[positionBufferIndex_]->GetVertexSize();
-                elementMask = vertexBuffers_[positionBufferIndex_]->GetElementMask();
-            }
-            else
-            {
-                vertexSize = 0;
-                elementMask = 0;
-            }
-        }
-        else
-        {
-            vertexData = 0;
-            vertexSize = 0;
-            elementMask = 0;
-        }
+        vertexData = 0;
+        vertexSize = 0;
+        elements = 0;
     }
 
     if (rawIndexData_)
@@ -283,36 +257,25 @@ void Geometry::GetRawData(const unsigned char*& vertexData, unsigned& vertexSize
 }
 
 void Geometry::GetRawDataShared(SharedArrayPtr<unsigned char>& vertexData, unsigned& vertexSize,
-    SharedArrayPtr<unsigned char>& indexData, unsigned& indexSize, unsigned& elementMask) const
+    SharedArrayPtr<unsigned char>& indexData, unsigned& indexSize, const PODVector<VertexElement>*& elements) const
 {
     if (rawVertexData_)
     {
         vertexData = rawVertexData_;
         vertexSize = rawVertexSize_;
-        elementMask = rawElementMask_;
+        elements = &rawElements_;
+    }
+    else if (vertexBuffers_.Size() && vertexBuffers_[0])
+    {
+        vertexData = vertexBuffers_[0]->GetShadowDataShared();
+        vertexSize = vertexBuffers_[0]->GetVertexSize();
+        elements = &vertexBuffers_[0]->GetElements();
     }
     else
     {
-        if (positionBufferIndex_ < vertexBuffers_.Size() && vertexBuffers_[positionBufferIndex_])
-        {
-            vertexData = vertexBuffers_[positionBufferIndex_]->GetShadowDataShared();
-            if (vertexData)
-            {
-                vertexSize = vertexBuffers_[positionBufferIndex_]->GetVertexSize();
-                elementMask = vertexBuffers_[positionBufferIndex_]->GetElementMask();
-            }
-            else
-            {
-                vertexSize = 0;
-                elementMask = 0;
-            }
-        }
-        else
-        {
-            vertexData = 0;
-            vertexSize = 0;
-            elementMask = 0;
-        }
+        vertexData = 0;
+        vertexSize = 0;
+        elements = 0;
     }
 
     if (rawIndexData_)
@@ -344,32 +307,25 @@ float Geometry::GetHitDistance(const Ray& ray, Vector3* outNormal, Vector2* outU
     const unsigned char* indexData;
     unsigned vertexSize;
     unsigned indexSize;
-    unsigned elementMask;
-    unsigned uvOffset = 0;
+    const PODVector<VertexElement>* elements;
 
-    GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
+    GetRawData(vertexData, vertexSize, indexData, indexSize, elements);
+    
+    if (!vertexData || !elements || VertexBuffer::GetElementOffset(*elements, TYPE_VECTOR3, SEM_POSITION) != 0)
+        return M_INFINITY;
 
-    if (vertexData)
+    unsigned uvOffset = VertexBuffer::GetElementOffset(*elements, TYPE_VECTOR2, SEM_TEXCOORD);
+    
+    if (outUV && uvOffset == M_MAX_UNSIGNED)
     {
-        if (outUV)
-        {
-            if ((elementMask & MASK_TEXCOORD1) == 0)
-            {
-                // requested UV output, but no texture data in vertex buffer
-                URHO3D_LOGWARNING("Illegal GetHitDistance call: UV return requested on vertex buffer without UV coords");
-                *outUV = Vector2::ZERO;
-                outUV = 0;
-            }
-            else
-                uvOffset = VertexBuffer::GetElementOffset(elementMask, ELEMENT_TEXCOORD1);
-        }
-
-        return indexData ? ray.HitDistance(vertexData, vertexSize, indexData, indexSize, indexStart_, indexCount_, outNormal, outUV,
-            uvOffset) :
-               ray.HitDistance(vertexData, vertexSize, vertexStart_, vertexCount_, outNormal, outUV, uvOffset);
+        // requested UV output, but no texture data in vertex buffer
+        URHO3D_LOGWARNING("Illegal GetHitDistance call: UV return requested on vertex buffer without UV coords");
+        *outUV = Vector2::ZERO;
+        outUV = 0;
     }
 
-    return M_INFINITY;
+    return indexData ? ray.HitDistance(vertexData, vertexSize, indexData, indexSize, indexStart_, indexCount_, outNormal, outUV,
+        uvOffset) : ray.HitDistance(vertexData, vertexSize, vertexStart_, vertexCount_, outNormal, outUV, uvOffset);
 }
 
 bool Geometry::IsInside(const Ray& ray) const
@@ -378,27 +334,12 @@ bool Geometry::IsInside(const Ray& ray) const
     const unsigned char* indexData;
     unsigned vertexSize;
     unsigned indexSize;
-    unsigned elementMask;
+    const PODVector<VertexElement>* elements;
 
-    GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
+    GetRawData(vertexData, vertexSize, indexData, indexSize, elements);
 
     return vertexData ? (indexData ? ray.InsideGeometry(vertexData, vertexSize, indexData, indexSize, indexStart_, indexCount_) :
                          ray.InsideGeometry(vertexData, vertexSize, vertexStart_, vertexCount_)) : false;
 }
 
-void Geometry::GetPositionBufferIndex()
-{
-    for (unsigned i = 0; i < vertexBuffers_.Size(); ++i)
-    {
-        if (vertexBuffers_[i] && vertexBuffers_[i]->GetElementMask() & MASK_POSITION)
-        {
-            positionBufferIndex_ = i;
-            return;
-        }
-    }
-
-    // No vertex buffer with positions
-    positionBufferIndex_ = M_MAX_UNSIGNED;
-}
-
 }

+ 17 - 28
Source/Urho3D/Graphics/Geometry.h

@@ -45,10 +45,10 @@ public:
     /// Destruct.
     virtual ~Geometry();
 
-    /// Set number of vertex buffer.
+    /// Set number of vertex buffers.
     bool SetNumVertexBuffers(unsigned num);
     /// Set a vertex buffer by index.
-    bool SetVertexBuffer(unsigned index, VertexBuffer* buffer, unsigned elementMask = MASK_DEFAULT);
+    bool SetVertexBuffer(unsigned index, VertexBuffer* buffer);
     /// Set the index buffer.
     void SetIndexBuffer(IndexBuffer* buffer);
     /// Set the draw range.
@@ -59,7 +59,9 @@ public:
     /// Set the LOD distance.
     void SetLodDistance(float distance);
     /// Override raw vertex data to be returned for CPU-side operations.
-    void SetRawVertexData(SharedArrayPtr<unsigned char> data, unsigned vertexSize, unsigned elementMask);
+    void SetRawVertexData(SharedArrayPtr<unsigned char> data, const PODVector<VertexElement>& elements);
+    /// Override raw vertex data to be returned for CPU-side operations using a legacy vertex bitmask.
+    void SetRawVertexData(SharedArrayPtr<unsigned char> data, unsigned elementMask);
     /// Override raw index data to be returned for CPU-side operations.
     void SetRawIndexData(SharedArrayPtr<unsigned char> data, unsigned indexSize);
     /// Draw.
@@ -68,16 +70,11 @@ public:
     /// Return all vertex buffers.
     const Vector<SharedPtr<VertexBuffer> >& GetVertexBuffers() const { return vertexBuffers_; }
 
-    /// Return vertex element masks.
-    const PODVector<unsigned>& GetVertexElementMasks() const { return elementMasks_; }
-
     /// Return number of vertex buffers.
     unsigned GetNumVertexBuffers() const { return vertexBuffers_.Size(); }
 
     /// Return vertex buffer by index.
     VertexBuffer* GetVertexBuffer(unsigned index) const;
-    /// Return vertex element mask by index.
-    unsigned GetVertexElementMask(unsigned index) const;
 
     /// Return the index buffer.
     IndexBuffer* GetIndexBuffer() const { return indexBuffer_; }
@@ -102,12 +99,11 @@ public:
 
     /// Return buffers' combined hash value for state sorting.
     unsigned short GetBufferHash() const;
-    /// Return raw vertex and index data for CPU operations, or null pointers if not available.
-    void GetRawData(const unsigned char*& vertexData, unsigned& vertexSize, const unsigned char*& indexData, unsigned& indexSize,
-        unsigned& elementMask) const;
-    /// Return raw vertex and index data for CPU operations, or null pointers if not available.
+    /// Return raw vertex and index data for CPU operations, or null pointers if not available. Will return data of the first vertex buffer if override data not set.
+    void GetRawData(const unsigned char*& vertexData, unsigned& vertexSize, const unsigned char*& indexData, unsigned& indexSize, const PODVector<VertexElement>*& elements) const;
+    /// Return raw vertex and index data for CPU operations, or null pointers if not available. Will return data of the first vertex buffer if override data not set.
     void GetRawDataShared(SharedArrayPtr<unsigned char>& vertexData, unsigned& vertexSize, SharedArrayPtr<unsigned char>& indexData,
-        unsigned& indexSize, unsigned& elementMask) const;
+        unsigned& indexSize, const PODVector<VertexElement>*& elements) const;
     /// Return ray hit distance or infinity if no hit. Requires raw data to be set. Optionally return hit normal and hit uv coordinates at intersect point.
     float GetHitDistance(const Ray& ray, Vector3* outNormal = 0, Vector2* outUV = 0) const;
     /// Return whether or not the ray is inside geometry.
@@ -117,19 +113,10 @@ public:
     bool IsEmpty() const { return indexCount_ == 0 && vertexCount_ == 0; }
 
 private:
-    /// Locate vertex buffer with position data.
-    void GetPositionBufferIndex();
-
     /// Vertex buffers.
     Vector<SharedPtr<VertexBuffer> > vertexBuffers_;
-    /// Vertex element masks.
-    PODVector<unsigned> elementMasks_;
     /// Index buffer.
     SharedPtr<IndexBuffer> indexBuffer_;
-    /// Raw vertex data override.
-    SharedArrayPtr<unsigned char> rawVertexData_;
-    /// Raw index data override.
-    SharedArrayPtr<unsigned char> rawIndexData_;
     /// Primitive type.
     PrimitiveType primitiveType_;
     /// Start index.
@@ -140,16 +127,18 @@ private:
     unsigned vertexStart_;
     /// Number of used vertices.
     unsigned vertexCount_;
-    /// Index of vertex buffer with position data.
-    unsigned positionBufferIndex_;
+    /// LOD distance.
+    float lodDistance_;
+    /// Raw vertex data elements.
+    PODVector<VertexElement> rawElements_;
+    /// Raw vertex data override.
+    SharedArrayPtr<unsigned char> rawVertexData_;
+    /// Raw index data override.
+    SharedArrayPtr<unsigned char> rawIndexData_;
     /// Raw vertex data override size.
     unsigned rawVertexSize_;
-    /// Raw vertex data override element mask.
-    unsigned rawElementMask_;
     /// Raw index data override size.
     unsigned rawIndexSize_;
-    /// LOD distance.
-    float lodDistance_;
 };
 
 }

+ 65 - 6
Source/Urho3D/Graphics/GraphicsDefs.h

@@ -124,8 +124,8 @@ enum LockState
     LOCK_SCRATCH
 };
 
-/// Vertex elements.
-enum VertexElement
+/// Hardcoded legacy vertex elements.
+enum LegacyVertexElement
 {
     ELEMENT_POSITION = 0,
     ELEMENT_NORMAL,
@@ -142,7 +142,68 @@ enum VertexElement
     ELEMENT_INSTANCEMATRIX3,
     // Custom 32-bit integer object index. Due to API limitations, not supported on D3D9
     ELEMENT_OBJECTINDEX,
-    MAX_VERTEX_ELEMENTS
+    MAX_LEGACY_VERTEX_ELEMENTS
+};
+
+/// Arbitrary vertex declaration element datatypes.
+enum VertexElementType
+{
+    TYPE_INT = 0,
+    TYPE_FLOAT,
+    TYPE_VECTOR2,
+    TYPE_VECTOR3,
+    TYPE_VECTOR4,
+    TYPE_UBYTE4,
+    TYPE_UBYTE4_NORM
+};
+
+/// Arbitrary vertex declaration element semantics.
+enum VertexElementSemantic
+{
+    SEM_POSITION = 0,
+    SEM_NORMAL,
+    SEM_BINORMAL,
+    SEM_TANGENT,
+    SEM_TEXCOORD,
+    SEM_COLOR,
+    SEM_BLENDWEIGHTS,
+    SEM_BLENDINDICES,
+    SEM_OBJECTINDEX
+};
+
+/// Vertex element description for arbitrary vertex declarations.
+struct URHO3D_API VertexElement
+{
+    /// Default-construct.
+    VertexElement() :
+        type_(TYPE_VECTOR3),
+        semantic_(SEM_POSITION),
+        index_(0),
+        perInstance_(false),
+        offset_(0)
+    {
+    }
+
+    /// Construct with type, semantic, index and whether is per-instance data.
+    VertexElement(VertexElementType type, VertexElementSemantic semantic, unsigned char index = 0, bool perInstance = false) :
+        type_(type),
+        semantic_(semantic),
+        index_(index),
+        perInstance_(perInstance),
+        offset_(0)
+    {
+    }
+
+    /// Data type of element.
+    VertexElementType type_;
+    /// Semantic of element.
+    VertexElementSemantic semantic_;
+    /// Semantic index of element, for example multi-texcoords.
+    unsigned char index_;
+    /// Per-instance flag.
+    bool perInstance_;
+    /// Offset of element from vertex start. Filled by VertexBuffer once the vertex declaration is built.
+    unsigned offset_;
 };
 
 /// Texture filtering mode.
@@ -289,7 +350,6 @@ enum ShadowQuality
     SHADOWQUALITY_BLUR_VSM
 };
 
-
 // Inbuilt shader parameters.
 extern URHO3D_API const StringHash VSP_AMBIENTSTARTCOLOR;
 extern URHO3D_API const StringHash VSP_AMBIENTENDCOLOR;
@@ -353,6 +413,7 @@ static const unsigned CLEAR_COLOR = 0x1;
 static const unsigned CLEAR_DEPTH = 0x2;
 static const unsigned CLEAR_STENCIL = 0x4;
 
+// Legacy vertex element bitmasks.
 static const unsigned MASK_NONE = 0x0;
 static const unsigned MASK_POSITION = 0x1;
 static const unsigned MASK_NORMAL = 0x2;
@@ -368,8 +429,6 @@ static const unsigned MASK_INSTANCEMATRIX1 = 0x400;
 static const unsigned MASK_INSTANCEMATRIX2 = 0x800;
 static const unsigned MASK_INSTANCEMATRIX3 = 0x1000;
 static const unsigned MASK_OBJECTINDEX = 0x2000;
-static const unsigned MASK_DEFAULT = 0xffffffff;
-static const unsigned NO_ELEMENT = 0xffffffff;
 
 static const int MAX_RENDERTARGETS = 4;
 static const int MAX_VERTEX_STREAMS = 4;

+ 1 - 2
Source/Urho3D/Graphics/Model.cpp

@@ -643,8 +643,7 @@ SharedPtr<Model> Model::Clone(const String& cloneName) const
                 unsigned numVbs = origGeometry->GetNumVertexBuffers();
                 for (unsigned k = 0; k < numVbs; ++k)
                 {
-                    cloneGeometry->SetVertexBuffer(k, vbMapping[origGeometry->GetVertexBuffer(k)],
-                        origGeometry->GetVertexElementMask(k));
+                    cloneGeometry->SetVertexBuffer(k, vbMapping[origGeometry->GetVertexBuffer(k)]);
                 }
                 cloneGeometry->SetDrawRange(origGeometry->GetPrimitiveType(), origGeometry->GetIndexStart(),
                     origGeometry->GetIndexCount(), origGeometry->GetVertexStart(), origGeometry->GetVertexCount(), false);

+ 4 - 3
Source/Urho3D/Graphics/StaticModel.cpp

@@ -31,6 +31,7 @@
 #include "../Graphics/Material.h"
 #include "../Graphics/OcclusionBuffer.h"
 #include "../Graphics/OctreeQuery.h"
+#include "../Graphics/VertexBuffer.h"
 #include "../IO/FileSystem.h"
 #include "../IO/Log.h"
 #include "../Resource/ResourceCache.h"
@@ -210,11 +211,11 @@ bool StaticModel::DrawOcclusion(OcclusionBuffer* buffer)
         unsigned vertexSize;
         const unsigned char* indexData;
         unsigned indexSize;
-        unsigned elementMask;
+        const PODVector<VertexElement>* elements;
 
-        geometry->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
+        geometry->GetRawData(vertexData, vertexSize, indexData, indexSize, elements);
         // Check for valid geometry data
-        if (!vertexData || !indexData)
+        if (!vertexData || !indexData || !elements || VertexBuffer::GetElementOffset(*elements, TYPE_VECTOR3, SEM_POSITION) != 0)
             continue;
 
         unsigned indexStart = geometry->GetIndexStart();

+ 4 - 3
Source/Urho3D/Graphics/StaticModelGroup.cpp

@@ -30,6 +30,7 @@
 #include "../Graphics/OcclusionBuffer.h"
 #include "../Graphics/OctreeQuery.h"
 #include "../Graphics/StaticModelGroup.h"
+#include "../Graphics/VertexBuffer.h"
 #include "../Scene/Scene.h"
 
 #include "../DebugNew.h"
@@ -246,11 +247,11 @@ bool StaticModelGroup::DrawOcclusion(OcclusionBuffer* buffer)
             unsigned vertexSize;
             const unsigned char* indexData;
             unsigned indexSize;
-            unsigned elementMask;
+            const PODVector<VertexElement>* elements;
 
-            geometry->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
+            geometry->GetRawData(vertexData, vertexSize, indexData, indexSize, elements);
             // Check for valid geometry data
-            if (!vertexData || !indexData)
+            if (!vertexData || !indexData || !elements || VertexBuffer::GetElementOffset(*elements, TYPE_VECTOR3, SEM_POSITION) != 0)
                 continue;
 
             unsigned indexStart = geometry->GetIndexStart();

+ 3 - 3
Source/Urho3D/Graphics/Terrain.cpp

@@ -590,13 +590,13 @@ void Terrain::CreatePatchGeometry(TerrainPatch* patch)
 
         geometry->SetIndexBuffer(indexBuffer_);
         geometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[0].first_, drawRanges_[0].second_, false);
-        geometry->SetRawVertexData(cpuVertexData, sizeof(Vector3), MASK_POSITION);
+        geometry->SetRawVertexData(cpuVertexData, MASK_POSITION);
         maxLodGeometry->SetIndexBuffer(indexBuffer_);
         maxLodGeometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[0].first_, drawRanges_[0].second_, false);
-        maxLodGeometry->SetRawVertexData(cpuVertexData, sizeof(Vector3), MASK_POSITION);
+        maxLodGeometry->SetRawVertexData(cpuVertexData, MASK_POSITION);
         occlusionGeometry->SetIndexBuffer(indexBuffer_);
         occlusionGeometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[occlusionDrawRange].first_, drawRanges_[occlusionDrawRange].second_, false);
-        occlusionGeometry->SetRawVertexData(occlusionCpuVertexData, sizeof(Vector3), MASK_POSITION);
+        occlusionGeometry->SetRawVertexData(occlusionCpuVertexData, MASK_POSITION);
     }
 
     patch->ResetLod();

+ 7 - 7
Source/Urho3D/Graphics/TerrainPatch.cpp

@@ -54,9 +54,9 @@ TerrainPatch::TerrainPatch(Context* context) :
     coordinates_(IntVector2::ZERO),
     lodLevel_(0)
 {
-    geometry_->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
-    maxLodGeometry_->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
-    occlusionGeometry_->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT);
+    geometry_->SetVertexBuffer(0, vertexBuffer_);
+    maxLodGeometry_->SetVertexBuffer(0, vertexBuffer_);
+    occlusionGeometry_->SetVertexBuffer(0, vertexBuffer_);
 
     batches_.Resize(1);
     batches_[0].geometry_ = geometry_;
@@ -196,12 +196,12 @@ bool TerrainPatch::DrawOcclusion(OcclusionBuffer* buffer)
     unsigned vertexSize;
     const unsigned char* indexData;
     unsigned indexSize;
-    unsigned elementMask;
+    const PODVector<VertexElement>* elements;
 
-    occlusionGeometry_->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
+    occlusionGeometry_->GetRawData(vertexData, vertexSize, indexData, indexSize, elements);
     // Check for valid geometry data
-    if (!vertexData || !indexData)
-        return true;
+    if (!vertexData || !indexData || !elements || VertexBuffer::GetElementOffset(*elements, TYPE_VECTOR3, SEM_POSITION) != 0)
+        return false;
 
     // Draw and check for running out of triangles
     return buffer->AddTriangles(node_->GetWorldTransform(), vertexData, vertexSize, indexData, indexSize, occlusionGeometry_->GetIndexStart(),

+ 4 - 3
Source/Urho3D/Navigation/NavigationMesh.cpp

@@ -30,6 +30,7 @@
 #include "../Graphics/Model.h"
 #include "../Graphics/StaticModel.h"
 #include "../Graphics/TerrainPatch.h"
+#include "../Graphics/VertexBuffer.h"
 #include "../IO/Log.h"
 #include "../IO/MemoryBuffer.h"
 #include "../Navigation/CrowdAgent.h"
@@ -1081,10 +1082,10 @@ void NavigationMesh::AddTriMeshGeometry(NavBuildData* build, Geometry* geometry,
     const unsigned char* indexData;
     unsigned vertexSize;
     unsigned indexSize;
-    unsigned elementMask;
+    const PODVector<VertexElement>* elements;
 
-    geometry->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
-    if (!vertexData || !indexData || (elementMask & MASK_POSITION) == 0)
+    geometry->GetRawData(vertexData, vertexSize, indexData, indexSize, elements);
+    if (!vertexData || !indexData || !elements || VertexBuffer::GetElementOffset(*elements, TYPE_VECTOR3, SEM_POSITION) != 0)
         return;
 
     unsigned srcIndexStart = geometry->GetIndexStart();

+ 11 - 11
Source/Urho3D/Physics/CollisionShape.cpp

@@ -103,10 +103,10 @@ public:
             SharedArrayPtr<unsigned char> indexData;
             unsigned vertexSize;
             unsigned indexSize;
-            unsigned elementMask;
+            const PODVector<VertexElement>* elements;
 
-            geometry->GetRawDataShared(vertexData, vertexSize, indexData, indexSize, elementMask);
-            if (!vertexData || !indexData)
+            geometry->GetRawDataShared(vertexData, vertexSize, indexData, indexSize, elements);
+            if (!vertexData || !indexData || !elements || VertexBuffer::GetElementOffset(*elements, TYPE_VECTOR3, SEM_POSITION) != 0)
             {
                 URHO3D_LOGWARNING("Skipping geometry with no CPU-side geometry data for triangle mesh collision");
                 continue;
@@ -237,8 +237,8 @@ ConvexData::ConvexData(Model* model, unsigned lodLevel)
 
     for (unsigned i = 0; i < numGeometries; ++i)
     {
-        Geometry* geom = model->GetGeometry(i, lodLevel);
-        if (!geom)
+        Geometry* geometry = model->GetGeometry(i, lodLevel);
+        if (!geometry)
         {
             URHO3D_LOGWARNING("Skipping null geometry for convex hull collision");
             continue;
@@ -248,17 +248,17 @@ ConvexData::ConvexData(Model* model, unsigned lodLevel)
         const unsigned char* indexData;
         unsigned vertexSize;
         unsigned indexSize;
-        unsigned elementMask;
+        const PODVector<VertexElement>* elements;
 
-        geom->GetRawData(vertexData, vertexSize, indexData, indexSize, elementMask);
-        if (!vertexData)
+        geometry->GetRawData(vertexData, vertexSize, indexData, indexSize, elements);
+        if (!vertexData || VertexBuffer::GetElementOffset(*elements, TYPE_VECTOR3, SEM_POSITION) != 0)
         {
-            URHO3D_LOGWARNING("Skipping geometry with no CPU-side geometry data for convex hull collision");
+            URHO3D_LOGWARNING("Skipping geometry with no or unsuitable CPU-side geometry data for convex hull collision");
             continue;
         }
 
-        unsigned vertexStart = geom->GetVertexStart();
-        unsigned vertexCount = geom->GetVertexCount();
+        unsigned vertexStart = geometry->GetVertexStart();
+        unsigned vertexCount = geometry->GetVertexCount();
 
         // Copy vertex data
         for (unsigned j = 0; j < vertexCount; ++j)

+ 1 - 1
Source/Urho3D/UI/Text3D.cpp

@@ -537,7 +537,7 @@ void Text3D::UpdateTextMaterials(bool forceUpdate)
         if (!geometries_[i])
         {
             Geometry* geometry = new Geometry(context_);
-            geometry->SetVertexBuffer(0, vertexBuffer_, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1);
+            geometry->SetVertexBuffer(0, vertexBuffer_);
             batches_[i].geometry_ = geometries_[i] = geometry;
         }
 

+ 1 - 1
Source/Urho3D/Urho2D/Renderer2D.cpp

@@ -510,7 +510,7 @@ void Renderer2D::AddViewBatch(ViewBatchInfo2D& viewBatchInfo, Material* material
     {
         SharedPtr<Geometry> geometry(new Geometry(context_));
         geometry->SetIndexBuffer(indexBuffer_);
-        geometry->SetVertexBuffer(0, viewBatchInfo.vertexBuffer_, MASK_VERTEX2D);
+        geometry->SetVertexBuffer(0, viewBatchInfo.vertexBuffer_);
 
         viewBatchInfo.geometries_.Push(geometry);
     }