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