0030239: Visualization, Graphic3d_ArrayOfPrimitives - pass Graphic3d_ArrayFlags bitma...
[occt.git] / src / Graphic3d / Graphic3d_ArrayOfPrimitives.cxx
1 // Created on: 2000-06-16
2 // Copyright (c) 2000-2014 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 <Graphic3d_ArrayOfPrimitives.hxx>
16
17 #include <Graphic3d_ArrayOfPoints.hxx>
18 #include <Graphic3d_ArrayOfSegments.hxx>
19 #include <Graphic3d_ArrayOfPolylines.hxx>
20 #include <Graphic3d_ArrayOfTriangles.hxx>
21 #include <Graphic3d_ArrayOfTriangleStrips.hxx>
22 #include <Graphic3d_ArrayOfTriangleFans.hxx>
23 #include <Graphic3d_ArrayOfQuadrangles.hxx>
24 #include <Graphic3d_ArrayOfQuadrangleStrips.hxx>
25 #include <Graphic3d_ArrayOfPolygons.hxx>
26
27 #include <NCollection_AlignedAllocator.hxx>
28 #include <TCollection_AsciiString.hxx>
29
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfPrimitives, Standard_Transient)
34
35 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfPoints,           Graphic3d_ArrayOfPrimitives)
36 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfSegments,         Graphic3d_ArrayOfPrimitives)
37 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfPolylines,        Graphic3d_ArrayOfPrimitives)
38 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfTriangles,        Graphic3d_ArrayOfPrimitives)
39 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfTriangleStrips,   Graphic3d_ArrayOfPrimitives)
40 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfTriangleFans,     Graphic3d_ArrayOfPrimitives)
41 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfQuadrangles,      Graphic3d_ArrayOfPrimitives)
42 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfQuadrangleStrips, Graphic3d_ArrayOfPrimitives)
43 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_ArrayOfPolygons,         Graphic3d_ArrayOfPrimitives)
44
45 // =======================================================================
46 // function : init
47 // purpose  :
48 // =======================================================================
49 void Graphic3d_ArrayOfPrimitives::init (Graphic3d_TypeOfPrimitiveArray theType,
50                                         Standard_Integer theMaxVertexs,
51                                         Standard_Integer theMaxBounds,
52                                         Standard_Integer theMaxEdges,
53                                         Graphic3d_ArrayFlags theArrayOptions)
54 {
55   myType = theType;
56   myVNor = 0;
57   myVTex = 0;
58   myVCol = 0;
59   myAttribs.Nullify();
60   myIndices.Nullify();
61   myBounds.Nullify();
62
63   Handle(NCollection_AlignedAllocator) anAlloc = new NCollection_AlignedAllocator (16);
64   myAttribs = new Graphic3d_Buffer (anAlloc);
65   if (theMaxVertexs < 1)
66   {
67     return;
68   }
69
70   if (theMaxEdges > 0)
71   {
72     myIndices = new Graphic3d_IndexBuffer (anAlloc);
73     if (theMaxVertexs < Standard_Integer(USHRT_MAX))
74     {
75       if (!myIndices->Init<unsigned short> (theMaxEdges))
76       {
77         myIndices.Nullify();
78         return;
79       }
80     }
81     else
82     {
83       if (!myIndices->Init<unsigned int> (theMaxEdges))
84       {
85         myIndices.Nullify();
86         return;
87       }
88     }
89     myIndices->NbElements = 0;
90   }
91
92   Graphic3d_Attribute anAttribs[4];
93   Standard_Integer    aNbAttribs = 0;
94   anAttribs[aNbAttribs].Id       = Graphic3d_TOA_POS;
95   anAttribs[aNbAttribs].DataType = Graphic3d_TOD_VEC3;
96   ++aNbAttribs;
97   if ((theArrayOptions & Graphic3d_ArrayFlags_VertexNormal) != 0)
98   {
99     anAttribs[aNbAttribs].Id       = Graphic3d_TOA_NORM;
100     anAttribs[aNbAttribs].DataType = Graphic3d_TOD_VEC3;
101     ++aNbAttribs;
102   }
103   if ((theArrayOptions & Graphic3d_ArrayFlags_VertexTexel) != 0)
104   {
105     anAttribs[aNbAttribs].Id       = Graphic3d_TOA_UV;
106     anAttribs[aNbAttribs].DataType = Graphic3d_TOD_VEC2;
107     ++aNbAttribs;
108   }
109   if ((theArrayOptions & Graphic3d_ArrayFlags_VertexColor) != 0)
110   {
111     anAttribs[aNbAttribs].Id       = Graphic3d_TOA_COLOR;
112     anAttribs[aNbAttribs].DataType = Graphic3d_TOD_VEC4UB;
113     ++aNbAttribs;
114   }
115
116   if (!myAttribs->Init (theMaxVertexs, anAttribs, aNbAttribs))
117   {
118     myAttribs.Nullify();
119     myIndices.Nullify();
120     return;
121   }
122   myAttribs->NbElements = 0;
123   memset (myAttribs->ChangeData (0), 0, size_t(myAttribs->Stride) * size_t(myAttribs->NbMaxElements()));
124
125   if (theMaxBounds > 0)
126   {
127     myBounds = new Graphic3d_BoundBuffer (anAlloc);
128     if (!myBounds->Init (theMaxBounds, (theArrayOptions & Graphic3d_ArrayFlags_BoundColor) != 0))
129     {
130       myAttribs.Nullify();
131       myIndices.Nullify();
132       myBounds .Nullify();
133       return;
134     }
135     myBounds->NbBounds = 0;
136   }
137
138   for (Standard_Integer anAttribIter = 0; anAttribIter < aNbAttribs; ++anAttribIter)
139   {
140     const Graphic3d_Attribute& anAttrib = anAttribs[anAttribIter];
141     switch (anAttrib.Id)
142     {
143       case Graphic3d_TOA_POS:
144       case Graphic3d_TOA_CUSTOM:
145         break;
146       case Graphic3d_TOA_NORM:
147       {
148         myVNor = static_cast<Standard_Byte>(myAttribs->AttributeOffset (anAttribIter));
149         break;
150       }
151       case Graphic3d_TOA_UV:
152       {
153         myVTex = static_cast<Standard_Byte>(myAttribs->AttributeOffset (anAttribIter));
154         break;
155       }
156       case Graphic3d_TOA_COLOR:
157       {
158         myVCol = static_cast<Standard_Byte>(myAttribs->AttributeOffset (anAttribIter));
159         break;
160       }
161     }
162   }
163 }
164
165 // =======================================================================
166 // function : ~Graphic3d_ArrayOfPrimitives
167 // purpose  :
168 // =======================================================================
169 Graphic3d_ArrayOfPrimitives::~Graphic3d_ArrayOfPrimitives()
170 {
171   myVNor = 0;
172   myVTex = 0;
173   myVCol = 0;
174   myIndices.Nullify();
175   myAttribs.Nullify();
176   myBounds .Nullify();
177 }
178
179 // =======================================================================
180 // function : AddBound
181 // purpose  :
182 // =======================================================================
183 Standard_Integer Graphic3d_ArrayOfPrimitives::AddBound (const Standard_Integer theEdgeNumber)
184 {
185   Standard_OutOfRange_Raise_if (myBounds.IsNull() || myBounds->NbBounds >= myBounds->NbMaxBounds, "TOO many BOUND");
186   myBounds->Bounds[myBounds->NbBounds] = theEdgeNumber;
187   return ++myBounds->NbBounds;
188 }
189
190 // =======================================================================
191 // function : AddBound
192 // purpose  :
193 // =======================================================================
194 Standard_Integer Graphic3d_ArrayOfPrimitives::AddBound (const Standard_Integer theEdgeNumber,
195                                                         const Standard_Real    theR,
196                                                         const Standard_Real    theG,
197                                                         const Standard_Real    theB)
198 {
199   Standard_OutOfRange_Raise_if (myBounds.IsNull() || myBounds->NbBounds >= myBounds->NbMaxBounds, "TOO many BOUND");
200   myBounds->Bounds[myBounds->NbBounds] = theEdgeNumber;
201   ++myBounds->NbBounds;
202   SetBoundColor (myBounds->NbBounds, theR, theG, theB);
203   return myBounds->NbBounds;
204 }
205
206 // =======================================================================
207 // function : AddEdge
208 // purpose  :
209 // =======================================================================
210 Standard_Integer Graphic3d_ArrayOfPrimitives::AddEdge (const Standard_Integer theVertexIndex)
211 {
212   Standard_OutOfRange_Raise_if (myIndices.IsNull() || myIndices->NbElements >= myIndices->NbMaxElements(), "TOO many EDGE");
213   Standard_OutOfRange_Raise_if (theVertexIndex < 1 || theVertexIndex > myAttribs->NbElements, "BAD VERTEX index");
214   const Standard_Integer aVertIndex = theVertexIndex - 1;
215   myIndices->SetIndex (myIndices->NbElements, aVertIndex);
216   return ++myIndices->NbElements;
217 }
218
219 // =======================================================================
220 // function : StringType
221 // purpose  :
222 // =======================================================================
223 Standard_CString Graphic3d_ArrayOfPrimitives::StringType() const
224 {
225   switch (myType)
226   {
227     case Graphic3d_TOPA_POINTS:           return "ArrayOfPoints";
228     case Graphic3d_TOPA_SEGMENTS:         return "ArrayOfSegments";
229     case Graphic3d_TOPA_POLYLINES:        return "ArrayOfPolylines";
230     case Graphic3d_TOPA_TRIANGLES:        return "ArrayOfTriangles";
231     case Graphic3d_TOPA_TRIANGLESTRIPS:   return "ArrayOfTriangleStrips";
232     case Graphic3d_TOPA_TRIANGLEFANS:     return "ArrayOfTriangleFans";
233     case Graphic3d_TOPA_LINES_ADJACENCY:          return "ArrayOfLinesAdjacency";
234     case Graphic3d_TOPA_LINE_STRIP_ADJACENCY:     return "ArrayOfLineStripAdjacency";
235     case Graphic3d_TOPA_TRIANGLES_ADJACENCY:      return "ArrayOfTrianglesAdjacency";
236     case Graphic3d_TOPA_TRIANGLE_STRIP_ADJACENCY: return "ArrayOfTriangleStripAdjacency";
237     case Graphic3d_TOPA_QUADRANGLES:      return "ArrayOfQuadrangles";
238     case Graphic3d_TOPA_QUADRANGLESTRIPS: return "ArrayOfQuadrangleStrips";
239     case Graphic3d_TOPA_POLYGONS:         return "ArrayOfPolygons";
240     case Graphic3d_TOPA_UNDEFINED:        return "UndefinedArray";
241   }
242   return "UndefinedArray";
243 }
244
245 // =======================================================================
246 // function : ItemNumber
247 // purpose  :
248 // =======================================================================
249 Standard_Integer Graphic3d_ArrayOfPrimitives::ItemNumber() const
250 {
251   if (myAttribs.IsNull())
252   {
253     return -1;
254   }
255
256   switch (myType)
257   {
258     case Graphic3d_TOPA_POINTS:           return myAttribs->NbElements;
259     case Graphic3d_TOPA_POLYLINES:
260     case Graphic3d_TOPA_POLYGONS:         return !myBounds.IsNull() ? myBounds->NbBounds : 1;
261     case Graphic3d_TOPA_SEGMENTS:         return myIndices.IsNull() || myIndices->NbElements < 1
262                                                ? myAttribs->NbElements / 2
263                                                : myIndices->NbElements / 2;
264     case Graphic3d_TOPA_TRIANGLES:        return myIndices.IsNull() || myIndices->NbElements < 1
265                                                ? myAttribs->NbElements / 3
266                                                : myIndices->NbElements / 3;
267     case Graphic3d_TOPA_QUADRANGLES:      return myIndices.IsNull() || myIndices->NbElements < 1
268                                                ? myAttribs->NbElements / 4
269                                                : myIndices->NbElements / 4;
270     case Graphic3d_TOPA_TRIANGLESTRIPS:   return !myBounds.IsNull()
271                                                ? myAttribs->NbElements - 2 * myBounds->NbBounds
272                                                : myAttribs->NbElements - 2;
273     case Graphic3d_TOPA_QUADRANGLESTRIPS: return !myBounds.IsNull()
274                                                ? myAttribs->NbElements / 2 - myBounds->NbBounds
275                                                : myAttribs->NbElements / 2 - 1;
276     case Graphic3d_TOPA_TRIANGLEFANS:     return !myBounds.IsNull()
277                                                ? myAttribs->NbElements - 2 * myBounds->NbBounds
278                                                : myAttribs->NbElements - 2;
279     case Graphic3d_TOPA_LINES_ADJACENCY:  return myIndices.IsNull() || myIndices->NbElements < 1
280                                                ? myAttribs->NbElements / 4
281                                                : myIndices->NbElements / 4;
282     case Graphic3d_TOPA_LINE_STRIP_ADJACENCY: return !myBounds.IsNull()
283                                                     ? myAttribs->NbElements - 4 * myBounds->NbBounds
284                                                     : myAttribs->NbElements - 4;
285     case Graphic3d_TOPA_TRIANGLES_ADJACENCY: return myIndices.IsNull() || myIndices->NbElements < 1
286                                                   ? myAttribs->NbElements / 6
287                                                   : myIndices->NbElements / 6;
288     case Graphic3d_TOPA_TRIANGLE_STRIP_ADJACENCY: return !myBounds.IsNull()
289                                                 ? myAttribs->NbElements - 4 * myBounds->NbBounds
290                                                 : myAttribs->NbElements - 4;
291     case Graphic3d_TOPA_UNDEFINED:        return -1;
292   }
293   return -1;
294 }
295
296 // =======================================================================
297 // function : IsValid
298 // purpose  :
299 // =======================================================================
300 Standard_Boolean Graphic3d_ArrayOfPrimitives::IsValid()
301 {
302   if (myAttribs.IsNull())
303   {
304     return Standard_False;
305   }
306
307   Standard_Integer nvertexs = myAttribs->NbElements;
308   Standard_Integer nbounds  = myBounds.IsNull()  ? 0 : myBounds->NbBounds;
309   Standard_Integer nedges   = myIndices.IsNull() ? 0 : myIndices->NbElements;
310   switch (myType)
311   {
312     case Graphic3d_TOPA_POINTS:
313       if (nvertexs < 1)
314       {
315         return Standard_False;
316       }
317       break;
318     case Graphic3d_TOPA_POLYLINES:
319       if (nedges > 0
320        && nedges < 2)
321       {
322         return Standard_False;
323       }
324       if (nvertexs < 2)
325       {
326         return Standard_False;
327       }
328       break;
329     case Graphic3d_TOPA_SEGMENTS:
330       if (nvertexs < 2)
331       {
332         return Standard_False;
333       }
334       break;
335     case Graphic3d_TOPA_POLYGONS:
336       if (nedges > 0
337        && nedges < 3)
338       {
339         return Standard_False;
340       }
341       if (nvertexs < 3)
342       {
343         return Standard_False;
344       }
345       break;
346     case Graphic3d_TOPA_TRIANGLES:
347       if (nedges > 0)
348       {
349         if (nedges < 3
350          || nedges % 3 != 0)
351         {
352           if (nedges <= 3)
353           {
354             return Standard_False;
355           }
356           myIndices->NbElements = 3 * (nedges / 3);
357         }
358       }
359       else if (nvertexs < 3
360             || nvertexs % 3 != 0 )
361       {
362         if (nvertexs <= 3)
363         {
364           return Standard_False;
365         }
366         myAttribs->NbElements = 3 * (nvertexs / 3);
367       }
368       break;
369     case Graphic3d_TOPA_QUADRANGLES:
370       if (nedges > 0)
371       {
372         if (nedges < 4
373          || nedges % 4 != 0)
374         {
375           if (nedges <= 4)
376           {
377             return Standard_False;
378           }
379           myIndices->NbElements = 4 * (nedges / 4);
380         }
381       }
382       else if (nvertexs < 4
383             || nvertexs % 4 != 0)
384       {
385         if (nvertexs <= 4)
386         {
387           return Standard_False;
388         }
389         myAttribs->NbElements = 4 * (nvertexs / 4);
390       }
391       break;
392     case Graphic3d_TOPA_TRIANGLEFANS:
393     case Graphic3d_TOPA_TRIANGLESTRIPS:
394       if (nvertexs < 3)
395       {
396         return Standard_False;
397       }
398       break;
399     case Graphic3d_TOPA_QUADRANGLESTRIPS:
400       if (nvertexs < 4)
401       {
402         return Standard_False;
403       }
404       break;
405     case Graphic3d_TOPA_LINES_ADJACENCY:
406     case Graphic3d_TOPA_LINE_STRIP_ADJACENCY:
407       if (nvertexs < 4)
408       {
409         return Standard_False;
410       }
411       break;
412     case Graphic3d_TOPA_TRIANGLES_ADJACENCY:
413     case Graphic3d_TOPA_TRIANGLE_STRIP_ADJACENCY:
414       if (nvertexs < 6)
415       {
416         return Standard_False;
417       }
418       break;
419     case Graphic3d_TOPA_UNDEFINED:
420     default:
421       return Standard_False;
422   }
423
424   // total number of edges(vertices) in bounds should be the same as variable
425   // of total number of defined edges(vertices); if no edges - only vertices
426   // could be in bounds.
427   if (nbounds > 0)
428   {
429     Standard_Integer n = 0;
430     for (Standard_Integer aBoundIter = 0; aBoundIter < nbounds; ++aBoundIter)
431     {
432       n += myBounds->Bounds[aBoundIter];
433     }
434     if (nedges > 0
435      && n != nedges)
436     {
437       if (nedges <= n)
438       {
439         return Standard_False;
440       }
441       myIndices->NbElements = n;
442     }
443     else if (nedges == 0
444           && n != nvertexs)
445     {
446       if (nvertexs <= n)
447       {
448         return Standard_False;
449       }
450       myAttribs->NbElements = n;
451     }
452   }
453
454   // check that edges (indexes to an array of vertices) are in range.
455   if (nedges > 0)
456   {
457     for (Standard_Integer anEdgeIter = 0; anEdgeIter < nedges; ++anEdgeIter)
458     {
459       if (myIndices->Index (anEdgeIter) >= myAttribs->NbElements)
460       {
461         return Standard_False;
462       }
463     }
464   }
465   return Standard_True;
466 }