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 | |
27 | namespace |
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 | |
34 | IMPLEMENT_STANDARD_RTTIEXT(RWGltf_TriangulationReader, RWGltf_PrimitiveArrayReader) |
35 | |
36 | // ======================================================================= |
37 | // function : RWGltf_TriangulationReader |
38 | // purpose : |
39 | // ======================================================================= |
40 | RWGltf_TriangulationReader::RWGltf_TriangulationReader() |
41 | { |
42 | // |
43 | } |
44 | |
45 | // ======================================================================= |
46 | // function : reset |
47 | // purpose : |
48 | // ======================================================================= |
49 | void 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 | // ======================================================================= |
70 | Handle(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 | // ======================================================================= |
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) |
111 | { |
112 | if (theMode != RWGltf_GltfPrimitiveMode_Triangles) |
113 | { |
a87b1b37 |
114 | Message::SendWarning (TCollection_AsciiString("Buffer '") + theName + "' skipped unsupported primitive array"); |
0a419c51 |
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 | |
e2550e48 |
286 | Standard_ReadBuffer aBuffer (theAccessor.Count * aStride - (aStride - sizeof(Graphic3d_Vec3)), aStride, true); |
0a419c51 |
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 | } |
e2550e48 |
339 | Standard_ReadBuffer aBuffer (theAccessor.Count * aStride - (aStride - sizeof(Graphic3d_Vec3)), aStride, true); |
0a419c51 |
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 | |
e2550e48 |
405 | Standard_ReadBuffer aBuffer (theAccessor.Count * aStride - (aStride - sizeof(Graphic3d_Vec2)), aStride, true); |
0a419c51 |
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 | } |