Browse Source

New model format that supports arbitrary vertex declarations.

Lasse Öörni 9 years ago
parent
commit
31f8ff69ec
3 changed files with 56 additions and 21 deletions
  1. 7 2
      Docs/Reference.dox
  2. 47 17
      Source/Urho3D/Graphics/Model.cpp
  3. 2 2
      Source/Urho3D/Graphics/Model.h

+ 7 - 2
Docs/Reference.dox

@@ -3139,16 +3139,21 @@ Urho3D tries to use existing file formats whenever possible, and define custom f
 \verbatim
 Model geometry and vertex morph data
 
-byte[4]    Identifier "UMDL"
+byte[4]    Identifier "UMDL" or "UMD2"
 uint       Number of vertex buffers
 
   For each vertex buffer:
   uint       Vertex count
-  uint       Vertex element mask (determines vertex size)
+  uint       Legacy vertex element mask (determines vertex size)
   uint       Morphable vertex range start index
   uint       Morphable vertex count
   byte[]     Vertex data (vertex count * vertex size)
 
+  In "UMD2" format, the legacy vertex element mask is replaced with the following:
+  uint       Vertex element count
+  uint[]     Descriptions for each vertex element, where
+             bits 0-7 = element data type, bits 8-15 = semantic, bits 16-23 = semantic index
+
 uint    Number of index buffers
 
   For each index buffer:

+ 47 - 17
Source/Urho3D/Graphics/Model.cpp

@@ -30,6 +30,7 @@
 #include "../Graphics/Graphics.h"
 #include "../Graphics/VertexBuffer.h"
 #include "../IO/Log.h"
+#include "../IO/File.h"
 
 #include "../DebugNew.h"
 
@@ -73,12 +74,15 @@ void Model::RegisterObject(Context* context)
 bool Model::BeginLoad(Deserializer& source)
 {
     // Check ID
-    if (source.ReadFileID() != "UMDL")
+    String fileID = source.ReadFileID();
+    if (fileID != "UMDL" && fileID != "UMD2")
     {
         URHO3D_LOGERROR(source.GetName() + " is not a valid model file");
         return false;
     }
 
+    bool hasVertexDeclarations = (fileID == "UMD2");
+
     geometries_.Clear();
     geometryBoneMappings_.Clear();
     geometryCenters_.Clear();
@@ -97,35 +101,53 @@ bool Model::BeginLoad(Deserializer& source)
     loadVBData_.Resize(numVertexBuffers);
     for (unsigned i = 0; i < numVertexBuffers; ++i)
     {
-        unsigned vertexCount = source.ReadUInt();
-        unsigned elementMask = source.ReadUInt();
+        VertexBufferDesc& desc = loadVBData_[i];
+
+        desc.vertexCount_ = source.ReadUInt();
+        if (!hasVertexDeclarations)
+        {
+            unsigned elementMask = source.ReadUInt();
+            desc.vertexElements_ = VertexBuffer::GetElements(elementMask);
+        }
+        else
+        {
+            desc.vertexElements_.Clear();
+            unsigned numElements = source.ReadUInt();
+            for (unsigned j = 0; j < numElements; ++j)
+            {
+                unsigned elementDesc = source.ReadUInt();
+                VertexElementType type = (VertexElementType)(elementDesc & 0xff);
+                VertexElementSemantic semantic = (VertexElementSemantic)((elementDesc >> 8) & 0xff);
+                unsigned char index = (unsigned char)((elementDesc >> 16) & 0xff);
+                desc.vertexElements_.Push(VertexElement(type, semantic, index));
+            }
+        }
+
         morphRangeStarts_[i] = source.ReadUInt();
         morphRangeCounts_[i] = source.ReadUInt();
 
         SharedPtr<VertexBuffer> buffer(new VertexBuffer(context_));
-        unsigned vertexSize = VertexBuffer::GetVertexSize(elementMask);
+        unsigned vertexSize = VertexBuffer::GetVertexSize(desc.vertexElements_);
+        desc.dataSize_ = desc.vertexCount_ * vertexSize;
 
         // Prepare vertex buffer data to be uploaded during EndLoad()
         if (async)
         {
-            loadVBData_[i].vertexCount_ = vertexCount;
-            loadVBData_[i].elementMask_ = elementMask;
-            loadVBData_[i].dataSize_ = vertexCount * vertexSize;
-            loadVBData_[i].data_ = new unsigned char[loadVBData_[i].dataSize_];
-            source.Read(loadVBData_[i].data_.Get(), loadVBData_[i].dataSize_);
+            desc.data_ = new unsigned char[desc.dataSize_];
+            source.Read(desc.data_.Get(), desc.dataSize_);
         }
         else
         {
             // If not async loading, use locking to avoid extra allocation & copy
-            loadVBData_[i].data_.Reset(); // Make sure no previous data
+            desc.data_.Reset(); // Make sure no previous data
             buffer->SetShadowed(true);
-            buffer->SetSize(vertexCount, elementMask);
-            void* dest = buffer->Lock(0, vertexCount);
-            source.Read(dest, vertexCount * vertexSize);
+            buffer->SetSize(desc.vertexCount_, desc.vertexElements_);
+            void* dest = buffer->Lock(0, desc.vertexCount_);
+            source.Read(dest, desc.vertexCount_ * vertexSize);
             buffer->Unlock();
         }
 
-        memoryUse += sizeof(VertexBuffer) + vertexCount * vertexSize;
+        memoryUse += sizeof(VertexBuffer) + desc.vertexCount_ * vertexSize;
         vertexBuffers_.Push(buffer);
     }
 
@@ -298,7 +320,7 @@ bool Model::EndLoad()
         if (desc.data_)
         {
             buffer->SetShadowed(true);
-            buffer->SetSize(desc.vertexCount_, desc.elementMask_);
+            buffer->SetSize(desc.vertexCount_, desc.vertexElements_);
             buffer->SetData(desc.data_.Get());
         }
     }
@@ -338,7 +360,7 @@ bool Model::EndLoad()
 bool Model::Save(Serializer& dest) const
 {
     // Write ID
-    if (!dest.WriteFileID("UMDL"))
+    if (!dest.WriteFileID("UMD2"))
         return false;
 
     // Write vertex buffers
@@ -347,7 +369,15 @@ bool Model::Save(Serializer& dest) const
     {
         VertexBuffer* buffer = vertexBuffers_[i];
         dest.WriteUInt(buffer->GetVertexCount());
-        dest.WriteUInt(buffer->GetElementMask());
+        const PODVector<VertexElement>& elements = buffer->GetElements();
+        dest.WriteUInt(elements.Size());
+        for (unsigned j = 0; j < elements.Size(); ++j)
+        {
+            unsigned elementDesc = ((unsigned)elements[j].type_) |
+                (((unsigned)elements[j].semantic_) << 8) |
+                (((unsigned)elements[j].index_) << 16);
+            dest.WriteUInt(elementDesc);
+        }
         dest.WriteUInt(morphRangeStarts_[i]);
         dest.WriteUInt(morphRangeCounts_[i]);
         dest.Write(buffer->GetShadowData(), buffer->GetVertexCount() * buffer->GetVertexSize());

+ 2 - 2
Source/Urho3D/Graphics/Model.h

@@ -68,8 +68,8 @@ struct VertexBufferDesc
 {
     /// Vertex count.
     unsigned vertexCount_;
-    /// Element mask.
-    unsigned elementMask_;
+    /// Vertex declaration.
+    PODVector<VertexElement> vertexElements_;
     /// Vertex data size.
     unsigned dataSize_;
     /// Vertex data.