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