1 // Author: Kirill Gavrilov
2 // Copyright (c) 2019 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
15 #include <RWGltf_TriangulationReader.hxx>
17 #include <RWMesh_CoordinateSystemConverter.hxx>
18 #include <Standard_ReadBuffer.hxx>
20 #include <BRep_Builder.hxx>
21 #include <Graphic3d_Vec.hxx>
22 #include <Message.hxx>
23 #include <Message_Messenger.hxx>
25 #include <TopoDS_Iterator.hxx>
29 static const Standard_Integer THE_LOWER_TRI_INDEX = 1;
30 static const Standard_Integer THE_LOWER_NODE_INDEX = 1;
31 static const Standard_ShortReal THE_NORMAL_PREC2 = 0.001f;
34 IMPLEMENT_STANDARD_RTTIEXT(RWGltf_TriangulationReader, RWGltf_PrimitiveArrayReader)
36 // =======================================================================
37 // function : RWGltf_TriangulationReader
39 // =======================================================================
40 RWGltf_TriangulationReader::RWGltf_TriangulationReader()
45 // =======================================================================
48 // =======================================================================
49 void RWGltf_TriangulationReader::reset()
51 myTriangulation = new Poly_Triangulation (1, 1, true);
53 TColgp_Array1OfPnt anEmpty;
54 myTriangulation->ChangeNodes().Move (anEmpty);
57 TColgp_Array1OfPnt2d anEmpty;
58 myTriangulation->ChangeUVNodes().Move (anEmpty);
61 Poly_Array1OfTriangle anEmpty;
62 myTriangulation->ChangeTriangles().Move (anEmpty);
66 // =======================================================================
69 // =======================================================================
70 Handle(Poly_Triangulation) RWGltf_TriangulationReader::result()
72 if (myTriangulation->NbNodes() < 1)
74 return Handle(Poly_Triangulation)();
76 if (myTriangulation->UVNodes().Size() != myTriangulation->NbNodes())
78 myTriangulation->RemoveUVNodes();
81 if (myTriangulation->NbTriangles() < 1)
83 // reconstruct indexes
84 const Standard_Integer aNbTris = myTriangulation->NbNodes() / 3;
85 if (!setNbTriangles (aNbTris))
87 return Handle(Poly_Triangulation)();
90 for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
92 setTriangle (THE_LOWER_TRI_INDEX + aTriIter,
93 Poly_Triangle (THE_LOWER_NODE_INDEX + aTriIter * 3 + 0,
94 THE_LOWER_NODE_INDEX + aTriIter * 3 + 1,
95 THE_LOWER_NODE_INDEX + aTriIter * 3 + 2));
99 return myTriangulation;
102 // =======================================================================
103 // function : readBuffer
105 // =======================================================================
106 bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
107 const TCollection_AsciiString& theName,
108 const RWGltf_GltfAccessor& theAccessor,
109 RWGltf_GltfArrayType theType,
110 RWGltf_GltfPrimitiveMode theMode)
112 if (theMode != RWGltf_GltfPrimitiveMode_Triangles)
114 Message::SendWarning (TCollection_AsciiString("Buffer '") + theName + "' skipped unsupported primitive array");
120 case RWGltf_GltfArrayType_Indices:
122 if (theAccessor.Type != RWGltf_GltfAccessorLayout_Scalar)
128 if (theAccessor.ComponentType == RWGltf_GltfAccessorCompType_UInt16)
130 if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
132 reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
136 const Standard_Integer aNbTris = (Standard_Integer )(theAccessor.Count / 3);
137 if (!setNbTriangles (aNbTris))
141 const size_t aStride = theAccessor.ByteStride != 0
142 ? theAccessor.ByteStride
144 Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
145 for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
147 if (const uint16_t* anIndex0 = aBuffer.ReadChunk<uint16_t> (theStream))
149 aVec3.ChangeValue (1) = THE_LOWER_NODE_INDEX + *anIndex0;
151 if (const uint16_t* anIndex1 = aBuffer.ReadChunk<uint16_t> (theStream))
153 aVec3.ChangeValue (2) = THE_LOWER_NODE_INDEX + *anIndex1;
155 if (const uint16_t* anIndex2 = aBuffer.ReadChunk<uint16_t> (theStream))
157 aVec3.ChangeValue (3) = THE_LOWER_NODE_INDEX + *anIndex2;
161 reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
165 if (!setTriangle (THE_LOWER_TRI_INDEX + aTriIter, aVec3))
167 reportError (TCollection_AsciiString ("Buffer '") + theName + "' refers to invalid indices.");
171 else if (theAccessor.ComponentType == RWGltf_GltfAccessorCompType_UInt32)
173 if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
175 reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
179 const int aNbTris = (Standard_Integer )(theAccessor.Count / 3);
180 if (!setNbTriangles (aNbTris))
184 const size_t aStride = theAccessor.ByteStride != 0
185 ? theAccessor.ByteStride
187 Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
188 for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
190 if (const uint32_t* anIndex0 = aBuffer.ReadChunk<uint32_t> (theStream))
192 aVec3.ChangeValue (1) = THE_LOWER_NODE_INDEX + *anIndex0;
194 if (const uint32_t* anIndex1 = aBuffer.ReadChunk<uint32_t> (theStream))
196 aVec3.ChangeValue (2) = THE_LOWER_NODE_INDEX + *anIndex1;
198 if (const uint32_t* anIndex2 = aBuffer.ReadChunk<uint32_t> (theStream))
200 aVec3.ChangeValue (3) = THE_LOWER_NODE_INDEX + *anIndex2;
204 reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
208 if (!setTriangle (THE_LOWER_TRI_INDEX + aTriIter, aVec3))
210 reportError (TCollection_AsciiString ("Buffer '") + theName + "' refers to invalid indices.");
214 else if (theAccessor.ComponentType == RWGltf_GltfAccessorCompType_UInt8)
216 if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
218 reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
222 const Standard_Integer aNbTris = (Standard_Integer )(theAccessor.Count / 3);
223 if (!setNbTriangles (aNbTris))
227 const size_t aStride = theAccessor.ByteStride != 0
228 ? theAccessor.ByteStride
230 Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
231 for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
233 if (const uint8_t* anIndex0 = aBuffer.ReadChunk<uint8_t> (theStream))
235 aVec3.ChangeValue (1) = THE_LOWER_NODE_INDEX + (Standard_Integer )*anIndex0;
237 if (const uint8_t* anIndex1 = aBuffer.ReadChunk<uint8_t> (theStream))
239 aVec3.ChangeValue (2) = THE_LOWER_NODE_INDEX + (Standard_Integer )*anIndex1;
241 if (const uint8_t* anIndex2 = aBuffer.ReadChunk<uint8_t> (theStream))
243 aVec3.ChangeValue (3) = THE_LOWER_NODE_INDEX + (Standard_Integer )*anIndex2;
247 reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
251 if (!setTriangle (THE_LOWER_TRI_INDEX + aTriIter, aVec3))
253 reportError (TCollection_AsciiString ("Buffer '") + theName + "' refers to invalid indices.");
264 case RWGltf_GltfArrayType_Position:
266 if (theAccessor.ComponentType != RWGltf_GltfAccessorCompType_Float32
267 || theAccessor.Type != RWGltf_GltfAccessorLayout_Vec3)
271 else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
273 reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
277 const size_t aStride = theAccessor.ByteStride != 0
278 ? theAccessor.ByteStride
279 : sizeof(Graphic3d_Vec3);
280 const Standard_Integer aNbNodes = (Standard_Integer )theAccessor.Count;
281 if (!setNbPositionNodes (aNbNodes))
286 Standard_ReadBuffer aBuffer (theAccessor.Count * aStride - (aStride - sizeof(Graphic3d_Vec3)), aStride, true);
287 if (!myCoordSysConverter.IsEmpty())
289 for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
291 const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
294 reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
298 gp_Pnt anXYZ (aVec3->x(), aVec3->y(), aVec3->z());
299 myCoordSysConverter.TransformPosition (anXYZ.ChangeCoord());
300 setNodePosition (THE_LOWER_NODE_INDEX + aVertIter, anXYZ);
305 for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
307 const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
310 reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
313 setNodePosition (THE_LOWER_NODE_INDEX + aVertIter, gp_Pnt (aVec3->x(), aVec3->y(), aVec3->z()));
318 case RWGltf_GltfArrayType_Normal:
320 if (theAccessor.ComponentType != RWGltf_GltfAccessorCompType_Float32
321 || theAccessor.Type != RWGltf_GltfAccessorLayout_Vec3)
325 else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
327 reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
331 const size_t aStride = theAccessor.ByteStride != 0
332 ? theAccessor.ByteStride
333 : sizeof(Graphic3d_Vec3);
334 const Standard_Integer aNbNodes = (Standard_Integer )theAccessor.Count;
335 if (!setNbNormalNodes (aNbNodes))
339 Standard_ReadBuffer aBuffer (theAccessor.Count * aStride - (aStride - sizeof(Graphic3d_Vec3)), aStride, true);
340 if (!myCoordSysConverter.IsEmpty())
342 for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
344 Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
347 reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
350 if (aVec3->SquareModulus() >= THE_NORMAL_PREC2)
352 myCoordSysConverter.TransformNormal (*aVec3);
353 setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (aVec3->x(), aVec3->y(), aVec3->z()));
357 setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (0.0, 0.0, 1.0));
363 for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
365 const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
368 reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
371 if (aVec3->SquareModulus() >= THE_NORMAL_PREC2)
373 setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (aVec3->x(), aVec3->y(), aVec3->z()));
377 setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (0.0, 0.0, 1.0));
383 case RWGltf_GltfArrayType_TCoord0:
385 if (theAccessor.ComponentType != RWGltf_GltfAccessorCompType_Float32
386 || theAccessor.Type != RWGltf_GltfAccessorLayout_Vec2)
390 else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
392 reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
396 const size_t aStride = theAccessor.ByteStride != 0
397 ? theAccessor.ByteStride
398 : sizeof(Graphic3d_Vec2);
399 const Standard_Integer aNbNodes = (Standard_Integer )theAccessor.Count;
400 if (!setNbUVNodes (aNbNodes))
405 Standard_ReadBuffer aBuffer (theAccessor.Count * aStride - (aStride - sizeof(Graphic3d_Vec2)), aStride, true);
406 for (int aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
408 Graphic3d_Vec2* aVec2 = aBuffer.ReadChunk<Graphic3d_Vec2> (theStream);
411 reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
415 // Y should be flipped (relative to image layout used by OCCT)
416 aVec2->y() = 1.0f - aVec2->y();
417 setNodeUV (THE_LOWER_NODE_INDEX + aVertIter, gp_Pnt2d (aVec2->x(), aVec2->y()));
421 case RWGltf_GltfArrayType_Color:
422 case RWGltf_GltfArrayType_TCoord1:
423 case RWGltf_GltfArrayType_Joint:
424 case RWGltf_GltfArrayType_Weight:
428 case RWGltf_GltfArrayType_UNKNOWN: