0031332: Data Exchange - RWGltf_CafReader ignores bufferView.byteStride within glTF 2.0
authorkgv <kgv@opencascade.com>
Wed, 29 Jan 2020 17:48:24 +0000 (20:48 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 30 Jan 2020 15:55:55 +0000 (18:55 +0300)
RWGltf_GltfJsonParser::gltfParseBufferView() now reads byteStride parameter within bufferView.

src/RWGltf/RWGltf_GltfJsonParser.cxx
tests/de_mesh/gltf_read/boxinterleaved [new file with mode: 0644]

index 89feb12..6c3b78c 100644 (file)
@@ -1522,7 +1522,7 @@ bool RWGltf_GltfJsonParser::gltfParseAccessor (const Handle(RWGltf_GltfLatePrimi
   const RWGltf_JsonValue* aTypeStr        = findObjectMember (theAccessor, "type");
   const RWGltf_JsonValue* aBufferViewName = findObjectMember (theAccessor, "bufferView");
   const RWGltf_JsonValue* aByteOffset     = findObjectMember (theAccessor, "byteOffset");
   const RWGltf_JsonValue* aTypeStr        = findObjectMember (theAccessor, "type");
   const RWGltf_JsonValue* aBufferViewName = findObjectMember (theAccessor, "bufferView");
   const RWGltf_JsonValue* aByteOffset     = findObjectMember (theAccessor, "byteOffset");
-  const RWGltf_JsonValue* aByteStride     = findObjectMember (theAccessor, "byteStride");
+  const RWGltf_JsonValue* aByteStride     = findObjectMember (theAccessor, "byteStride"); // byteStride was part of bufferView in glTF 1.0
   const RWGltf_JsonValue* aCompType       = findObjectMember (theAccessor, "componentType");
   const RWGltf_JsonValue* aCount          = findObjectMember (theAccessor, "count");
   if (aTypeStr == NULL
   const RWGltf_JsonValue* aCompType       = findObjectMember (theAccessor, "componentType");
   const RWGltf_JsonValue* aCount          = findObjectMember (theAccessor, "count");
   if (aTypeStr == NULL
@@ -1664,6 +1664,7 @@ bool RWGltf_GltfJsonParser::gltfParseBufferView (const Handle(RWGltf_GltfLatePri
   const RWGltf_JsonValue* aBufferName = findObjectMember (theBufferView, "buffer");
   const RWGltf_JsonValue* aByteLength = findObjectMember (theBufferView, "byteLength");
   const RWGltf_JsonValue* aByteOffset = findObjectMember (theBufferView, "byteOffset");
   const RWGltf_JsonValue* aBufferName = findObjectMember (theBufferView, "buffer");
   const RWGltf_JsonValue* aByteLength = findObjectMember (theBufferView, "byteLength");
   const RWGltf_JsonValue* aByteOffset = findObjectMember (theBufferView, "byteOffset");
+  const RWGltf_JsonValue* aByteStride = findObjectMember (theBufferView, "byteStride"); // byteStride is part of bufferView since glTF 2.0
   const RWGltf_JsonValue* aTarget     = findObjectMember (theBufferView, "target");
   if (aBufferName == NULL)
   {
   const RWGltf_JsonValue* aTarget     = findObjectMember (theBufferView, "target");
   if (aBufferName == NULL)
   {
@@ -1677,6 +1678,9 @@ bool RWGltf_GltfJsonParser::gltfParseBufferView (const Handle(RWGltf_GltfLatePri
   aBuffView.ByteLength = aByteLength != NULL && aByteLength->IsNumber()
                        ? (int64_t )aByteLength->GetDouble()
                        : 0;
   aBuffView.ByteLength = aByteLength != NULL && aByteLength->IsNumber()
                        ? (int64_t )aByteLength->GetDouble()
                        : 0;
+  aBuffView.ByteStride = aByteStride != NULL && aByteStride->IsInt()
+                       ? aByteStride->GetInt()
+                       : 0;
   if (aTarget != NULL && aTarget->IsInt())
   {
     aBuffView.Target = (RWGltf_GltfBufferViewTarget )aTarget->GetInt();
   if (aTarget != NULL && aTarget->IsInt())
   {
     aBuffView.Target = (RWGltf_GltfBufferViewTarget )aTarget->GetInt();
@@ -1698,6 +1702,12 @@ bool RWGltf_GltfJsonParser::gltfParseBufferView (const Handle(RWGltf_GltfLatePri
     reportGltfError ("BufferView '" + theName + "' defines invalid byteOffset.");
     return false;
   }
     reportGltfError ("BufferView '" + theName + "' defines invalid byteOffset.");
     return false;
   }
+  else if (aBuffView.ByteStride < 0
+        || aBuffView.ByteStride > 255)
+  {
+    reportGltfError ("BufferView '" + theName + "' defines invalid byteStride.");
+    return false;
+  }
 
   const RWGltf_JsonValue* aBuffer = myGltfRoots[RWGltf_GltfRootElement_Buffers].FindChild (*aBufferName);
   if (aBuffer == NULL
 
   const RWGltf_JsonValue* aBuffer = myGltfRoots[RWGltf_GltfRootElement_Buffers].FindChild (*aBufferName);
   if (aBuffer == NULL
@@ -1726,6 +1736,7 @@ bool RWGltf_GltfJsonParser::gltfParseBuffer (const Handle(RWGltf_GltfLatePrimiti
   const RWGltf_JsonValue* anUriVal      = findObjectMember (theBuffer, "uri");
 
   int64_t anOffset = theView.ByteOffset + theAccessor.ByteOffset;
   const RWGltf_JsonValue* anUriVal      = findObjectMember (theBuffer, "uri");
 
   int64_t anOffset = theView.ByteOffset + theAccessor.ByteOffset;
+  const int32_t aByteStride = theAccessor.ByteStride != 0 ? theView.ByteStride : theView.ByteStride;
   bool isBinary = false;
   if (myIsBinary)
   {
   bool isBinary = false;
   if (myIsBinary)
   {
@@ -1738,6 +1749,7 @@ bool RWGltf_GltfJsonParser::gltfParseBuffer (const Handle(RWGltf_GltfLatePrimiti
 
     RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
     aData.Accessor = theAccessor;
 
     RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
     aData.Accessor = theAccessor;
+    aData.Accessor.ByteStride = aByteStride;
     aData.StreamOffset = anOffset;
     aData.StreamUri = myFilePath;
     return true;
     aData.StreamOffset = anOffset;
     aData.StreamUri = myFilePath;
     return true;
@@ -1755,6 +1767,7 @@ bool RWGltf_GltfJsonParser::gltfParseBuffer (const Handle(RWGltf_GltfLatePrimiti
   {
     RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
     aData.Accessor = theAccessor;
   {
     RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
     aData.Accessor = theAccessor;
+    aData.Accessor.ByteStride = aByteStride;
     aData.StreamOffset = anOffset;
     if (!myDecodedBuffers.Find (theName, aData.StreamData))
     {
     aData.StreamOffset = anOffset;
     if (!myDecodedBuffers.Find (theName, aData.StreamData))
     {
@@ -1788,6 +1801,7 @@ bool RWGltf_GltfJsonParser::gltfParseBuffer (const Handle(RWGltf_GltfLatePrimiti
 
     RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
     aData.Accessor = theAccessor;
 
     RWGltf_GltfPrimArrayData& aData = theMeshData->AddPrimArrayData (theType);
     aData.Accessor = theAccessor;
+    aData.Accessor.ByteStride = aByteStride;
     aData.StreamOffset = anOffset;
     aData.StreamUri = myFolder + anUri;
     if (myExternalFiles != NULL)
     aData.StreamOffset = anOffset;
     aData.StreamUri = myFolder + anUri;
     if (myExternalFiles != NULL)
diff --git a/tests/de_mesh/gltf_read/boxinterleaved b/tests/de_mesh/gltf_read/boxinterleaved
new file mode 100644 (file)
index 0000000..d309473
--- /dev/null
@@ -0,0 +1,35 @@
+puts "========"
+puts "0031332: Data Exchange - RWGltf_CafReader ignores bufferView.byteStride within glTF 2.0"
+puts "========"
+
+# glTF file content
+set cubeGltf {
+{
+"asset": {"generator": "","version": "2.0"},
+"scene": 0,
+"scenes": [{"nodes": [0]}],
+"nodes": [{"children": [1],"matrix": [1.0,0.0,0.0,0.0,0.0,0.0,-1.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,1.0]},{"mesh": 0}],
+"meshes": [{"primitives": [{"attributes": {"NORMAL": 1,"POSITION": 2},"indices": 0,"mode": 4,"material": 0}],"name": "Mesh"}],
+"accessors": [
+{"bufferView": 0,"byteOffset": 0, "componentType": 5123,"count": 36,"max": [23],"min": [0],"type": "SCALAR"},
+{"bufferView": 1,"byteOffset": 0, "componentType": 5126,"count": 24,"max": [1.0,1.0,1.0],"min": [-1.0,-1.0,-1.0],"type": "VEC3"},
+{"bufferView": 1,"byteOffset": 12,"componentType": 5126,"count": 24,"max": [0.5,0.5,0.5],"min": [-0.5,-0.5,-0.5],"type": "VEC3"}
+],
+"materials": [{"pbrMetallicRoughness": {"baseColorFactor": [0.800000011920929,0.0,0.0,1.0]}}],
+"bufferViews": [
+{"buffer": 0,"byteOffset": 576,"byteLength": 72,"target": 34963},
+{"buffer": 0,"byteOffset": 0,  "byteLength": 576,"byteStride": 24,"target": 34962}
+],
+"buffers": [{"byteLength": 648,"uri": "data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAvwAAAL8AAAA/AAAAAAAAAAAAAIA/AAAAPwAAAL8AAAA/AAAAAAAAAAAAAIA/AAAAvwAAAD8AAAA/AAAAAAAAAAAAAIA/AAAAPwAAAD8AAAA/AAAAAAAAgL8AAAAAAAAAPwAAAL8AAAA/AAAAAAAAgL8AAAAAAAAAvwAAAL8AAAA/AAAAAAAAgL8AAAAAAAAAPwAAAL8AAAC/AAAAAAAAgL8AAAAAAAAAvwAAAL8AAAC/AACAPwAAAAAAAAAAAAAAPwAAAD8AAAA/AACAPwAAAAAAAAAAAAAAPwAAAL8AAAA/AACAPwAAAAAAAAAAAAAAPwAAAD8AAAC/AACAPwAAAAAAAAAAAAAAPwAAAL8AAAC/AAAAAAAAgD8AAAAAAAAAvwAAAD8AAAA/AAAAAAAAgD8AAAAAAAAAPwAAAD8AAAA/AAAAAAAAgD8AAAAAAAAAvwAAAD8AAAC/AAAAAAAAgD8AAAAAAAAAPwAAAD8AAAC/AACAvwAAAAAAAAAAAAAAvwAAAL8AAAA/AACAvwAAAAAAAAAAAAAAvwAAAD8AAAA/AACAvwAAAAAAAAAAAAAAvwAAAL8AAAC/AACAvwAAAAAAAAAAAAAAvwAAAD8AAAC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAC/AAAAAAAAAAAAAIC/AAAAvwAAAD8AAAC/AAAAAAAAAAAAAIC/AAAAPwAAAL8AAAC/AAAAAAAAAAAAAIC/AAAAPwAAAD8AAAC/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA"}]
+}
+}
+
+set fd [open ${imagedir}/${casename}.gltf w]
+fconfigure $fd -translation lf
+puts $fd $cubeGltf
+close $fd
+
+ReadGltf D ${imagedir}/${casename}.gltf
+XGetOneShape s D
+checknbshapes s -face 1 -compound 0
+checktrinfo s -tri 12 -nod 24