0032171: Data Exchange - RWGltf_TriangulationReader doesn't copy cached bounding box
[occt.git] / src / RWGltf / RWGltf_TriangulationReader.cxx
1 // Author: Kirill Gavrilov
2 // Copyright (c) 2019 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
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.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #include <RWGltf_TriangulationReader.hxx>
16
17 #include <RWGltf_GltfLatePrimitiveArray.hxx>
18 #include <RWMesh_CoordinateSystemConverter.hxx>
19 #include <Standard_ReadBuffer.hxx>
20
21 #include <BRep_Builder.hxx>
22 #include <Graphic3d_Vec.hxx>
23 #include <Message.hxx>
24 #include <Message_Messenger.hxx>
25 #include <TopoDS.hxx>
26 #include <TopoDS_Iterator.hxx>
27
28 namespace
29 {
30   static const Standard_Integer   THE_LOWER_TRI_INDEX  = 1;
31   static const Standard_Integer   THE_LOWER_NODE_INDEX = 1;
32   static const Standard_ShortReal THE_NORMAL_PREC2 = 0.001f;
33 }
34
35 IMPLEMENT_STANDARD_RTTIEXT(RWGltf_TriangulationReader, RWGltf_PrimitiveArrayReader)
36
37 // =======================================================================
38 // function : RWGltf_TriangulationReader
39 // purpose  :
40 // =======================================================================
41 RWGltf_TriangulationReader::RWGltf_TriangulationReader()
42 : myIsDoublePrecision (false)
43 {
44   //
45 }
46
47 // =======================================================================
48 // function : reset
49 // purpose  :
50 // =======================================================================
51 void RWGltf_TriangulationReader::reset()
52 {
53   myTriangulation = new Poly_Triangulation();
54   myTriangulation->SetDoublePrecision (myIsDoublePrecision);
55 }
56
57 // =======================================================================
58 // function : result
59 // purpose  :
60 // =======================================================================
61 Handle(Poly_Triangulation) RWGltf_TriangulationReader::result()
62 {
63   if (myTriangulation->NbNodes() < 1)
64   {
65     return Handle(Poly_Triangulation)();
66   }
67
68   if (myTriangulation->NbTriangles() < 1)
69   {
70     // reconstruct indexes
71     const Standard_Integer aNbTris = myTriangulation->NbNodes() / 3;
72     if (!setNbTriangles (aNbTris))
73     {
74       return Handle(Poly_Triangulation)();
75     }
76
77     for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
78     {
79       setTriangle (THE_LOWER_TRI_INDEX + aTriIter,
80                    Poly_Triangle (THE_LOWER_NODE_INDEX + aTriIter * 3 + 0,
81                                   THE_LOWER_NODE_INDEX + aTriIter * 3 + 1,
82                                   THE_LOWER_NODE_INDEX + aTriIter * 3 + 2));
83     }
84   }
85
86   return myTriangulation;
87 }
88
89 // =======================================================================
90 // function : load
91 // purpose  :
92 // =======================================================================
93 bool RWGltf_TriangulationReader::load (const Handle(RWGltf_GltfLatePrimitiveArray)& theMesh,
94                                        const Handle(OSD_FileSystem)& theFileSystem)
95 {
96   if (!RWGltf_PrimitiveArrayReader::load (theMesh, theFileSystem))
97   {
98     return false;
99   }
100   if (!theMesh->CachedMinMax().IsVoid())
101   {
102     myTriangulation->SetCachedMinMax (theMesh->CachedMinMax());
103   }
104   return true;
105 }
106
107 // =======================================================================
108 // function : readBuffer
109 // purpose  :
110 // =======================================================================
111 bool RWGltf_TriangulationReader::readBuffer (std::istream& theStream,
112                                              const TCollection_AsciiString& theName,
113                                              const RWGltf_GltfAccessor& theAccessor,
114                                              RWGltf_GltfArrayType theType,
115                                              RWGltf_GltfPrimitiveMode theMode)
116 {
117   if (theMode != RWGltf_GltfPrimitiveMode_Triangles)
118   {
119     Message::SendWarning (TCollection_AsciiString("Buffer '") + theName + "' skipped unsupported primitive array");
120     return true;
121   }
122
123   switch (theType)
124   {
125     case RWGltf_GltfArrayType_Indices:
126     {
127       if (theAccessor.Type != RWGltf_GltfAccessorLayout_Scalar)
128       {
129         break;
130       }
131
132       Poly_Triangle aVec3;
133       if (theAccessor.ComponentType == RWGltf_GltfAccessorCompType_UInt16)
134       {
135         if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
136         {
137           reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
138           return false;
139         }
140
141         const Standard_Integer aNbTris = (Standard_Integer )(theAccessor.Count / 3);
142         if (!setNbTriangles (aNbTris))
143         {
144           return false;
145         }
146         const size_t aStride = theAccessor.ByteStride != 0
147                              ? theAccessor.ByteStride
148                              : sizeof(uint16_t);
149         Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
150         for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
151         {
152           if (const uint16_t* anIndex0 = aBuffer.ReadChunk<uint16_t> (theStream))
153           {
154             aVec3.ChangeValue (1) = THE_LOWER_NODE_INDEX + *anIndex0;
155           }
156           if (const uint16_t* anIndex1 = aBuffer.ReadChunk<uint16_t> (theStream))
157           {
158             aVec3.ChangeValue (2) = THE_LOWER_NODE_INDEX + *anIndex1;
159           }
160           if (const uint16_t* anIndex2 = aBuffer.ReadChunk<uint16_t> (theStream))
161           {
162             aVec3.ChangeValue (3) = THE_LOWER_NODE_INDEX + *anIndex2;
163           }
164           else
165           {
166             reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
167             return false;
168           }
169
170           if (!setTriangle (THE_LOWER_TRI_INDEX + aTriIter, aVec3))
171           {
172             reportError (TCollection_AsciiString ("Buffer '") + theName + "' refers to invalid indices.");
173           }
174         }
175       }
176       else if (theAccessor.ComponentType == RWGltf_GltfAccessorCompType_UInt32)
177       {
178         if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
179         {
180           reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
181           return false;
182         }
183
184         const int aNbTris = (Standard_Integer )(theAccessor.Count / 3);
185         if (!setNbTriangles (aNbTris))
186         {
187           return false;
188         }
189         const size_t aStride = theAccessor.ByteStride != 0
190                              ? theAccessor.ByteStride
191                              : sizeof(uint32_t);
192         Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
193         for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
194         {
195           if (const uint32_t* anIndex0 = aBuffer.ReadChunk<uint32_t> (theStream))
196           {
197             aVec3.ChangeValue (1) = THE_LOWER_NODE_INDEX + *anIndex0;
198           }
199           if (const uint32_t* anIndex1 = aBuffer.ReadChunk<uint32_t> (theStream))
200           {
201             aVec3.ChangeValue (2) = THE_LOWER_NODE_INDEX + *anIndex1;
202           }
203           if (const uint32_t* anIndex2 = aBuffer.ReadChunk<uint32_t> (theStream))
204           {
205             aVec3.ChangeValue (3) = THE_LOWER_NODE_INDEX + *anIndex2;
206           }
207           else
208           {
209             reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
210             return false;
211           }
212
213           if (!setTriangle (THE_LOWER_TRI_INDEX + aTriIter, aVec3))
214           {
215             reportError (TCollection_AsciiString ("Buffer '") + theName + "' refers to invalid indices.");
216           }
217         }
218       }
219       else if (theAccessor.ComponentType == RWGltf_GltfAccessorCompType_UInt8)
220       {
221         if ((theAccessor.Count / 3) > std::numeric_limits<Standard_Integer>::max())
222         {
223           reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
224           return false;
225         }
226
227         const Standard_Integer aNbTris = (Standard_Integer )(theAccessor.Count / 3);
228         if (!setNbTriangles (aNbTris))
229         {
230           return false;
231         }
232         const size_t aStride = theAccessor.ByteStride != 0
233                              ? theAccessor.ByteStride
234                              : sizeof(uint8_t);
235         Standard_ReadBuffer aBuffer (theAccessor.Count * aStride, aStride);
236         for (Standard_Integer aTriIter = 0; aTriIter < aNbTris; ++aTriIter)
237         {
238           if (const uint8_t* anIndex0 = aBuffer.ReadChunk<uint8_t> (theStream))
239           {
240             aVec3.ChangeValue (1) = THE_LOWER_NODE_INDEX + (Standard_Integer )*anIndex0;
241           }
242           if (const uint8_t* anIndex1 = aBuffer.ReadChunk<uint8_t> (theStream))
243           {
244             aVec3.ChangeValue (2) = THE_LOWER_NODE_INDEX + (Standard_Integer )*anIndex1;
245           }
246           if (const uint8_t* anIndex2 = aBuffer.ReadChunk<uint8_t> (theStream))
247           {
248             aVec3.ChangeValue (3) = THE_LOWER_NODE_INDEX + (Standard_Integer )*anIndex2;
249           }
250           else
251           {
252             reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
253             return false;
254           }
255
256           if (!setTriangle (THE_LOWER_TRI_INDEX + aTriIter, aVec3))
257           {
258             reportError (TCollection_AsciiString ("Buffer '") + theName + "' refers to invalid indices.");
259           }
260         }
261       }
262       else
263       {
264         break;
265       }
266
267       break;
268     }
269     case RWGltf_GltfArrayType_Position:
270     {
271       if (theAccessor.ComponentType != RWGltf_GltfAccessorCompType_Float32
272        || theAccessor.Type != RWGltf_GltfAccessorLayout_Vec3)
273       {
274         break;
275       }
276       else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
277       {
278         reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
279         return false;
280       }
281
282       const size_t aStride = theAccessor.ByteStride != 0
283                            ? theAccessor.ByteStride
284                            : sizeof(Graphic3d_Vec3);
285       const Standard_Integer aNbNodes = (Standard_Integer )theAccessor.Count;
286       if (!setNbPositionNodes (aNbNodes))
287       {
288         return false;
289       }
290
291       Standard_ReadBuffer aBuffer (theAccessor.Count * aStride - (aStride - sizeof(Graphic3d_Vec3)), aStride, true);
292       if (!myCoordSysConverter.IsEmpty())
293       {
294         for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
295         {
296           const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
297           if (aVec3 == NULL)
298           {
299             reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
300             return false;
301           }
302
303           gp_Pnt anXYZ (aVec3->x(), aVec3->y(), aVec3->z());
304           myCoordSysConverter.TransformPosition (anXYZ.ChangeCoord());
305           setNodePosition (THE_LOWER_NODE_INDEX + aVertIter, anXYZ);
306         }
307       }
308       else
309       {
310         for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
311         {
312           const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
313           if (aVec3 == NULL)
314           {
315             reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
316             return false;
317           }
318           setNodePosition (THE_LOWER_NODE_INDEX + aVertIter, gp_Pnt (aVec3->x(), aVec3->y(), aVec3->z()));
319         }
320       }
321       break;
322     }
323     case RWGltf_GltfArrayType_Normal:
324     {
325       if (theAccessor.ComponentType != RWGltf_GltfAccessorCompType_Float32
326        || theAccessor.Type != RWGltf_GltfAccessorLayout_Vec3)
327       {
328         break;
329       }
330       else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
331       {
332         reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
333         return false;
334       }
335
336       const size_t aStride = theAccessor.ByteStride != 0
337                            ? theAccessor.ByteStride
338                            : sizeof(Graphic3d_Vec3);
339       const Standard_Integer aNbNodes = (Standard_Integer )theAccessor.Count;
340       if (!setNbNormalNodes (aNbNodes))
341       {
342         return false;
343       }
344       Standard_ReadBuffer aBuffer (theAccessor.Count * aStride - (aStride - sizeof(Graphic3d_Vec3)), aStride, true);
345       if (!myCoordSysConverter.IsEmpty())
346       {
347         for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
348         {
349           Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
350           if (aVec3 == NULL)
351           {
352             reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
353             return false;
354           }
355           if (aVec3->SquareModulus() >= THE_NORMAL_PREC2)
356           {
357             myCoordSysConverter.TransformNormal (*aVec3);
358             setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (aVec3->x(), aVec3->y(), aVec3->z()));
359           }
360           else
361           {
362             setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (0.0, 0.0, 1.0));
363           }
364         }
365       }
366       else
367       {
368         for (Standard_Integer aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
369         {
370           const Graphic3d_Vec3* aVec3 = aBuffer.ReadChunk<Graphic3d_Vec3> (theStream);
371           if (aVec3 == NULL)
372           {
373             reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
374             return false;
375           }
376           if (aVec3->SquareModulus() >= THE_NORMAL_PREC2)
377           {
378             setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (aVec3->x(), aVec3->y(), aVec3->z()));
379           }
380           else
381           {
382             setNodeNormal (THE_LOWER_NODE_INDEX + aVertIter, gp_Dir (0.0, 0.0, 1.0));
383           }
384         }
385       }
386       break;
387     }
388     case RWGltf_GltfArrayType_TCoord0:
389     {
390       if (theAccessor.ComponentType != RWGltf_GltfAccessorCompType_Float32
391        || theAccessor.Type != RWGltf_GltfAccessorLayout_Vec2)
392       {
393         break;
394       }
395       else if (theAccessor.Count > std::numeric_limits<Standard_Integer>::max())
396       {
397         reportError (TCollection_AsciiString ("Buffer '") + theName + "' defines too big array.");
398         return false;
399       }
400
401       const size_t aStride = theAccessor.ByteStride != 0
402                            ? theAccessor.ByteStride
403                            : sizeof(Graphic3d_Vec2);
404       const Standard_Integer aNbNodes = (Standard_Integer )theAccessor.Count;
405       if (!setNbUVNodes (aNbNodes))
406       {
407         return false;
408       }
409
410       Standard_ReadBuffer aBuffer (theAccessor.Count * aStride - (aStride - sizeof(Graphic3d_Vec2)), aStride, true);
411       for (int aVertIter = 0; aVertIter < aNbNodes; ++aVertIter)
412       {
413         Graphic3d_Vec2* aVec2 = aBuffer.ReadChunk<Graphic3d_Vec2> (theStream);
414         if (aVec2 == NULL)
415         {
416           reportError (TCollection_AsciiString ("Buffer '") + theName + "' reading error.");
417           return false;
418         }
419
420         // Y should be flipped (relative to image layout used by OCCT)
421         aVec2->y() = 1.0f - aVec2->y();
422         setNodeUV (THE_LOWER_NODE_INDEX + aVertIter, gp_Pnt2d (aVec2->x(), aVec2->y()));
423       }
424       break;
425     }
426     case RWGltf_GltfArrayType_Color:
427     case RWGltf_GltfArrayType_TCoord1:
428     case RWGltf_GltfArrayType_Joint:
429     case RWGltf_GltfArrayType_Weight:
430     {
431       return true;
432     }
433     case RWGltf_GltfArrayType_UNKNOWN:
434     {
435       return false;
436     }
437   }
438   return true;
439 }