0028441: Coding Rules - move out nested Image_PixMap::ImgFormat enumeration to dedica...
[occt.git] / src / MeshVS / MeshVS_NodalColorPrsBuilder.cxx
1 // Created on: 2003-11-12
2 // Created by: Alexander SOLOVYOV
3 // Copyright (c) 2003-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #define _POLYGONES_
17
18 // if define _POLYGONES_ ColorPrsBuilder use ArrayOfPolygons for drawing faces
19
20 #include <Aspect_SequenceOfColor.hxx>
21 #include <gp_Pnt.hxx>
22 #include <Graphic3d_ArrayOfPolygons.hxx>
23 #include <Graphic3d_ArrayOfPolylines.hxx>
24 #include <Graphic3d_ArrayOfPrimitives.hxx>
25 #include <Graphic3d_ArrayOfSegments.hxx>
26 #include <Graphic3d_ArrayOfTriangles.hxx>
27 #include <Graphic3d_AspectFillArea3d.hxx>
28 #include <Graphic3d_AspectLine3d.hxx>
29 #include <Graphic3d_Group.hxx>
30 #include <Graphic3d_Texture2D.hxx>
31 #include <Graphic3d_TextureParams.hxx>
32 #include <Graphic3d_TypeOfTextureMode.hxx>
33 #include <Image_PixMap.hxx>
34 #include <MeshVS_Buffer.hxx>
35 #include <MeshVS_DataSource.hxx>
36 #include <MeshVS_DisplayModeFlags.hxx>
37 #include <MeshVS_Drawer.hxx>
38 #include <MeshVS_DrawerAttribute.hxx>
39 #include <MeshVS_HArray1OfSequenceOfInteger.hxx>
40 #include <MeshVS_Mesh.hxx>
41 #include <MeshVS_MeshPrsBuilder.hxx>
42 #include <MeshVS_NodalColorPrsBuilder.hxx>
43 #include <MeshVS_SymmetricPairHasher.hxx>
44 #include <MeshVS_Tool.hxx>
45 #include <NCollection_Map.hxx>
46 #include <NCollection_Vector.hxx>
47 #include <Prs3d_Drawer.hxx>
48 #include <Prs3d_LineAspect.hxx>
49 #include <Prs3d_Presentation.hxx>
50 #include <Prs3d_Root.hxx>
51 #include <Prs3d_ShadingAspect.hxx>
52 #include <PrsMgr_PresentationManager3d.hxx>
53 #include <Quantity_Array1OfColor.hxx>
54 #include <Quantity_Color.hxx>
55 #include <Standard_Type.hxx>
56 #include <TColStd_Array1OfInteger.hxx>
57 #include <TColStd_Array1OfReal.hxx>
58 #include <TColStd_HArray1OfReal.hxx>
59 #include <TColStd_HPackedMapOfInteger.hxx>
60 #include <TColStd_ListIteratorOfListOfInteger.hxx>
61 #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
62 #include <TColStd_SequenceOfInteger.hxx>
63
64 IMPLEMENT_STANDARD_RTTIEXT(MeshVS_NodalColorPrsBuilder,MeshVS_PrsBuilder)
65
66 /*
67   Class       : MeshVS_ImageTexture2D
68   Description : Texture for nodal presentation
69 */
70 class MeshVS_ImageTexture2D : public Graphic3d_Texture2D
71 {
72 public:
73
74   MeshVS_ImageTexture2D (const Handle(Image_PixMap)& theImg) : Graphic3d_Texture2D (theImg, Graphic3d_TOT_2D)
75   {
76     myParams->SetModulate (Standard_True);
77     myParams->SetFilter   (Graphic3d_TOTF_BILINEAR);
78   }
79
80 public:
81
82   DEFINE_STANDARD_RTTI_INLINE(MeshVS_ImageTexture2D,Graphic3d_Texture2D)
83 };
84
85 DEFINE_STANDARD_HANDLE    (MeshVS_ImageTexture2D, Graphic3d_Texture2D)
86
87
88 //================================================================
89 // Function : getNearestPow2
90 // Purpose  : Returns the nearest power of two greater than the
91 //            argument value
92 //================================================================
93 static inline Standard_Integer getNearestPow2( Standard_Integer theValue )
94 {
95   // Precaution against overflow
96   Standard_Integer aHalfMax = IntegerLast() >> 1, aRes = 1;
97   if ( theValue > aHalfMax ) theValue = aHalfMax;
98   while ( aRes < theValue ) aRes <<= 1;
99   return aRes;
100 }
101
102 /*
103   Class       : MeshVS_NodalColorPrsBuilder
104   Description : This class provides methods to create presentation of
105                 nodes with assigned color (See hxx for more description )
106 */
107
108 //================================================================
109 // Function : Constructor MeshVS_NodalColorPrsBuilder
110 // Purpose  :
111 //================================================================
112 MeshVS_NodalColorPrsBuilder::MeshVS_NodalColorPrsBuilder ( const Handle(MeshVS_Mesh)& Parent,
113                                                            const MeshVS_DisplayModeFlags& Flags,
114                                                            const Handle (MeshVS_DataSource)& DS,
115                                                            const Standard_Integer Id,
116                                                            const MeshVS_BuilderPriority& Priority )
117 : MeshVS_PrsBuilder ( Parent, Flags, DS, Id, Priority ),
118   myUseTexture( Standard_False ),
119   myInvalidColor( Quantity_NOC_GRAY )
120 {
121   SetExcluding ( Standard_True );
122 }
123
124 //================================================================
125 // Function : Build
126 // Purpose  :
127 //================================================================
128 void MeshVS_NodalColorPrsBuilder::Build ( const Handle(Prs3d_Presentation)& Prs,
129                                           const TColStd_PackedMapOfInteger& IDs,
130                                           TColStd_PackedMapOfInteger& IDsToExclude,
131                                           const Standard_Boolean IsElement,
132                                           const Standard_Integer DisplayMode) const
133 {
134   Handle (MeshVS_DataSource) aSource = GetDataSource();
135   Handle (MeshVS_Drawer)     aDrawer = GetDrawer();
136   if ( aSource.IsNull() || aDrawer.IsNull() )
137     return;
138
139   Standard_Integer aMaxFaceNodes;
140   if ( !aDrawer->GetInteger ( MeshVS_DA_MaxFaceNodes, aMaxFaceNodes ) || aMaxFaceNodes <= 0 )
141     return;
142
143   MeshVS_Buffer aCoordsBuf (3*aMaxFaceNodes*sizeof(Standard_Real));
144   TColStd_Array1OfReal aCoords ( aCoordsBuf, 1, 3 * aMaxFaceNodes );
145   Standard_Integer NbNodes;
146   MeshVS_EntityType aType;
147
148   if ( !( DisplayMode & GetFlags() ) || !IsElement )
149     return;
150
151   if ( (myUseTexture && ( !myTextureCoords.Extent() || !myTextureColorMap.Length() )) ||
152        (!myUseTexture && !myNodeColorMap.Extent()) )
153     return;
154
155   // subtract the hidden elements and ids to exclude (to minimize allocated memory)
156   TColStd_PackedMapOfInteger anIDs;
157   anIDs.Assign( IDs );
158   Handle(TColStd_HPackedMapOfInteger) aHiddenElems = myParentMesh->GetHiddenElems();
159   if ( !aHiddenElems.IsNull() )
160     anIDs.Subtract( aHiddenElems->Map() );
161   anIDs.Subtract( IDsToExclude );
162
163   Standard_Boolean IsReflect = Standard_False, IsMeshSmoothShading = Standard_False;
164   aDrawer->GetBoolean( MeshVS_DA_ColorReflection, IsReflect );
165   aDrawer->GetBoolean( MeshVS_DA_SmoothShading,   IsMeshSmoothShading );
166
167   // Following parameter are used for texture presentation only
168   int nbColors = 0; // Number of colors from color map
169   int nbTextureColors = 0; // Number of colors in texture (it will be pow of 2)
170   if ( myUseTexture )
171   {
172     nbColors = myTextureColorMap.Length();
173     nbTextureColors = getNearestPow2( nbColors );
174   }
175
176   Standard_Integer aSize = anIDs.Extent();
177
178   // Calculate maximum possible number of vertices and bounds
179   Handle( MeshVS_HArray1OfSequenceOfInteger ) aTopo;
180   Standard_Integer PolygonVerticesFor3D = 0, PolygonBoundsFor3D = 0;
181   TColStd_MapIteratorOfPackedMapOfInteger it (anIDs);
182   for( ; it.More(); it.Next() )
183   {
184     Standard_Integer aKey = it.Key();
185     if ( aSource->Get3DGeom( aKey, NbNodes, aTopo ) )
186       MeshVS_MeshPrsBuilder::HowManyPrimitives
187       ( aTopo, Standard_True, Standard_False, NbNodes,
188       PolygonVerticesFor3D, PolygonBoundsFor3D );
189   }
190
191   // Draw faces with nodal color
192   // OCC20644 Use "plastic" material as it is "non-physic" and so it is easier
193   // to get the required colors (see TelUpdateMaterial() function in OpenGl_attri.c)
194   Graphic3d_MaterialAspect aMaterial[ 2 ];
195   aMaterial[ 0 ] = Graphic3d_MaterialAspect( Graphic3d_NOM_PLASTIC );
196   aMaterial[ 1 ] = Graphic3d_MaterialAspect( Graphic3d_NOM_PLASTIC );
197   Standard_Integer i;
198   for ( i = 0; i < 2; i++ )
199   {
200     if ( !IsReflect )
201     {
202       aMaterial[ i ].SetReflectionModeOff( Graphic3d_TOR_SPECULAR );
203       aMaterial[ i ].SetReflectionModeOff( Graphic3d_TOR_AMBIENT );
204       aMaterial[ i ].SetReflectionModeOff( Graphic3d_TOR_DIFFUSE );
205       aMaterial[ i ].SetReflectionModeOff( Graphic3d_TOR_EMISSION );
206     }
207     else{
208       // OCC20644 Using the material with reflection properties same as in
209       // ElementalColorPrsBuilder, to get the same colors.
210       // Additionally, ambient and diffuse coefficients are used below to scale incoming colors,
211       // to simulate TelUpdateMaterial() function from OpenGl_attri.c.
212       // This is mandatory, as these "scaled" colors are then passed directly to OpenGL
213       // as ambient and diffuse colors of the current material using glColorMaterial().
214       // In ElementalColorPrsBuilder we do not need to do scale the colors, as this
215       // is done by TelUpdateMaterial().
216       // 0.5 is used to have the colors in 3D maximally similar to those in the color scale.
217       // This is possible when the sum of all coefficient is equal to 1.
218       aMaterial[i].SetAmbient( .5 );
219       aMaterial[i].SetDiffuse( .5 );
220       aMaterial[i].SetSpecular( 0. );
221       aMaterial[i].SetEmissive( 0. );
222     }
223
224  }
225
226
227   // Create array of polygons for interior presentation of faces and volumes
228   Handle(Graphic3d_ArrayOfPolygons) aCPolyArr = new Graphic3d_ArrayOfPolygons
229     ( aMaxFaceNodes * aSize + PolygonVerticesFor3D, aSize + PolygonBoundsFor3D,
230     0, myUseTexture || IsReflect, !myUseTexture, Standard_False, myUseTexture );
231
232     Standard_Integer aNbFacePrimitives = 0;
233     Standard_Integer aNbVolmPrimitives = 0;
234     Standard_Integer aNbEdgePrimitives = 0;
235     Standard_Integer aNbLinkPrimitives = 0;
236
237     for (it.Reset(); it.More(); it.Next())
238     {
239       Standard_Integer aNbNodes = 0;
240
241       if (!aSource->GetGeom (it.Key(), Standard_True, aCoords, aNbNodes, aType))
242         continue;
243
244       if (aType == MeshVS_ET_Volume)
245       {
246         if (aSource->Get3DGeom (it.Key(), aNbNodes, aTopo))
247         {
248           for (Standard_Integer aFaceIdx = aTopo->Lower(); aFaceIdx <= aTopo->Upper(); ++aFaceIdx)
249           {
250             const TColStd_SequenceOfInteger& aFaceNodes = aTopo->Value (aFaceIdx);
251
252             aNbEdgePrimitives += aFaceNodes.Length();     // add edge segments
253             aNbVolmPrimitives += aFaceNodes.Length() - 2; // add volumetric cell triangles
254           }
255         }
256       }
257       else if (aType == MeshVS_ET_Link)
258       {
259         aNbLinkPrimitives += aNbNodes - 1; // add link segments
260       }
261       else if (aType == MeshVS_ET_Face)
262       {
263         aNbEdgePrimitives += aNbNodes;     // add edge segments
264         aNbFacePrimitives += aNbNodes - 2; // add face triangles
265       }
266     }
267
268   // Here we do not use indices arrays because they are not effective for some mesh
269   // drawing modes: shrinking mode (displaces the vertices inside the polygon), 3D
270   // cell rendering (normal interpolation is not always applicable - flat shading),
271   // elemental coloring (color interpolation is impossible)
272
273   // Create array of polygons for interior presentation of faces and volumes
274   Handle(Graphic3d_ArrayOfTriangles) aFaceTriangles = new Graphic3d_ArrayOfTriangles
275     ( (aNbFacePrimitives + aNbVolmPrimitives) * 3, 0, myUseTexture || IsReflect, !myUseTexture, myUseTexture );
276
277   // Create array of polylines for presentation of edges
278   Handle(Graphic3d_ArrayOfSegments) anEdgeSegments = new Graphic3d_ArrayOfSegments
279     (aNbEdgePrimitives * 2);
280
281   gp_Pnt P, Start;
282   Standard_Real aMin = gp::Resolution() * gp::Resolution();
283   gp_Dir aDefNorm( 0., 0., 1. );
284
285   // Prepare for scaling the incoming colors
286   Standard_Real anColorRatio = aMaterial[0].Ambient();
287
288   for (it.Reset(); it.More(); it.Next())
289   {
290     Standard_Integer aKey = it.Key();
291
292     if (aSource->GetGeom (aKey, Standard_True, aCoords, NbNodes, aType))
293     {
294       TColStd_Array1OfInteger aNodes (1, NbNodes);
295       
296       if (!aSource->GetNodesByElement (aKey, aNodes, NbNodes))
297         continue;
298
299       Quantity_Color aNColor;
300
301       Standard_Boolean isValid = Standard_True;
302       
303       if (myUseTexture)
304       {
305         for (Standard_Integer k = 1; k <= NbNodes && isValid; ++k)
306           isValid = myTextureCoords.IsBound (aNodes (k));
307       }
308       else
309       {
310         for (Standard_Integer k = 1; k <= NbNodes && isValid; ++k)
311           isValid = GetColor (aNodes (k), aNColor);
312       }
313
314       if (!isValid)
315         continue;
316
317       // Preparing normal(s) to show reflections if requested
318       Handle(TColStd_HArray1OfReal) aNormals;
319
320       Standard_Boolean hasNormals =
321         (IsReflect && aSource->GetNormalsByElement (aKey, IsMeshSmoothShading, aMaxFaceNodes, aNormals));
322
323       if (aType == MeshVS_ET_Face)
324       {
325         for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes - 2; ++aNodeIdx) // triangulate polygon
326         {
327           for (Standard_Integer aSubIdx = 0; aSubIdx < 3; ++aSubIdx) // generate sub-triangle
328           {
329             gp_XYZ aPnt (aCoords (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 1),
330                          aCoords (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 2),
331                          aCoords (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 3));
332
333             gp_Vec aNorm = aDefNorm;
334
335             if (hasNormals)
336             {
337               gp_Vec aTestNorm (aNormals->Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 1),
338                                 aNormals->Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 2),
339                                 aNormals->Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 3));
340
341               if (aTestNorm.SquareMagnitude() > aMin)
342               {
343                 aNorm = gp_Dir (aTestNorm);
344               }
345             }
346
347             if (myUseTexture)
348             {
349               const Standard_Real aTexCoord = myTextureCoords (aNodes (aSubIdx == 0 ? 1 : (aNodeIdx + aSubIdx + 1)));
350
351               // Transform texture coordinate in accordance with number of colors specified
352               // by upper level and real size of OpenGL texture. The OpenGL texture has border
353               // colors interpolated with the colors from the color map, thats why we need to
354               // shrink texture coordinates around the middle point to exclude areas where the
355               // map colors are interpolated with the borders color
356               aFaceTriangles->AddVertex (aPnt, aNorm, gp_Pnt2d (
357                 (aTexCoord * (nbColors - 1.0) + 0.5) / nbTextureColors, aTexCoord < 0 || aTexCoord > 1 ? 0.25 : 0.75));
358             }
359             else
360             {
361               GetColor (aNodes (aSubIdx == 0 ? 1 : (aNodeIdx + aSubIdx + 1)), aNColor);
362               
363               if (IsReflect)
364               {
365                 aNColor.SetValues (anColorRatio * aNColor.Red(),
366                                    anColorRatio * aNColor.Green(),
367                                    anColorRatio * aNColor.Blue(),
368                                    Quantity_TOC_RGB);
369
370                 aFaceTriangles->AddVertex (aPnt, aNorm, aNColor);
371               }
372               else
373               {
374                 aFaceTriangles->AddVertex (aPnt, aNColor);
375               }
376             }
377           }
378         }
379
380         for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes; ++aNodeIdx) // border segmentation
381         {
382           const Standard_Integer aNextIdx = (aNodeIdx + 1) % NbNodes;
383
384           anEdgeSegments->AddVertex (aCoords (3 * aNodeIdx + 1),
385                                      aCoords (3 * aNodeIdx + 2),
386                                      aCoords (3 * aNodeIdx + 3));
387
388           anEdgeSegments->AddVertex (aCoords (3 * aNextIdx + 1),
389                                      aCoords (3 * aNextIdx + 2),
390                                      aCoords (3 * aNextIdx + 3));
391         }
392
393         // if IsExcludingOn then presentation must not be built by other builders
394         if (IsExcludingOn())
395         {
396           IDsToExclude.Add (aKey);
397         }
398       }
399       else if (aType == MeshVS_ET_Volume)
400       {
401         if (!aSource->Get3DGeom (aKey, NbNodes, aTopo))
402           continue;
403
404         AddVolumePrs (aTopo, aNodes, aCoords, aFaceTriangles,
405           IsReflect, nbColors, nbTextureColors, anColorRatio);
406         
407         AddVolumePrs (aTopo, aNodes, aCoords, anEdgeSegments,
408           IsReflect, nbColors, nbTextureColors, anColorRatio);
409
410         // if IsExcludingOn then presentation must not be built by other builders
411         if (IsExcludingOn())
412           IDsToExclude.Add (aKey);
413       }
414     }
415   } // for ( ...
416
417   Handle(Graphic3d_AspectFillArea3d) anAsp;
418
419 //  Aspect_InteriorStyle  aStyle;
420 //  Standard_Integer      aStyleInt;
421   Aspect_TypeOfLine     anEdgeType = Aspect_TOL_SOLID;
422   Standard_Integer      anEdgeInt;
423   Standard_Real         anEdgeWidth;
424   Quantity_Color        anInteriorColor;
425   Quantity_Color        anEdgeColor, aLineColor;
426   Standard_Boolean      aShowEdges = Standard_True;
427
428   aDrawer->GetColor  ( MeshVS_DA_InteriorColor, anInteriorColor );
429   aDrawer->GetColor  ( MeshVS_DA_EdgeColor, anEdgeColor );
430   aDrawer->GetColor  ( MeshVS_DA_BeamColor, aLineColor );
431   aDrawer->GetDouble ( MeshVS_DA_EdgeWidth, anEdgeWidth );
432   aDrawer->GetBoolean( MeshVS_DA_ShowEdges, aShowEdges );
433
434   if ( aDrawer->GetInteger ( MeshVS_DA_EdgeType, anEdgeInt ) )
435     anEdgeType = (Aspect_TypeOfLine) anEdgeInt;
436
437   if ( myUseTexture )
438   {
439     Handle(Prs3d_Drawer) aPrsDrawer =  myParentMesh->Attributes();
440     if ( aPrsDrawer.IsNull() )
441       return;
442
443     aPrsDrawer->SetShadingAspect( new Prs3d_ShadingAspect() );
444     anAsp = aPrsDrawer->ShadingAspect()->Aspect();
445     if ( anAsp.IsNull() )
446       return;
447
448     anAsp->SetFrontMaterial( aMaterial[ 0 ] );
449     anAsp->SetBackMaterial( aMaterial[ 1 ] );
450
451
452     Handle(Graphic3d_Texture2D) aTexture = CreateTexture();
453     if ( aTexture.IsNull() )
454       return;
455
456     anAsp->SetTextureMapOn();
457     anAsp->SetTextureMap( aTexture );
458     anAsp->SetInteriorColor( Quantity_NOC_WHITE );
459   }
460   else
461   {
462 //    if ( aDrawer->GetInteger ( MeshVS_DA_InteriorStyle, aStyleInt ) )
463 //      aStyle = (Aspect_InteriorStyle)aStyleInt;
464
465     anAsp = new Graphic3d_AspectFillArea3d (
466       Aspect_IS_SOLID, Quantity_NOC_GRAY, anEdgeColor,
467       anEdgeType, anEdgeWidth, aMaterial[ 0 ], aMaterial[ 1 ] );
468   }
469
470   anAsp->SetDistinguishOff();
471   anAsp->SetEdgeOff();
472
473   Handle(Graphic3d_AspectLine3d) anLAsp =
474     new Graphic3d_AspectLine3d( anEdgeColor, anEdgeType, anEdgeWidth );
475
476   Handle(Graphic3d_Group) aGroup1 = Prs3d_Root::NewGroup (Prs);
477
478   Standard_Boolean toSupressBackFaces = Standard_False;
479   aDrawer->GetBoolean (MeshVS_DA_SupressBackFaces, toSupressBackFaces);
480   aGroup1->SetClosed (toSupressBackFaces == Standard_True);
481
482   aGroup1->SetPrimitivesAspect( anAsp );
483   aGroup1->AddPrimitiveArray( aFaceTriangles /*aCPolyArr*/ );
484   //aGroup1->AddPrimitiveArray( aCPolyArr );
485
486   if (aShowEdges)
487   {
488     Prs3d_Root::NewGroup ( Prs );
489     Handle(Graphic3d_Group) aGroup2 = Prs3d_Root::CurrentGroup ( Prs );
490
491     Handle(Graphic3d_AspectFillArea3d) anAspCopy = new Graphic3d_AspectFillArea3d (*anAsp);
492     anAspCopy->SetTextureMapOff();
493     aGroup2->SetPrimitivesAspect( anAspCopy );
494     aGroup2->SetPrimitivesAspect( anLAsp );
495     aGroup2->AddPrimitiveArray( anEdgeSegments );
496   }
497 }
498
499 //================================================================
500 // Function : AddVolumePrs
501 // Purpose  :
502 //================================================================
503 void MeshVS_NodalColorPrsBuilder::AddVolumePrs (const Handle(MeshVS_HArray1OfSequenceOfInteger)& theTopo,
504                                                 const TColStd_Array1OfInteger&                   theNodes,
505                                                 const TColStd_Array1OfReal&                      theCoords,
506                                                 const Handle(Graphic3d_ArrayOfPrimitives)&       theArray,
507                                                 const Standard_Boolean                           theIsShaded,
508                                                 const Standard_Integer                           theNbColors,
509                                                 const Standard_Integer                           theNbTexColors,
510                                                 const Standard_Real                              theColorRatio) const
511 {
512   Standard_Integer aLow = theCoords.Lower();
513
514   if (theTopo.IsNull() || theArray.IsNull())
515     return;
516
517   Standard_Boolean aIsPolygons = theArray->IsKind (STANDARD_TYPE (Graphic3d_ArrayOfTriangles));
518
519   if (aIsPolygons)
520   {    
521     for (Standard_Integer aFaceIdx = theTopo->Lower(), topoup = theTopo->Upper(); aFaceIdx <= topoup; ++aFaceIdx)
522     {
523       const TColStd_SequenceOfInteger& aFaceNodes = theTopo->Value (aFaceIdx);
524       
525       TColStd_Array1OfReal aPolyNodes (0, 3 * aFaceNodes.Length());
526
527       for (Standard_Integer aNodeIdx = 0; aNodeIdx < aFaceNodes.Length(); ++aNodeIdx)
528       {
529         Standard_Integer anIdx = aFaceNodes.Value (aNodeIdx + 1);
530
531         Standard_Real aX = theCoords.Value (aLow + 3 * anIdx + 0);
532         Standard_Real aY = theCoords.Value (aLow + 3 * anIdx + 1);
533         Standard_Real aZ = theCoords.Value (aLow + 3 * anIdx + 2);
534
535         aPolyNodes.SetValue (3 * aNodeIdx + 1, aX);
536         aPolyNodes.SetValue (3 * aNodeIdx + 2, aY);
537         aPolyNodes.SetValue (3 * aNodeIdx + 3, aZ);
538       }
539       
540       gp_Vec aNorm (0.0, 0.0, 1.0);
541
542       if (theIsShaded)
543       {
544         aPolyNodes.SetValue (0, aFaceNodes.Length());
545         
546         if (!MeshVS_Tool::GetAverageNormal (aPolyNodes, aNorm))
547         {
548           aNorm.SetCoord (0.0, 0.0, 1.0);
549         }
550       }
551
552       for (Standard_Integer aNodeIdx = 0; aNodeIdx < aFaceNodes.Length() - 2; ++aNodeIdx) // triangulate polygon
553       {
554         for (Standard_Integer aSubIdx = 0; aSubIdx < 3; ++aSubIdx) // generate sub-triangle
555         {
556           gp_Pnt aPnt (aPolyNodes.Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 1),
557                        aPolyNodes.Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 2),
558                        aPolyNodes.Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 3));
559
560           if (myUseTexture)
561           {
562             const Standard_Real aTexCoord = myTextureCoords (theNodes (aFaceNodes (aSubIdx == 0 ? 1 : (aNodeIdx + aSubIdx + 1)) + 1));
563
564             theArray->AddVertex (aPnt, aNorm, gp_Pnt2d (
565               (aTexCoord * (theNbColors - 1.0) + 0.5) / theNbTexColors, aTexCoord < 0 || aTexCoord > 1 ? 0.25 : 0.75));
566           }
567           else
568           {
569             Quantity_Color aNColor;
570             GetColor (theNodes ((aFaceNodes (aSubIdx == 0 ? 1 : (aNodeIdx + aSubIdx + 1)) + 1)), aNColor);
571
572             if (theIsShaded)
573             {
574               aNColor.SetValues (theColorRatio * aNColor.Red(),
575                                  theColorRatio * aNColor.Green(),
576                                  theColorRatio * aNColor.Blue(),
577                                  Quantity_TOC_RGB);
578
579               theArray->AddVertex (aPnt, aNorm, aNColor);
580             }
581             else
582             {
583               theArray->AddVertex (aPnt, aNColor);
584             }
585           }
586         }
587       }
588     }
589   }
590   else
591   {
592     // Find all pairs of nodes (edges) to draw (will be drawn only once)
593     NCollection_Map<MeshVS_NodePair, MeshVS_SymmetricPairHasher> aEdgeMap;
594
595     for (Standard_Integer aFaceIdx = theTopo->Lower(), topoup = theTopo->Upper(); aFaceIdx <= topoup; ++aFaceIdx)
596     {
597       const TColStd_SequenceOfInteger& aFaceNodes = theTopo->Value (aFaceIdx);
598       
599       for (Standard_Integer aNodeIdx = 0, aNbNodes = aFaceNodes.Length(); aNodeIdx < aNbNodes; ++aNodeIdx)
600       {
601         const Standard_Integer aNextIdx = (aNodeIdx + 1) % aNbNodes;
602
603         aEdgeMap.Add (MeshVS_NodePair (aFaceNodes.Value (aNodeIdx + 1),
604                                        aFaceNodes.Value (aNextIdx + 1)));
605       }
606     }
607
608     // Draw edges
609     for(NCollection_Map<MeshVS_NodePair, MeshVS_SymmetricPairHasher>::Iterator anIt (aEdgeMap); anIt.More(); anIt.Next())
610     {      
611       const Standard_Integer anIdx1 = aLow + 3 * anIt.Key().first;
612       const Standard_Integer anIdx2 = aLow + 3 * anIt.Key().second;
613
614       Standard_Real aX[] = { theCoords.Value (anIdx1 + 0), theCoords.Value (anIdx2 + 0) };
615       Standard_Real aY[] = { theCoords.Value (anIdx1 + 1), theCoords.Value (anIdx2 + 1) };
616       Standard_Real aZ[] = { theCoords.Value (anIdx1 + 2), theCoords.Value (anIdx2 + 2) };
617
618       theArray->AddVertex (aX[0], aY[0], aZ[0]);
619       theArray->AddVertex (aX[1], aY[1], aZ[1]);
620     }
621   }
622 }
623
624 //================================================================
625 // Function : SetColors
626 // Purpose  :
627 //================================================================
628 void MeshVS_NodalColorPrsBuilder::SetColors (
629   const MeshVS_DataMapOfIntegerColor& theColorMap )
630 {
631   myNodeColorMap = theColorMap;
632 }
633
634 //================================================================
635 // Function : GetColors
636 // Purpose  :
637 //================================================================
638 const MeshVS_DataMapOfIntegerColor& MeshVS_NodalColorPrsBuilder::GetColors() const
639 {
640   return myNodeColorMap;
641 }
642
643 //================================================================
644 // Function : HasColors
645 // Purpose  :
646 //================================================================
647 Standard_Boolean MeshVS_NodalColorPrsBuilder::HasColors () const
648 {
649   return ( myNodeColorMap.Extent() >0 );
650 }
651
652 //================================================================
653 // Function : GetColor
654 // Purpose  :
655 //================================================================
656 Standard_Boolean MeshVS_NodalColorPrsBuilder::GetColor ( const Standard_Integer ID,
657                                                          Quantity_Color& theColor ) const
658 {
659   Standard_Boolean aRes = myNodeColorMap.IsBound ( ID );
660   if ( aRes )
661     theColor = myNodeColorMap.Find ( ID );
662   return aRes;
663 }
664
665 //================================================================
666 // Function : SetColor
667 // Purpose  :
668 //================================================================
669 void MeshVS_NodalColorPrsBuilder::SetColor ( const Standard_Integer theID,
670                                              const Quantity_Color& theCol )
671 {
672   Standard_Boolean aRes = myNodeColorMap.IsBound ( theID );
673   if ( aRes )
674     myNodeColorMap.ChangeFind ( theID ) = theCol;
675   else
676     myNodeColorMap.Bind ( theID, theCol );
677 }
678
679 //================================================================
680 // Function : UseTexture
681 // Purpose  : Specify whether texture must be used to build presentation
682 //================================================================
683 void MeshVS_NodalColorPrsBuilder::UseTexture( const Standard_Boolean theToUse )
684 {
685   myUseTexture = theToUse;
686   if ( myUseTexture )
687     myNodeColorMap.Clear();
688   else
689     myTextureColorMap.Clear();
690 }
691
692 //================================================================
693 // Function : IsUseTexture
694 // Purpose  : Verify whether texture is used to build presentation
695 //================================================================
696 Standard_Boolean MeshVS_NodalColorPrsBuilder::IsUseTexture() const
697 {
698   return myUseTexture;
699 }
700
701 //================================================================
702 // Function : SetColorMap
703 // Purpose  : Set colors to be used for texrture presentation.
704 //            Generate texture in accordance with given parameters
705 //================================================================
706 void MeshVS_NodalColorPrsBuilder::SetColorMap( const Aspect_SequenceOfColor& theColors )
707 {
708   myTextureColorMap = theColors;
709 }
710
711 //================================================================
712 // Function : GetColorMap
713 // Purpose  : Return colors used for texrture presentation
714 //================================================================
715 const Aspect_SequenceOfColor& MeshVS_NodalColorPrsBuilder::GetColorMap() const
716 {
717   return myTextureColorMap;
718 }
719
720 //================================================================
721 // Function : SetInvalidColor
722 // Purpose  : Set color representing invalid texture coordinate
723 //            (laying outside range [0, 1])
724 //================================================================
725 void MeshVS_NodalColorPrsBuilder::SetInvalidColor(
726   const Quantity_Color& theInvalidColor )
727 {
728   myInvalidColor = theInvalidColor;
729 }
730
731 //================================================================
732 // Function : GetInvalidColor
733 // Purpose  : Return color representing invalid texture coordinate
734 //            (laying outside range [0, 1])
735 //================================================================
736 Quantity_Color MeshVS_NodalColorPrsBuilder::GetInvalidColor() const
737 {
738   return myInvalidColor;
739 }
740
741 //================================================================
742 // Function : SetTextureCoords
743 // Purpose  : Specify correspondence between node IDs and texture
744 //            coordinates (range [0, 1])
745 //================================================================
746 void MeshVS_NodalColorPrsBuilder::SetTextureCoords (
747   const TColStd_DataMapOfIntegerReal& theMap )
748 {
749   myTextureCoords = theMap;
750 }
751
752 //================================================================
753 // Function : GetTextureCoords
754 // Purpose  : Get correspondence between node IDs and texture
755 //            coordinates (range [0, 1])
756 //================================================================
757 const TColStd_DataMapOfIntegerReal& MeshVS_NodalColorPrsBuilder::GetTextureCoords() const
758 {
759   return myTextureCoords;
760 }
761
762 //================================================================
763 // Function : SetTextureCoord
764 // Purpose  : Specify correspondence between node ID and texture
765 //            coordinate (range [0, 1])
766 //================================================================
767 void MeshVS_NodalColorPrsBuilder::SetTextureCoord( const Standard_Integer theID,
768                                                    const Standard_Real theCoord )
769 {
770   myTextureCoords.Bind( theID, theCoord );
771 }
772
773 //================================================================
774 // Function : GetTextureCoord
775 // Purpose  : Return correspondence between node IDs and texture
776 //            coordinate (range [0, 1])
777 //================================================================
778 Standard_Real MeshVS_NodalColorPrsBuilder::GetTextureCoord( const Standard_Integer theID )
779 {
780   return myTextureCoords.IsBound( theID ) ? myTextureCoords( theID ) : -1;
781 }
782
783 //================================================================
784 // Function : CreateTexture
785 // Purpose  : Create texture in accordance with myTextureColorMap
786 //================================================================
787 Handle(Graphic3d_Texture2D) MeshVS_NodalColorPrsBuilder::CreateTexture() const
788 {
789   const Standard_Integer aColorsNb = myTextureColorMap.Length();
790   if (aColorsNb == 0)
791   {
792     return NULL;
793   }
794
795   // create and fill image with colors
796   Handle(Image_PixMap) anImage = new Image_PixMap();
797   if (!anImage->InitTrash (Image_Format_RGBA, Standard_Size(getNearestPow2 (aColorsNb)), 2))
798   {
799     return NULL;
800   }
801
802   anImage->SetTopDown (false);
803   for (Standard_Size aCol = 0; aCol < Standard_Size(aColorsNb); ++aCol)
804   {
805     const Quantity_Color& aSrcColor = myTextureColorMap.Value (Standard_Integer(aCol) + 1);
806     Image_ColorRGBA& aColor = anImage->ChangeValue<Image_ColorRGBA> (0, aCol);
807     aColor.r() = Standard_Byte(255.0 * aSrcColor.Red());
808     aColor.g() = Standard_Byte(255.0 * aSrcColor.Green());
809     aColor.b() = Standard_Byte(255.0 * aSrcColor.Blue());
810     aColor.a() = 0xFF;
811   }
812
813   // fill padding bytes
814   const Quantity_Color& aLastColorSrc = myTextureColorMap.Last();
815   const Image_ColorRGBA aLastColor =
816   {{
817     Standard_Byte(255.0 * aLastColorSrc.Red()),
818     Standard_Byte(255.0 * aLastColorSrc.Green()),
819     Standard_Byte(255.0 * aLastColorSrc.Blue()),
820     0xFF
821   }};
822
823   // fill second row
824   for (Standard_Size aCol = (Standard_Size )aColorsNb; aCol < anImage->SizeX(); ++aCol)
825   {
826     anImage->ChangeValue<Image_ColorRGBA> (0, aCol) = aLastColor;
827   }
828
829   const Image_ColorRGBA anInvalidColor =
830   {{
831     Standard_Byte(255.0 * myInvalidColor.Red()),
832     Standard_Byte(255.0 * myInvalidColor.Green()),
833     Standard_Byte(255.0 * myInvalidColor.Blue()),
834     0xFF
835   }};
836   for (Standard_Size aCol = 0; aCol < anImage->SizeX(); ++aCol)
837   {
838     anImage->ChangeValue<Image_ColorRGBA> (1, aCol) = anInvalidColor;
839   }
840
841   // create texture
842   return new MeshVS_ImageTexture2D (anImage);
843 }