1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-10 18:51:21 +03:00
occt/src/RWGltf/RWGltf_TriangulationReader.cxx
dpasukhi a5a7b3185b Coding - Apply .clang-format formatting #286
Update empty method guards to new style with regex (see PR).
Used clang-format 18.1.8.
New actions to validate code formatting is added.
Update .clang-format with disabling of include sorting.
  It is temporary changes, then include will be sorted.
Apply formatting for /src and /tools folder.
The files with .hxx,.cxx,.lxx,.h,.pxx,.hpp,*.cpp extensions.
2025-01-26 00:43:57 +00:00

997 lines
35 KiB
C++

// Author: Kirill Gavrilov
// Copyright (c) 2019 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <RWGltf_TriangulationReader.hxx>
#include <Message.hxx>
#include <OSD_FileSystem.hxx>
#include <RWGltf_GltfLatePrimitiveArray.hxx>
#include <RWGltf_GltfPrimArrayData.hxx>
#include <Standard_ArrayStreamBuffer.hxx>
#include <Standard_ReadBuffer.hxx>
#ifdef HAVE_DRACO
#include <Standard_WarningsDisable.hxx>
#include <draco/compression/decode.h>
#include <Standard_WarningsRestore.hxx>
#endif
namespace
{
static const Standard_Integer THE_LOWER_TRI_INDEX = 1;
static const Standard_Integer THE_LOWER_NODE_INDEX = 1;
static const Standard_ShortReal THE_NORMAL_PREC2 = 0.001f;
#ifdef HAVE_DRACO
//! Return array type from Draco attribute type.
static RWGltf_GltfArrayType arrayTypeFromDraco(draco::GeometryAttribute::Type theType)
{
switch (theType)
{
case draco::GeometryAttribute::POSITION:
return RWGltf_GltfArrayType_Position;
case draco::GeometryAttribute::NORMAL:
return RWGltf_GltfArrayType_Normal;
case draco::GeometryAttribute::COLOR:
return RWGltf_GltfArrayType_Color;
case draco::GeometryAttribute::TEX_COORD:
return RWGltf_GltfArrayType_TCoord0;
default:
return RWGltf_GltfArrayType_UNKNOWN;
}
}
//! Return layout from Draco number of components.
static RWGltf_GltfAccessorLayout layoutFromDraco(int8_t theNbComps)
{
switch (theNbComps)
{
case 1:
return RWGltf_GltfAccessorLayout_Scalar;
case 2:
return RWGltf_GltfAccessorLayout_Vec2;
case 3:
return RWGltf_GltfAccessorLayout_Vec3;
case 4:
return RWGltf_GltfAccessorLayout_Vec4;
}
return RWGltf_GltfAccessorLayout_UNKNOWN;
}
//! Return component type from Draco data type.
static RWGltf_GltfAccessorCompType compTypeFromDraco(draco::DataType theType)
{
switch (theType)
{
case draco::DT_INT8:
return RWGltf_GltfAccessorCompType_Int8;
case draco::DT_UINT8:
return RWGltf_GltfAccessorCompType_UInt8;
case draco::DT_INT16:
return RWGltf_GltfAccessorCompType_Int16;
case draco::DT_UINT16:
return RWGltf_GltfAccessorCompType_UInt16;
case draco::DT_INT32:
case draco::DT_UINT32:
return RWGltf_GltfAccessorCompType_UInt32;
// case draco::DT_INT64:
// case draco::DT_UINT64:
case draco::DT_FLOAT32:
return RWGltf_GltfAccessorCompType_Float32;
// case draco::DT_FLOAT64:
// case draco::DT_BOOL:
default:
return RWGltf_GltfAccessorCompType_UNKNOWN;
}
}
#endif
} // namespace
IMPLEMENT_STANDARD_RTTIEXT(RWGltf_TriangulationReader, RWMesh_TriangulationReader)
// =======================================================================
// function : RWGltf_TriangulationReader
// purpose :
// =======================================================================
RWGltf_TriangulationReader::RWGltf_TriangulationReader()
{
//
}
// =======================================================================
// function : reportError
// purpose :
// =======================================================================
void RWGltf_TriangulationReader::reportError(const TCollection_AsciiString& theText) const
{
Message::SendFail(TCollection_AsciiString("File '") + myFileName + "' defines invalid glTF!\n"
+ theText);
}
// =======================================================================
// function : LoadStreamData
// purpose :
// =======================================================================
bool RWGltf_TriangulationReader::LoadStreamData(
const Handle(RWMesh_TriangulationSource)& theSourceMesh,
const Handle(Poly_Triangulation)& theDestMesh) const
{
Standard_ASSERT_RETURN(!theDestMesh.IsNull(),
"The destination mesh should be initialized before loading data to it",
false);
theDestMesh->Clear();
theDestMesh->SetDoublePrecision(myIsDoublePrecision);
if (!loadStreamData(theSourceMesh, theDestMesh))
{
theDestMesh->Clear();
return false;
}
if (!finalizeLoading(theSourceMesh, theDestMesh))
{
theDestMesh->Clear();
return false;
}
return true;
}
// =======================================================================
// function : readStreamData
// purpose :
// =======================================================================
bool RWGltf_TriangulationReader::readStreamData(
const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh,
const RWGltf_GltfPrimArrayData& theGltfData,
const Handle(Poly_Triangulation)& theDestMesh) const
{
Standard_ArrayStreamBuffer aStreamBuffer((const char*)theGltfData.StreamData->Data(),
theGltfData.StreamData->Size());
std::istream aStream(&aStreamBuffer);
aStream.seekg((std::streamoff)theGltfData.StreamOffset, std::ios_base::beg);
if (!readBuffer(theSourceGltfMesh, theDestMesh, aStream, theGltfData.Accessor, theGltfData.Type))
{
return false;
}
return true;
}
// =======================================================================
// function : readFileData
// purpose :
// =======================================================================
bool RWGltf_TriangulationReader::readFileData(
const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh,
const RWGltf_GltfPrimArrayData& theGltfData,
const Handle(Poly_Triangulation)& theDestMesh,
const Handle(OSD_FileSystem)& theFileSystem) const
{
const Handle(OSD_FileSystem)& aFileSystem =
!theFileSystem.IsNull() ? theFileSystem : OSD_FileSystem::DefaultFileSystem();
std::shared_ptr<std::istream> aSharedStream =
aFileSystem->OpenIStream(theGltfData.StreamUri,
std::ios::in | std::ios::binary,
theGltfData.StreamOffset);
if (aSharedStream.get() == NULL)
{
reportError(TCollection_AsciiString("Buffer '") + theSourceGltfMesh->Id()
+ "' refers to invalid file '" + theGltfData.StreamUri + "'.");
return false;
}
if (!readBuffer(theSourceGltfMesh,
theDestMesh,
*aSharedStream.get(),
theGltfData.Accessor,
theGltfData.Type))
{
return false;
}
return true;
}
// =======================================================================
// function : loadStreamData
// purpose :
// =======================================================================
bool RWGltf_TriangulationReader::loadStreamData(
const Handle(RWMesh_TriangulationSource)& theSourceMesh,
const Handle(Poly_Triangulation)& theDestMesh,
bool theToResetStream) const
{
const Handle(RWGltf_GltfLatePrimitiveArray) aSourceGltfMesh =
Handle(RWGltf_GltfLatePrimitiveArray)::DownCast(theSourceMesh);
if (aSourceGltfMesh.IsNull()
|| aSourceGltfMesh->PrimitiveMode() == RWGltf_GltfPrimitiveMode_UNKNOWN)
{
return false;
}
bool wasLoaded = false;
for (NCollection_Sequence<RWGltf_GltfPrimArrayData>::Iterator aDataIter(aSourceGltfMesh->Data());
aDataIter.More();
aDataIter.Next())
{
RWGltf_GltfPrimArrayData& aData = aDataIter.ChangeValue();
if (aData.StreamData.IsNull())
{
continue;
}
if (!readStreamData(aSourceGltfMesh, aData, theDestMesh))
{
return false;
}
if (theToResetStream)
{
aData.StreamData.Nullify();
}
wasLoaded = true;
}
return wasLoaded;
}
// =======================================================================
// function : readDracoBuffer
// purpose :
// =======================================================================
bool RWGltf_TriangulationReader::readDracoBuffer(
const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceGltfMesh,
const RWGltf_GltfPrimArrayData& theGltfData,
const Handle(Poly_Triangulation)& theDestMesh,
const Handle(OSD_FileSystem)& theFileSystem) const
{
const TCollection_AsciiString& aName = theSourceGltfMesh->Id();
const Handle(OSD_FileSystem)& aFileSystem =
!theFileSystem.IsNull() ? theFileSystem : OSD_FileSystem::DefaultFileSystem();
std::shared_ptr<std::istream> aSharedStream =
aFileSystem->OpenIStream(theGltfData.StreamUri,
std::ios::in | std::ios::binary,
theGltfData.StreamOffset);
if (aSharedStream.get() == NULL)
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' refers to invalid file '"
+ theGltfData.StreamUri + "'.");
return false;
}
#ifdef HAVE_DRACO
std::vector<char> aReadData;
aReadData.resize((size_t)theGltfData.StreamLength);
aSharedStream->read(aReadData.data(), (std::streamsize)theGltfData.StreamLength);
if (!aSharedStream->good())
{
reportError(TCollection_AsciiString("Buffer '") + aName
+ "' refers to file that cannot be read '" + theGltfData.StreamUri + "'.");
return false;
}
draco::DecoderBuffer aDracoBuf;
aDracoBuf.Init(aReadData.data(), aReadData.size());
draco::Decoder aDracoDecoder;
draco::StatusOr<std::unique_ptr<draco::Mesh>> aDracoStat =
aDracoDecoder.DecodeMeshFromBuffer(&aDracoBuf);
if (!aDracoStat.ok() || aDracoStat.value().get() == NULL)
{
reportError(TCollection_AsciiString("Buffer '") + aName
+ "' refers to Draco data that cannot be decoded '" + theGltfData.StreamUri + "'.");
return false;
}
const Standard_Integer aNbNodes = (Standard_Integer)aDracoStat.value()->num_points();
const Standard_Integer aNbTris = (Standard_Integer)aDracoStat.value()->num_faces();
if (aNbNodes < 0)
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' defines an empty array.");
return false;
}
if ((int64_t)aDracoStat.value()->num_points() > std::numeric_limits<Standard_Integer>::max())
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' defines too big array.");
return false;
}
if (!setNbPositionNodes(theDestMesh, aNbNodes))
{
return false;
}
if (aNbTris > 0 && !setNbTriangles(theDestMesh, aNbTris))
{
return false;
}
// copy vertex attributes
for (int32_t anAttrIter = 0; anAttrIter < aDracoStat.value()->num_attributes(); ++anAttrIter)
{
const draco::PointAttribute* anAttrib = aDracoStat.value()->attribute(anAttrIter);
const RWGltf_GltfArrayType aWrapType = arrayTypeFromDraco(anAttrib->attribute_type());
const RWGltf_GltfAccessorLayout aWrapLayout = layoutFromDraco(anAttrib->num_components());
const RWGltf_GltfAccessorCompType aWrapCompType = compTypeFromDraco(anAttrib->data_type());
switch (aWrapType)
{
case RWGltf_GltfArrayType_Position: {
if (aWrapCompType != RWGltf_GltfAccessorCompType_Float32
|| aWrapLayout != RWGltf_GltfAccessorLayout_Vec3)
{
reportError(TCollection_AsciiString("Buffer '") + aName
+ "' has unsupported position data type.");
return false;
}
for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
{
const Graphic3d_Vec3* aVec3 = reinterpret_cast<const Graphic3d_Vec3*>(
anAttrib->GetAddressOfMappedIndex(draco::PointIndex(aVertIter)));
if (aVec3 == NULL)
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error.");
return false;
}
gp_Pnt anXYZ(aVec3->x(), aVec3->y(), aVec3->z());
myCoordSysConverter.TransformPosition(anXYZ.ChangeCoord());
setNodePosition(theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, anXYZ);
}
break;
}
case RWGltf_GltfArrayType_Normal: {
if (aWrapCompType != RWGltf_GltfAccessorCompType_Float32
|| aWrapLayout != RWGltf_GltfAccessorLayout_Vec3)
{
Message::SendTrace(TCollection_AsciiString()
+ "Vertex normals in unsupported format have been skipped while "
"reading glTF triangulation '"
+ aName + "'");
break;
}
if (!setNbNormalNodes(theDestMesh, aNbNodes))
{
return false;
}
for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
{
const Graphic3d_Vec3* aVec3 = reinterpret_cast<const Graphic3d_Vec3*>(
anAttrib->GetAddressOfMappedIndex(draco::PointIndex(aVertIter)));
if (aVec3 == NULL)
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error.");
return false;
}
if (aVec3->SquareModulus() >= THE_NORMAL_PREC2)
{
Graphic3d_Vec3 aVec3Copy = *aVec3;
myCoordSysConverter.TransformNormal(aVec3Copy);
setNodeNormal(theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, aVec3Copy);
}
else
{
setNodeNormal(theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, gp_Vec3f(0.0, 0.0, 1.0));
}
}
break;
}
case RWGltf_GltfArrayType_TCoord0: {
if (aWrapCompType != RWGltf_GltfAccessorCompType_Float32
|| aWrapLayout != RWGltf_GltfAccessorLayout_Vec2)
{
Message::SendTrace(TCollection_AsciiString()
+ "Vertex UV coordinates in unsupported format have been skipped "
"while reading glTF triangulation '"
+ aName + "'");
break;
}
if (!setNbUVNodes(theDestMesh, aNbNodes))
{
return false;
}
for (int aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
{
const Graphic3d_Vec2* aVec2 = reinterpret_cast<const Graphic3d_Vec2*>(
anAttrib->GetAddressOfMappedIndex(draco::PointIndex(aVertIter)));
if (aVec2 == NULL)
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error.");
return false;
}
// Y should be flipped (relative to image layout used by OCCT)
float aTexY = 1.0f - aVec2->y();
setNodeUV(theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, gp_Pnt2d(aVec2->x(), aTexY));
}
break;
}
default: {
break;
}
}
}
// copy triangles
Standard_Integer aLastTriIndex = 0;
for (Standard_Integer aFaceIter = 0; aFaceIter < aNbTris; ++aFaceIter)
{
const draco::Mesh::Face& aFace = aDracoStat.value()->face(draco::FaceIndex(aFaceIter));
Poly_Triangle aVec3;
aVec3.ChangeValue(1) = THE_LOWER_NODE_INDEX + aFace[0].value();
aVec3.ChangeValue(2) = THE_LOWER_NODE_INDEX + aFace[1].value();
aVec3.ChangeValue(3) = THE_LOWER_NODE_INDEX + aFace[2].value();
const Standard_Integer wasSet =
setTriangle(theDestMesh, THE_LOWER_TRI_INDEX + aLastTriIndex, aVec3);
if (!wasSet)
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' refers to invalid indices.");
}
if (wasSet > 0)
{
++aLastTriIndex;
}
}
const Standard_Integer aNbDegenerate = aNbTris - aLastTriIndex;
if (aNbDegenerate > 0)
{
if (aNbDegenerate == aNbTris)
{
Message::SendWarning(TCollection_AsciiString("Buffer '") + aName
+ "' has been skipped (all elements are degenerative in)");
return false;
}
theSourceGltfMesh->ChangeDegeneratedTriNb() += aNbDegenerate;
if (myLoadingStatistic == NULL && myToPrintDebugMessages)
{
Message::SendTrace(
TCollection_AsciiString() + aNbDegenerate
+ " degenerate triangles have been skipped while reading glTF triangulation '" + aName
+ "'");
}
if (!setNbTriangles(theDestMesh, aLastTriIndex, true))
{
return false;
}
}
return true;
#else
(void)theDestMesh;
reportError(TCollection_AsciiString("Buffer '") + aName
+ "' refers to unsupported compressed data.");
return false;
#endif
}
// =======================================================================
// function : load
// purpose :
// =======================================================================
bool RWGltf_TriangulationReader::load(const Handle(RWMesh_TriangulationSource)& theSourceMesh,
const Handle(Poly_Triangulation)& theDestMesh,
const Handle(OSD_FileSystem)& theFileSystem) const
{
const Handle(RWGltf_GltfLatePrimitiveArray) aSourceGltfMesh =
Handle(RWGltf_GltfLatePrimitiveArray)::DownCast(theSourceMesh);
if (aSourceGltfMesh.IsNull()
|| aSourceGltfMesh->PrimitiveMode() == RWGltf_GltfPrimitiveMode_UNKNOWN)
{
return false;
}
bool hasCompressed = false;
for (NCollection_Sequence<RWGltf_GltfPrimArrayData>::Iterator aDataIter(aSourceGltfMesh->Data());
aDataIter.More();
aDataIter.Next())
{
const RWGltf_GltfPrimArrayData& aData = aDataIter.Value();
const TCollection_AsciiString& aName = aSourceGltfMesh->Id();
if (!aData.StreamData.IsNull())
{
Message::SendWarning(
TCollection_AsciiString("Buffer '") + aName
+ "' contains stream data that cannot be loaded during deferred data loading.");
continue;
}
else if (aData.StreamUri.IsEmpty())
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' does not define uri.");
return false;
}
if (aData.Accessor.IsCompressed)
{
if (hasCompressed)
{
// already decoded (compressed stream defines all attributes at once)
continue;
}
if (!readDracoBuffer(aSourceGltfMesh, aData, theDestMesh, theFileSystem))
{
return false;
}
// keep decoding - there are might be uncompressed attributes in addition to compressed
hasCompressed = true;
}
else if (!readFileData(aSourceGltfMesh, aData, theDestMesh, theFileSystem))
{
return false;
}
}
return true;
}
// =======================================================================
// function : finalizeLoading
// purpose :
// =======================================================================
bool RWGltf_TriangulationReader::finalizeLoading(
const Handle(RWMesh_TriangulationSource)& theSourceMesh,
const Handle(Poly_Triangulation)& theDestMesh) const
{
if (theDestMesh->NbNodes() < 1)
{
return false;
}
if (theDestMesh->NbTriangles() < 1)
{
const Handle(RWGltf_GltfLatePrimitiveArray) aSourceGltfMesh =
Handle(RWGltf_GltfLatePrimitiveArray)::DownCast(theSourceMesh);
if (!aSourceGltfMesh.IsNull()
&& aSourceGltfMesh->PrimitiveMode() == RWGltf_GltfPrimitiveMode_Triangles)
{
// reconstruct indexes
const Standard_Integer aNbTris = theDestMesh->NbNodes() / 3;
if (!setNbTriangles(theDestMesh, aNbTris))
{
return false;
}
for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
{
if (!setTriangle(theDestMesh,
THE_LOWER_TRI_INDEX + aTriIter,
Poly_Triangle(THE_LOWER_NODE_INDEX + aTriIter * 3 + 0,
THE_LOWER_NODE_INDEX + aTriIter * 3 + 1,
THE_LOWER_NODE_INDEX + aTriIter * 3 + 2)))
{
return false;
}
}
}
}
return RWMesh_TriangulationReader::finalizeLoading(theSourceMesh, theDestMesh);
}
// =======================================================================
// function : readBuffer
// purpose :
// =======================================================================
bool RWGltf_TriangulationReader::readBuffer(
const Handle(RWGltf_GltfLatePrimitiveArray)& theSourceMesh,
const Handle(Poly_Triangulation)& theDestMesh,
std::istream& theStream,
const RWGltf_GltfAccessor& theAccessor,
RWGltf_GltfArrayType theType) const
{
const TCollection_AsciiString& aName = theSourceMesh->Id();
if (theSourceMesh->PrimitiveMode() != RWGltf_GltfPrimitiveMode_Triangles)
{
Message::SendWarning(TCollection_AsciiString("Buffer '") + aName
+ "' skipped unsupported primitive array");
return true;
}
switch (theType)
{
case RWGltf_GltfArrayType_Indices: {
if (theAccessor.Type != RWGltf_GltfAccessorLayout_Scalar)
{
break;
}
Poly_Triangle aVec3;
if (theAccessor.ComponentType == RWGltf_GltfAccessorCompType_UInt16)
{
if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' defines too big array.");
return false;
}
const Standard_Integer aNbTris = (Standard_Integer)(theAccessor.Count / 3);
if (!setNbTriangles(theDestMesh, aNbTris))
{
return false;
}
const size_t aStride =
theAccessor.ByteStride != 0 ? theAccessor.ByteStride : sizeof(uint16_t);
Standard_ReadBuffer aBuffer(theAccessor.Count * aStride, aStride);
Standard_Integer aLastTriIndex = 0;
for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
{
if (const uint16_t* anIndex0 = aBuffer.ReadChunk<uint16_t>(theStream))
{
aVec3.ChangeValue(1) = THE_LOWER_NODE_INDEX + *anIndex0;
}
if (const uint16_t* anIndex1 = aBuffer.ReadChunk<uint16_t>(theStream))
{
aVec3.ChangeValue(2) = THE_LOWER_NODE_INDEX + *anIndex1;
}
if (const uint16_t* anIndex2 = aBuffer.ReadChunk<uint16_t>(theStream))
{
aVec3.ChangeValue(3) = THE_LOWER_NODE_INDEX + *anIndex2;
}
else
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error.");
return false;
}
const Standard_Integer wasSet =
setTriangle(theDestMesh, THE_LOWER_TRI_INDEX + aLastTriIndex, aVec3);
if (!wasSet)
{
reportError(TCollection_AsciiString("Buffer '") + aName
+ "' refers to invalid indices.");
}
if (wasSet > 0)
{
aLastTriIndex++;
}
}
const Standard_Integer aNbDegenerate = aNbTris - aLastTriIndex;
if (aNbDegenerate > 0)
{
if (aNbDegenerate == aNbTris)
{
Message::SendWarning(TCollection_AsciiString("Buffer '") + aName
+ "' has been skipped (all elements are degenerative in)");
return false;
}
theSourceMesh->ChangeDegeneratedTriNb() += aNbDegenerate;
if ((myLoadingStatistic == NULL) && myToPrintDebugMessages)
{
Message::SendTrace(
TCollection_AsciiString() + aNbDegenerate
+ " degenerate triangles have been skipped while reading glTF triangulation '" + aName
+ "'");
}
if (!setNbTriangles(theDestMesh, aLastTriIndex, true))
{
return false;
}
}
}
else if (theAccessor.ComponentType == RWGltf_GltfAccessorCompType_UInt32)
{
if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' defines too big array.");
return false;
}
const int aNbTris = (Standard_Integer)(theAccessor.Count / 3);
if (!setNbTriangles(theDestMesh, aNbTris))
{
return false;
}
const size_t aStride =
theAccessor.ByteStride != 0 ? theAccessor.ByteStride : sizeof(uint32_t);
Standard_ReadBuffer aBuffer(theAccessor.Count * aStride, aStride);
Standard_Integer aLastTriIndex = 0;
for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
{
if (const uint32_t* anIndex0 = aBuffer.ReadChunk<uint32_t>(theStream))
{
aVec3.ChangeValue(1) = THE_LOWER_NODE_INDEX + *anIndex0;
}
if (const uint32_t* anIndex1 = aBuffer.ReadChunk<uint32_t>(theStream))
{
aVec3.ChangeValue(2) = THE_LOWER_NODE_INDEX + *anIndex1;
}
if (const uint32_t* anIndex2 = aBuffer.ReadChunk<uint32_t>(theStream))
{
aVec3.ChangeValue(3) = THE_LOWER_NODE_INDEX + *anIndex2;
}
else
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error.");
return false;
}
const Standard_Integer wasSet =
setTriangle(theDestMesh, THE_LOWER_TRI_INDEX + aLastTriIndex, aVec3);
if (!wasSet)
{
reportError(TCollection_AsciiString("Buffer '") + aName
+ "' refers to invalid indices.");
}
if (wasSet > 0)
{
aLastTriIndex++;
}
}
const Standard_Integer aNbDegenerate = aNbTris - aLastTriIndex;
if (aNbDegenerate > 0)
{
if (aNbDegenerate == aNbTris)
{
Message::SendWarning(TCollection_AsciiString("Buffer '") + aName
+ "' has been skipped (all elements are degenerative in)");
return false;
}
theSourceMesh->ChangeDegeneratedTriNb() += aNbDegenerate;
if (myLoadingStatistic == NULL && myToPrintDebugMessages)
{
Message::SendTrace(
TCollection_AsciiString() + aNbDegenerate
+ " degenerate triangles have been skipped while reading glTF triangulation '" + aName
+ "'");
}
if (!setNbTriangles(theDestMesh, aLastTriIndex, true))
{
return false;
}
}
}
else if (theAccessor.ComponentType == RWGltf_GltfAccessorCompType_UInt8)
{
if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' defines too big array.");
return false;
}
const Standard_Integer aNbTris = (Standard_Integer)(theAccessor.Count / 3);
if (!setNbTriangles(theDestMesh, aNbTris))
{
return false;
}
const size_t aStride =
theAccessor.ByteStride != 0 ? theAccessor.ByteStride : sizeof(uint8_t);
Standard_ReadBuffer aBuffer(theAccessor.Count * aStride, aStride);
Standard_Integer aLastTriIndex = 0;
for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
{
if (const uint8_t* anIndex0 = aBuffer.ReadChunk<uint8_t>(theStream))
{
aVec3.ChangeValue(1) = THE_LOWER_NODE_INDEX + (Standard_Integer)*anIndex0;
}
if (const uint8_t* anIndex1 = aBuffer.ReadChunk<uint8_t>(theStream))
{
aVec3.ChangeValue(2) = THE_LOWER_NODE_INDEX + (Standard_Integer)*anIndex1;
}
if (const uint8_t* anIndex2 = aBuffer.ReadChunk<uint8_t>(theStream))
{
aVec3.ChangeValue(3) = THE_LOWER_NODE_INDEX + (Standard_Integer)*anIndex2;
}
else
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error.");
return false;
}
const Standard_Integer wasSet =
setTriangle(theDestMesh, THE_LOWER_TRI_INDEX + aLastTriIndex, aVec3);
if (!wasSet)
{
reportError(TCollection_AsciiString("Buffer '") + aName
+ "' refers to invalid indices.");
}
if (wasSet > 0)
{
aLastTriIndex++;
}
}
const Standard_Integer aNbDegenerate = aNbTris - aLastTriIndex;
if (aNbDegenerate > 0)
{
if (aNbDegenerate == aNbTris)
{
Message::SendWarning(TCollection_AsciiString("Buffer '") + aName
+ "' has been skipped (all elements are degenerative in)");
return false;
}
theSourceMesh->ChangeDegeneratedTriNb() += aNbDegenerate;
if (myLoadingStatistic == NULL && myToPrintDebugMessages)
{
Message::SendTrace(
TCollection_AsciiString() + aNbDegenerate
+ " degenerate triangles have been skipped while reading glTF triangulation '" + aName
+ "'");
}
if (!setNbTriangles(theDestMesh, aLastTriIndex, true))
{
return false;
}
}
}
else
{
break;
}
break;
}
case RWGltf_GltfArrayType_Position: {
if (theAccessor.ComponentType != RWGltf_GltfAccessorCompType_Float32
|| theAccessor.Type != RWGltf_GltfAccessorLayout_Vec3)
{
break;
}
else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' defines too big array.");
return false;
}
const size_t aStride =
theAccessor.ByteStride != 0 ? theAccessor.ByteStride : sizeof(Graphic3d_Vec3);
const Standard_Integer aNbNodes = (Standard_Integer)theAccessor.Count;
if (!setNbPositionNodes(theDestMesh, aNbNodes))
{
return false;
}
Standard_ReadBuffer aBuffer(theAccessor.Count * aStride - (aStride - sizeof(Graphic3d_Vec3)),
aStride,
true);
if (!myCoordSysConverter.IsEmpty())
{
for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
{
const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3>(theStream);
if (aVec3 == NULL)
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error.");
return false;
}
gp_Pnt anXYZ(aVec3->x(), aVec3->y(), aVec3->z());
myCoordSysConverter.TransformPosition(anXYZ.ChangeCoord());
setNodePosition(theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, anXYZ);
}
}
else
{
for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
{
const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3>(theStream);
if (aVec3 == NULL)
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error.");
return false;
}
setNodePosition(theDestMesh,
THE_LOWER_NODE_INDEX + aVertIter,
gp_Pnt(aVec3->x(), aVec3->y(), aVec3->z()));
}
}
break;
}
case RWGltf_GltfArrayType_Normal: {
if (theAccessor.ComponentType != RWGltf_GltfAccessorCompType_Float32
|| theAccessor.Type != RWGltf_GltfAccessorLayout_Vec3)
{
break;
}
else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' defines too big array.");
return false;
}
const size_t aStride =
theAccessor.ByteStride != 0 ? theAccessor.ByteStride : sizeof(Graphic3d_Vec3);
const Standard_Integer aNbNodes = (Standard_Integer)theAccessor.Count;
if (!setNbNormalNodes(theDestMesh, aNbNodes))
{
return false;
}
Standard_ReadBuffer aBuffer(theAccessor.Count * aStride - (aStride - sizeof(Graphic3d_Vec3)),
aStride,
true);
if (!myCoordSysConverter.IsEmpty())
{
for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
{
Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3>(theStream);
if (aVec3 == NULL)
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error.");
return false;
}
if (aVec3->SquareModulus() >= THE_NORMAL_PREC2)
{
myCoordSysConverter.TransformNormal(*aVec3);
setNodeNormal(theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, *aVec3);
}
else
{
setNodeNormal(theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, gp_Vec3f(0.0, 0.0, 1.0));
}
}
}
else
{
for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
{
const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3>(theStream);
if (aVec3 == NULL)
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error.");
return false;
}
if (aVec3->SquareModulus() >= THE_NORMAL_PREC2)
{
setNodeNormal(theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, *aVec3);
}
else
{
setNodeNormal(theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, gp_Vec3f(0.0, 0.0, 1.0));
}
}
}
break;
}
case RWGltf_GltfArrayType_TCoord0: {
if (theAccessor.ComponentType != RWGltf_GltfAccessorCompType_Float32
|| theAccessor.Type != RWGltf_GltfAccessorLayout_Vec2)
{
break;
}
else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' defines too big array.");
return false;
}
const size_t aStride =
theAccessor.ByteStride != 0 ? theAccessor.ByteStride : sizeof(Graphic3d_Vec2);
const Standard_Integer aNbNodes = (Standard_Integer)theAccessor.Count;
if (!setNbUVNodes(theDestMesh, aNbNodes))
{
return false;
}
Standard_ReadBuffer aBuffer(theAccessor.Count * aStride - (aStride - sizeof(Graphic3d_Vec2)),
aStride,
true);
for (int aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
{
Graphic3d_Vec2* aVec2 = aBuffer.ReadChunk<Graphic3d_Vec2>(theStream);
if (aVec2 == NULL)
{
reportError(TCollection_AsciiString("Buffer '") + aName + "' reading error.");
return false;
}
// Y should be flipped (relative to image layout used by OCCT)
aVec2->y() = 1.0f - aVec2->y();
setNodeUV(theDestMesh, THE_LOWER_NODE_INDEX + aVertIter, gp_Pnt2d(aVec2->x(), aVec2->y()));
}
break;
}
case RWGltf_GltfArrayType_Color:
case RWGltf_GltfArrayType_TCoord1:
case RWGltf_GltfArrayType_Joint:
case RWGltf_GltfArrayType_Weight: {
return true;
}
case RWGltf_GltfArrayType_UNKNOWN: {
return false;
}
}
return true;
}