//! Material extension.
const char THE_KHR_materials_common[] = "KHR_materials_common";
const char THE_KHR_binary_glTF[] = "KHR_binary_glTF";
+
+ //! Data buffer referring to a portion of another buffer.
+ class RWGltf_SubBuffer : public NCollection_Buffer
+ {
+ public:
+ RWGltf_SubBuffer (const Handle(NCollection_Buffer)& theBase,
+ Standard_Size theOffset,
+ Standard_Size theLength)
+ : NCollection_Buffer (Handle(NCollection_BaseAllocator)(), theLength, theBase->ChangeData() + theOffset),
+ myBaseBuffer (theBase) {}
+
+ private:
+ Handle(NCollection_Buffer) myBaseBuffer;
+ };
}
//! Find member of the object in a safe way.
if (aBinVal != NULL)
{
- //const RWGltf_JsonValue* aMimeTypeVal = findObjectMember (*aBinVal, "mimeType");
- //const RWGltf_JsonValue* aWidthVal = findObjectMember (*aBinVal, "width");
- //const RWGltf_JsonValue* aHeightVal = findObjectMember (*aBinVal, "height");
if (aBufferViewName == NULL)
{
reportGltfWarning ("Invalid texture node '" + aTextureId + "' points to invalid data source.");
return false;
}
-
const RWGltf_JsonValue* aBufferView = myGltfRoots[RWGltf_GltfRootElement_BufferViews].FindChild (*aBufferViewName);
if (aBufferView == NULL
|| !aBufferView->IsObject())
reportGltfWarning ("Invalid texture node '" + aTextureId + "' points to invalid buffer view '" + getKeyString (*aBufferViewName) + "'.");
return false;
}
+ return gltfParseTexturInGlbBuffer (theTexture, *aBinVal, getKeyString (*aBufferViewName), *aBufferView);
+ }
+ }
- const RWGltf_JsonValue* aBufferName = findObjectMember (*aBufferView, "buffer");
- const RWGltf_JsonValue* aByteLength = findObjectMember (*aBufferView, "byteLength");
- const RWGltf_JsonValue* aByteOffset = findObjectMember (*aBufferView, "byteOffset");
- if (aBufferName != NULL
- && aBufferName->IsString()
- && !IsEqual (aBufferName->GetString(), "binary_glTF"))
- {
- reportGltfError ("BufferView '" + getKeyString (*aBufferViewName) + "' does not define binary_glTF buffer.");
- return false;
- }
-
- RWGltf_GltfBufferView aBuffView;
- aBuffView.ByteOffset = aByteOffset != NULL && aByteOffset->IsNumber()
- ? (int64_t )aByteOffset->GetDouble()
- : 0;
- aBuffView.ByteLength = aByteLength != NULL && aByteLength->IsNumber()
- ? (int64_t )aByteLength->GetDouble()
- : 0;
- if (aBuffView.ByteLength < 0)
- {
- reportGltfError ("BufferView '" + getKeyString (*aBufferViewName) + "' defines invalid byteLength.");
- return false;
- }
- else if (aBuffView.ByteOffset < 0)
- {
- reportGltfError ("BufferView '" + getKeyString (*aBufferViewName) + "' defines invalid byteOffset.");
- return false;
- }
-
+ const RWGltf_JsonValue* anUriVal = findObjectMember (*anImgNode, "uri");
+ if (anUriVal == NULL)
+ {
+ const RWGltf_JsonValue* aBufferViewName = findObjectMember (*anImgNode, "bufferView");
+ if (aBufferViewName == NULL)
+ {
+ reportGltfWarning ("Invalid texture node '" + aTextureId + "' points to invalid data source.");
+ return false;
+ }
- const int64_t anOffset = myBinBodyOffset + aBuffView.ByteOffset;
- theTexture = new Image_Texture (myFilePath, anOffset, aBuffView.ByteLength);
- return true;
+ const RWGltf_JsonValue* aBufferView = myGltfRoots[RWGltf_GltfRootElement_BufferViews].FindChild (*aBufferViewName);
+ if (aBufferView == NULL
+ || !aBufferView->IsObject())
+ {
+ reportGltfWarning ("Invalid texture node '" + aTextureId + "' points to invalid buffer view '" + getKeyString (*aBufferViewName) + "'.");
+ return false;
}
+ return gltfParseTextureInBufferView (theTexture, getKeyString (*aSrcVal), getKeyString (*aBufferViewName), *aBufferView);
}
- const RWGltf_JsonValue* anUriVal = findObjectMember (*anImgNode, "uri");
- if (anUriVal == NULL
- || !anUriVal->IsString())
+ if (!anUriVal->IsString())
{
+ reportGltfWarning ("Invalid texture node '" + aTextureId + "' points to invalid data source.");
return false;
}
return true;
}
+// =======================================================================
+// function : gltfParseTexturInGlbBuffer
+// purpose :
+// =======================================================================
+bool RWGltf_GltfJsonParser::gltfParseTexturInGlbBuffer (Handle(Image_Texture)& theTexture,
+ const RWGltf_JsonValue& theBinVal,
+ const TCollection_AsciiString& theBufferViewId,
+ const RWGltf_JsonValue& theBufferView)
+{
+ const RWGltf_JsonValue* aMimeTypeVal = findObjectMember (theBinVal, "mimeType");
+ //const RWGltf_JsonValue* aWidthVal = findObjectMember (theBinVal, "width");
+ //const RWGltf_JsonValue* aHeightVal = findObjectMember (theBinVal, "height");
+ (void )aMimeTypeVal;
+
+ const RWGltf_JsonValue* aBufferName = findObjectMember (theBufferView, "buffer");
+ const RWGltf_JsonValue* aByteLength = findObjectMember (theBufferView, "byteLength");
+ const RWGltf_JsonValue* aByteOffset = findObjectMember (theBufferView, "byteOffset");
+ if (aBufferName != NULL
+ && aBufferName->IsString()
+ && !IsEqual (aBufferName->GetString(), "binary_glTF"))
+ {
+ reportGltfError ("BufferView '" + theBufferViewId + "' does not define binary_glTF buffer.");
+ return false;
+ }
+
+ RWGltf_GltfBufferView aBuffView;
+ aBuffView.ByteOffset = aByteOffset != NULL && aByteOffset->IsNumber()
+ ? (int64_t )aByteOffset->GetDouble()
+ : 0;
+ aBuffView.ByteLength = aByteLength != NULL && aByteLength->IsNumber()
+ ? (int64_t )aByteLength->GetDouble()
+ : 0;
+ if (aBuffView.ByteLength <= 0)
+ {
+ reportGltfError ("BufferView '" + theBufferViewId + "' defines invalid byteLength.");
+ return false;
+ }
+ else if (aBuffView.ByteOffset < 0)
+ {
+ reportGltfError ("BufferView '" + theBufferViewId + "' defines invalid byteOffset.");
+ return false;
+ }
+
+ const int64_t anOffset = myBinBodyOffset + aBuffView.ByteOffset;
+ theTexture = new Image_Texture (myFilePath, anOffset, aBuffView.ByteLength);
+ return true;
+}
+
+// =======================================================================
+// function : gltfParseTextureInBufferView
+// purpose :
+// =======================================================================
+bool RWGltf_GltfJsonParser::gltfParseTextureInBufferView (Handle(Image_Texture)& theTexture,
+ const TCollection_AsciiString& theSourceId,
+ const TCollection_AsciiString& theBufferViewId,
+ const RWGltf_JsonValue& theBufferView)
+{
+ const RWGltf_JsonValue* aBufferName = findObjectMember (theBufferView, "buffer");
+ const RWGltf_JsonValue* aByteLength = findObjectMember (theBufferView, "byteLength");
+ const RWGltf_JsonValue* aByteOffset = findObjectMember (theBufferView, "byteOffset");
+ if (aBufferName == NULL)
+ {
+ reportGltfError ("BufferView '" + theBufferViewId + "' does not define buffer.");
+ return false;
+ }
+
+ const TCollection_AsciiString aBufferId = getKeyString (*aBufferName);
+ const RWGltf_JsonValue* aBuffer = myGltfRoots[RWGltf_GltfRootElement_Buffers].FindChild (*aBufferName);
+ if (aBuffer == NULL
+ || !aBuffer->IsObject())
+ {
+ reportGltfError ("BufferView '" + theBufferViewId + "' refers to non-existing buffer.");
+ return false;
+ }
+
+ RWGltf_GltfBufferView aBuffView;
+ aBuffView.ByteOffset = aByteOffset != NULL && aByteOffset->IsNumber()
+ ? (int64_t )aByteOffset->GetDouble()
+ : 0;
+ aBuffView.ByteLength = aByteLength != NULL && aByteLength->IsNumber()
+ ? (int64_t )aByteLength->GetDouble()
+ : 0;
+ if (aBuffView.ByteLength <= 0)
+ {
+ reportGltfError ("BufferView '" + theBufferViewId + "' defines invalid byteLength.");
+ return false;
+ }
+ else if (aBuffView.ByteOffset < 0)
+ {
+ reportGltfError ("BufferView '" + theBufferViewId + "' defines invalid byteOffset.");
+ return false;
+ }
+
+ const RWGltf_JsonValue* anUriVal = findObjectMember (*aBuffer, "uri");
+ if (anUriVal == NULL
+ || !anUriVal->IsString())
+ {
+ reportGltfError ("Buffer '" + aBufferId + "' does not define uri.");
+ return false;
+ }
+
+ const char* anUriData = anUriVal->GetString();
+ if (::strncmp (anUriData, "data:application/octet-stream;base64,", 37) == 0)
+ {
+ Handle(NCollection_Buffer) aBaseBuffer;
+ if (!myDecodedBuffers.Find (aBufferId, aBaseBuffer))
+ {
+ aBaseBuffer = FSD_Base64Decoder::Decode ((const Standard_Byte* )anUriData + 37, anUriVal->GetStringLength() - 37);
+ myDecodedBuffers.Bind (aBufferId, aBaseBuffer);
+ }
+
+ Handle(RWGltf_SubBuffer) aSubBuffer = new RWGltf_SubBuffer (aBaseBuffer, (Standard_Size )aBuffView.ByteOffset, (Standard_Size )aBuffView.ByteLength);
+ theTexture = new Image_Texture (aSubBuffer, myFilePath + "@" + theSourceId);
+ return true;
+ }
+
+ const TCollection_AsciiString anUri (anUriData);
+ if (anUri.IsEmpty())
+ {
+ reportGltfError ("Buffer '" + aBufferId + "' does not define uri.");
+ return false;
+ }
+
+ const TCollection_AsciiString aPath = myFolder + anUri;
+ bool isFileExist = false;
+ if (!myProbedFiles.Find (aPath, isFileExist))
+ {
+ isFileExist = OSD_File (aPath).Exists();
+ myProbedFiles.Bind (aPath, isFileExist);
+ }
+ if (!isFileExist)
+ {
+ reportGltfError ("Buffer '" + aBufferId + "' refers to non-existing file '" + anUri + "'.");
+ return false;
+ }
+
+ theTexture = new Image_Texture (aPath, aBuffView.ByteOffset, aBuffView.ByteLength);
+ if (myExternalFiles != NULL)
+ {
+ myExternalFiles->Add (aPath);
+ }
+ return true;
+}
+
// =======================================================================
// function : gltfParseScene
// purpose :
}
}
- if (aBuffView.ByteLength < 0)
+ if (aBuffView.ByteLength <= 0)
{
reportGltfError ("BufferView '" + theName + "' defines invalid byteLength.");
return false;
--- /dev/null
+puts "========"
+puts "0031312: Data Exchange - RWGltf_CafReader fails reading texture embedded into base64 bufferView"
+puts "========"
+
+# glTF file content
+set cubeGltf {
+{
+"asset":{"generator":"","version":"2.0"},
+"scene":0,
+"scenes":[{"name":"Scene","nodes":[0]}],
+"nodes":[{"mesh":0,"name":"Cube"}],
+"materials":[{"name":"Material","pbrMetallicRoughness":{"baseColorTexture":{"index":0,"texCoord":0},"metallicFactor":0,"roughnessFactor":0.4}}],
+"meshes":[{"name":"Cube","primitives":[{"attributes":{"POSITION":0,"NORMAL":1,"TEXCOORD_0":2},"indices":3,"material":0}]}],
+"textures":[{"source":0}],
+"images":[{"bufferView":4,"mimeType":"image/jpeg","name":"UVGrid"}],
+"accessors":[
+{"bufferView":0,"componentType":5126,"count":24,"type":"VEC3"},
+{"bufferView":1,"componentType":5126,"count":24,"type":"VEC3"},
+{"bufferView":2,"componentType":5126,"count":24,"type":"VEC2"},
+{"bufferView":3,"componentType":5123,"count":36,"type":"SCALAR"}
+],
+"bufferViews":[
+{"buffer":0,"byteLength":288,"byteOffset":0},
+{"buffer":0,"byteLength":288,"byteOffset":288},
+{"buffer":0,"byteLength":192,"byteOffset":576},
+{"buffer":0,"byteLength":72,"byteOffset":768},
+{"buffer":0,"byteLength":2870,"byteOffset":840}
+],
+"buffers":[{
+"byteLength":3712,
+"uri":"data:application/octet-stream;base64,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"
+}]
+}
+}
+
+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