0024750: Replace instantiations of TCollection generic classes by NCollection templat...
[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 // if define _POLYGONES_ ColorPrsBuilder use ArrayOfPolygons for drawing faces
18
19 #include <MeshVS_NodalColorPrsBuilder.ixx>
20
21 #include <Graphic3d_AspectFillArea3d.hxx>
22 #include <Graphic3d_AspectLine3d.hxx>
23 #include <Graphic3d_ArrayOfPolygons.hxx>
24 #include <Graphic3d_ArrayOfPolylines.hxx>
25 #include <Graphic3d_ArrayOfSegments.hxx>
26 #include <Graphic3d_ArrayOfTriangles.hxx>
27 #include <Graphic3d_Group.hxx>
28 #include <Graphic3d_TextureParams.hxx>
29
30 #include <Prs3d_Drawer.hxx>
31 #include <Prs3d_ShadingAspect.hxx>
32 #include <Prs3d_Root.hxx>
33 #include <Prs3d_LineAspect.hxx>
34
35 #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
36 #include <TColStd_ListIteratorOfListOfInteger.hxx>
37 #include <TColStd_Array1OfReal.hxx>
38 #include <TColStd_HArray1OfReal.hxx>
39 #include <TColStd_Array1OfInteger.hxx>
40 #include <TColStd_SequenceOfInteger.hxx>
41 #include <TColStd_HPackedMapOfInteger.hxx>
42
43 #include <MeshVS_DisplayModeFlags.hxx>
44 #include <MeshVS_DrawerAttribute.hxx>
45 #include <MeshVS_DataSource.hxx>
46 #include <MeshVS_Drawer.hxx>
47 #include <MeshVS_Mesh.hxx>
48 #include <MeshVS_MeshPrsBuilder.hxx>
49 #include <MeshVS_HArray1OfSequenceOfInteger.hxx>
50 #include <MeshVS_Buffer.hxx>
51 #include <MeshVS_Tool.hxx>
52 #include <MeshVS_SymmetricPairHasher.hxx>
53
54 #include <gp_Pnt.hxx>
55 #include <Image_PixMap.hxx>
56 #include <Graphic3d_Texture2D.hxx>
57 #include <Graphic3d_TypeOfTextureMode.hxx>
58 #include <Standard_Type.hxx>
59 #include <PrsMgr_PresentationManager3d.hxx>
60 #include <Quantity_Array1OfColor.hxx>
61 #include <Aspect_SequenceOfColor.hxx>
62
63 #include <NCollection_Map.hxx>
64 #include <NCollection_Vector.hxx>
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(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       Standard_Integer i;
303       
304       if (myUseTexture)
305       {
306         for (i = 1; i <= NbNodes && isValid; ++i)
307           isValid = myTextureCoords.IsBound (aNodes (i));
308       }
309       else
310       {
311         for (i = 1; i <= NbNodes && isValid; ++i)
312           isValid = GetColor (aNodes (i), aNColor);
313       }
314
315       if (!isValid)
316         continue;
317
318       // Preparing normal(s) to show reflections if requested
319       Handle(TColStd_HArray1OfReal) aNormals;
320
321       Standard_Boolean hasNormals =
322         (IsReflect && aSource->GetNormalsByElement (aKey, IsMeshSmoothShading, aMaxFaceNodes, aNormals));
323
324       if (aType == MeshVS_ET_Face)
325       {
326         for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes - 2; ++aNodeIdx) // triangulate polygon
327         {
328           for (Standard_Integer aSubIdx = 0; aSubIdx < 3; ++aSubIdx) // generate sub-triangle
329           {
330             gp_XYZ aPnt (aCoords (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 1),
331                          aCoords (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 2),
332                          aCoords (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 3));
333
334             gp_Vec aNorm = aDefNorm;
335
336             if (hasNormals)
337             {
338               gp_Vec aTestNorm (aNormals->Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 1),
339                                 aNormals->Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 2),
340                                 aNormals->Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 3));
341
342               if (aTestNorm.SquareMagnitude() > aMin)
343               {
344                 aNorm = gp_Dir (aTestNorm);
345               }
346             }
347
348             if (myUseTexture)
349             {
350               const Standard_Real aTexCoord = myTextureCoords (aNodes (aSubIdx == 0 ? 1 : (aNodeIdx + aSubIdx + 1)));
351
352               // Transform texture coordinate in accordance with number of colors specified
353               // by upper level and real size of OpenGL texture. The OpenGL texture has border
354               // colors interpolated with the colors from the color map, thats why we need to
355               // shrink texture coordinates around the middle point to exclude areas where the
356               // map colors are interpolated with the borders color
357               aFaceTriangles->AddVertex (aPnt, aNorm, gp_Pnt2d (
358                 (aTexCoord * (nbColors - 1.0) + 0.5) / nbTextureColors, aTexCoord < 0 || aTexCoord > 1 ? 0.25 : 0.75));
359             }
360             else
361             {
362               GetColor (aNodes (aSubIdx == 0 ? 1 : (aNodeIdx + aSubIdx + 1)), aNColor);
363               
364               if (IsReflect)
365               {
366                 aNColor.SetValues (anColorRatio * aNColor.Red(),
367                                    anColorRatio * aNColor.Green(),
368                                    anColorRatio * aNColor.Blue(),
369                                    Quantity_TOC_RGB);
370
371                 aFaceTriangles->AddVertex (aPnt, aNorm, aNColor);
372               }
373               else
374               {
375                 aFaceTriangles->AddVertex (aPnt, aNColor);
376               }
377             }
378           }
379         }
380
381         for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes; ++aNodeIdx) // border segmentation
382         {
383           const Standard_Integer aNextIdx = (aNodeIdx + 1) % NbNodes;
384
385           anEdgeSegments->AddVertex (aCoords (3 * aNodeIdx + 1),
386                                      aCoords (3 * aNodeIdx + 2),
387                                      aCoords (3 * aNodeIdx + 3));
388
389           anEdgeSegments->AddVertex (aCoords (3 * aNextIdx + 1),
390                                      aCoords (3 * aNextIdx + 2),
391                                      aCoords (3 * aNextIdx + 3));
392         }
393
394         // if IsExcludingOn then presentation must not be built by other builders
395         if (IsExcludingOn())
396         {
397           IDsToExclude.Add (aKey);
398         }
399       }
400       else if (aType == MeshVS_ET_Volume)
401       {
402         if (!aSource->Get3DGeom (aKey, NbNodes, aTopo))
403           continue;
404
405         AddVolumePrs (aTopo, aNodes, aCoords, aFaceTriangles,
406           IsReflect, nbColors, nbTextureColors, anColorRatio);
407         
408         AddVolumePrs (aTopo, aNodes, aCoords, anEdgeSegments,
409           IsReflect, nbColors, nbTextureColors, anColorRatio);
410
411         // if IsExcludingOn then presentation must not be built by other builders
412         if (IsExcludingOn())
413           IDsToExclude.Add (aKey);
414       }
415     }
416   } // for ( ...
417
418   Handle(Graphic3d_AspectFillArea3d) anAsp;
419
420 //  Aspect_InteriorStyle  aStyle;
421 //  Standard_Integer      aStyleInt;
422   Aspect_TypeOfLine     anEdgeType = Aspect_TOL_SOLID;
423   Standard_Integer      anEdgeInt;
424   Standard_Real         anEdgeWidth;
425   Quantity_Color        anInteriorColor;
426   Quantity_Color        anEdgeColor, aLineColor;
427   Standard_Boolean      aShowEdges = Standard_True;
428
429   aDrawer->GetColor  ( MeshVS_DA_InteriorColor, anInteriorColor );
430   aDrawer->GetColor  ( MeshVS_DA_EdgeColor, anEdgeColor );
431   aDrawer->GetColor  ( MeshVS_DA_BeamColor, aLineColor );
432   aDrawer->GetDouble ( MeshVS_DA_EdgeWidth, anEdgeWidth );
433   aDrawer->GetBoolean( MeshVS_DA_ShowEdges, aShowEdges );
434
435   if ( aDrawer->GetInteger ( MeshVS_DA_EdgeType, anEdgeInt ) )
436     anEdgeType = (Aspect_TypeOfLine) anEdgeInt;
437
438   if ( myUseTexture )
439   {
440     Handle(Prs3d_Drawer) aPrsDrawer =  myParentMesh->Attributes();
441     if ( aPrsDrawer.IsNull() )
442       return;
443
444     aPrsDrawer->SetShadingAspect( new Prs3d_ShadingAspect() );
445     anAsp = aPrsDrawer->ShadingAspect()->Aspect();
446     if ( anAsp.IsNull() )
447       return;
448
449     anAsp->SetFrontMaterial( aMaterial[ 0 ] );
450     anAsp->SetBackMaterial( aMaterial[ 1 ] );
451
452
453     Handle(Graphic3d_Texture2D) aTexture = CreateTexture();
454     if ( aTexture.IsNull() )
455       return;
456
457     anAsp->SetTextureMapOn();
458     anAsp->SetTextureMap( aTexture );
459     anAsp->SetInteriorColor( Quantity_NOC_WHITE );
460   }
461   else
462   {
463 //    if ( aDrawer->GetInteger ( MeshVS_DA_InteriorStyle, aStyleInt ) )
464 //      aStyle = (Aspect_InteriorStyle)aStyleInt;
465
466     anAsp = new Graphic3d_AspectFillArea3d (
467       Aspect_IS_SOLID, Quantity_NOC_GRAY, anEdgeColor,
468       anEdgeType, anEdgeWidth, aMaterial[ 0 ], aMaterial[ 1 ] );
469   }
470
471   anAsp->SetDistinguishOff();
472   anAsp->SetEdgeOff();
473
474   Handle(Graphic3d_AspectLine3d) anLAsp =
475     new Graphic3d_AspectLine3d( anEdgeColor, anEdgeType, anEdgeWidth );
476
477   Prs3d_Root::NewGroup ( Prs );
478   Handle(Graphic3d_Group) aGroup1 = Prs3d_Root::CurrentGroup ( Prs );
479
480   aGroup1->SetPrimitivesAspect( anAsp );
481   aGroup1->AddPrimitiveArray( aFaceTriangles /*aCPolyArr*/ );
482   //aGroup1->AddPrimitiveArray( aCPolyArr );
483
484   if (aShowEdges)
485   {
486     Prs3d_Root::NewGroup ( Prs );
487     Handle(Graphic3d_Group) aGroup2 = Prs3d_Root::CurrentGroup ( Prs );
488
489     anAsp->SetEdgeOff();
490     anAsp->SetTextureMapOff();
491     aGroup2->SetPrimitivesAspect( anAsp );
492     aGroup2->SetPrimitivesAspect( anLAsp );
493     aGroup2->AddPrimitiveArray( anEdgeSegments );
494     anAsp->SetEdgeOn();
495   }
496 }
497
498 //================================================================
499 // Function : AddVolumePrs
500 // Purpose  :
501 //================================================================
502 void MeshVS_NodalColorPrsBuilder::AddVolumePrs (const Handle(MeshVS_HArray1OfSequenceOfInteger)& theTopo,
503                                                 const TColStd_Array1OfInteger&                   theNodes,
504                                                 const TColStd_Array1OfReal&                      theCoords,
505                                                 const Handle(Graphic3d_ArrayOfPrimitives)&       theArray,
506                                                 const Standard_Boolean                           theIsShaded,
507                                                 const Standard_Integer                           theNbColors,
508                                                 const Standard_Integer                           theNbTexColors,
509                                                 const Standard_Real                              theColorRatio) const
510 {
511   Standard_Integer aLow = theCoords.Lower();
512
513   if (theTopo.IsNull() || theArray.IsNull())
514     return;
515
516   Standard_Boolean aIsPolygons = theArray->IsKind (STANDARD_TYPE (Graphic3d_ArrayOfTriangles));
517
518   if (aIsPolygons)
519   {    
520     for (Standard_Integer aFaceIdx = theTopo->Lower(), topoup = theTopo->Upper(); aFaceIdx <= topoup; ++aFaceIdx)
521     {
522       const TColStd_SequenceOfInteger& aFaceNodes = theTopo->Value (aFaceIdx);
523       
524       TColStd_Array1OfReal aPolyNodes (0, 3 * aFaceNodes.Length());
525
526       for (Standard_Integer aNodeIdx = 0; aNodeIdx < aFaceNodes.Length(); ++aNodeIdx)
527       {
528         Standard_Integer anIdx = aFaceNodes.Value (aNodeIdx + 1);
529
530         Standard_Real aX = theCoords.Value (aLow + 3 * anIdx + 0);
531         Standard_Real aY = theCoords.Value (aLow + 3 * anIdx + 1);
532         Standard_Real aZ = theCoords.Value (aLow + 3 * anIdx + 2);
533
534         aPolyNodes.SetValue (3 * aNodeIdx + 1, aX);
535         aPolyNodes.SetValue (3 * aNodeIdx + 2, aY);
536         aPolyNodes.SetValue (3 * aNodeIdx + 3, aZ);
537       }
538       
539       gp_Vec aNorm (0.0, 0.0, 1.0);
540
541       if (theIsShaded)
542       {
543         aPolyNodes.SetValue (0, aFaceNodes.Length());
544         
545         if (!MeshVS_Tool::GetAverageNormal (aPolyNodes, aNorm))
546         {
547           aNorm.SetCoord (0.0, 0.0, 1.0);
548         }
549       }
550
551       for (Standard_Integer aNodeIdx = 0; aNodeIdx < aFaceNodes.Length() - 2; ++aNodeIdx) // triangulate polygon
552       {
553         for (Standard_Integer aSubIdx = 0; aSubIdx < 3; ++aSubIdx) // generate sub-triangle
554         {
555           gp_Pnt aPnt (aPolyNodes.Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 1),
556                        aPolyNodes.Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 2),
557                        aPolyNodes.Value (3 * (aSubIdx == 0 ? 0 : (aNodeIdx + aSubIdx)) + 3));
558
559           if (myUseTexture)
560           {
561             const Standard_Real aTexCoord = myTextureCoords (theNodes (aFaceNodes (aSubIdx == 0 ? 1 : (aNodeIdx + aSubIdx + 1)) + 1));
562
563             theArray->AddVertex (aPnt, aNorm, gp_Pnt2d (
564               (aTexCoord * (theNbColors - 1.0) + 0.5) / theNbTexColors, aTexCoord < 0 || aTexCoord > 1 ? 0.25 : 0.75));
565           }
566           else
567           {
568             Quantity_Color aNColor;
569             GetColor (theNodes ((aFaceNodes (aSubIdx == 0 ? 1 : (aNodeIdx + aSubIdx + 1)) + 1)), aNColor);
570
571             if (theIsShaded)
572             {
573               aNColor.SetValues (theColorRatio * aNColor.Red(),
574                                  theColorRatio * aNColor.Green(),
575                                  theColorRatio * aNColor.Blue(),
576                                  Quantity_TOC_RGB);
577
578               theArray->AddVertex (aPnt, aNorm, aNColor);
579             }
580             else
581             {
582               theArray->AddVertex (aPnt, aNColor);
583             }
584           }
585         }
586       }
587     }
588   }
589   else
590   {
591     // Find all pairs of nodes (edges) to draw (will be drawn only once)
592     NCollection_Map<MeshVS_NodePair, MeshVS_SymmetricPairHasher> aEdgeMap;
593
594     for (Standard_Integer aFaceIdx = theTopo->Lower(), topoup = theTopo->Upper(); aFaceIdx <= topoup; ++aFaceIdx)
595     {
596       const TColStd_SequenceOfInteger& aFaceNodes = theTopo->Value (aFaceIdx);
597       
598       for (Standard_Integer aNodeIdx = 0, aNbNodes = aFaceNodes.Length(); aNodeIdx < aNbNodes; ++aNodeIdx)
599       {
600         const Standard_Integer aNextIdx = (aNodeIdx + 1) % aNbNodes;
601
602         aEdgeMap.Add (MeshVS_NodePair (aFaceNodes.Value (aNodeIdx + 1),
603                                        aFaceNodes.Value (aNextIdx + 1)));
604       }
605     }
606
607     // Draw edges
608     for(NCollection_Map<MeshVS_NodePair, MeshVS_SymmetricPairHasher>::Iterator anIt (aEdgeMap); anIt.More(); anIt.Next())
609     {      
610       const Standard_Integer anIdx1 = aLow + 3 * anIt.Key().first;
611       const Standard_Integer anIdx2 = aLow + 3 * anIt.Key().second;
612
613       Standard_Real aX[] = { theCoords.Value (anIdx1 + 0), theCoords.Value (anIdx2 + 0) };
614       Standard_Real aY[] = { theCoords.Value (anIdx1 + 1), theCoords.Value (anIdx2 + 1) };
615       Standard_Real aZ[] = { theCoords.Value (anIdx1 + 2), theCoords.Value (anIdx2 + 2) };
616
617       theArray->AddVertex (aX[0], aY[0], aZ[0]);
618       theArray->AddVertex (aX[1], aY[1], aZ[1]);
619     }
620   }
621 }
622
623 //================================================================
624 // Function : SetColors
625 // Purpose  :
626 //================================================================
627 void MeshVS_NodalColorPrsBuilder::SetColors (
628   const MeshVS_DataMapOfIntegerColor& theColorMap )
629 {
630   myNodeColorMap = theColorMap;
631 }
632
633 //================================================================
634 // Function : GetColors
635 // Purpose  :
636 //================================================================
637 const MeshVS_DataMapOfIntegerColor& MeshVS_NodalColorPrsBuilder::GetColors() const
638 {
639   return myNodeColorMap;
640 }
641
642 //================================================================
643 // Function : HasColors
644 // Purpose  :
645 //================================================================
646 Standard_Boolean MeshVS_NodalColorPrsBuilder::HasColors () const
647 {
648   return ( myNodeColorMap.Extent() >0 );
649 }
650
651 //================================================================
652 // Function : GetColor
653 // Purpose  :
654 //================================================================
655 Standard_Boolean MeshVS_NodalColorPrsBuilder::GetColor ( const Standard_Integer ID,
656                                                          Quantity_Color& theColor ) const
657 {
658   Standard_Boolean aRes = myNodeColorMap.IsBound ( ID );
659   if ( aRes )
660     theColor = myNodeColorMap.Find ( ID );
661   return aRes;
662 }
663
664 //================================================================
665 // Function : SetColor
666 // Purpose  :
667 //================================================================
668 void MeshVS_NodalColorPrsBuilder::SetColor ( const Standard_Integer theID,
669                                              const Quantity_Color& theCol )
670 {
671   Standard_Boolean aRes = myNodeColorMap.IsBound ( theID );
672   if ( aRes )
673     myNodeColorMap.ChangeFind ( theID ) = theCol;
674   else
675     myNodeColorMap.Bind ( theID, theCol );
676 }
677
678 //================================================================
679 // Function : UseTexture
680 // Purpose  : Specify whether texture must be used to build presentation
681 //================================================================
682 void MeshVS_NodalColorPrsBuilder::UseTexture( const Standard_Boolean theToUse )
683 {
684   myUseTexture = theToUse;
685   if ( myUseTexture )
686     myNodeColorMap.Clear();
687   else
688     myTextureColorMap.Clear();
689 }
690
691 //================================================================
692 // Function : IsUseTexture
693 // Purpose  : Verify whether texture is used to build presentation
694 //================================================================
695 Standard_Boolean MeshVS_NodalColorPrsBuilder::IsUseTexture() const
696 {
697   return myUseTexture;
698 }
699
700 //================================================================
701 // Function : SetColorMap
702 // Purpose  : Set colors to be used for texrture presentation.
703 //            Generate texture in accordance with given parameters
704 //================================================================
705 void MeshVS_NodalColorPrsBuilder::SetColorMap( const Aspect_SequenceOfColor& theColors )
706 {
707   myTextureColorMap = theColors;
708 }
709
710 //================================================================
711 // Function : GetColorMap
712 // Purpose  : Return colors used for texrture presentation
713 //================================================================
714 const Aspect_SequenceOfColor& MeshVS_NodalColorPrsBuilder::GetColorMap() const
715 {
716   return myTextureColorMap;
717 }
718
719 //================================================================
720 // Function : SetInvalidColor
721 // Purpose  : Set color representing invalid texture coordinate
722 //            (laying outside range [0, 1])
723 //================================================================
724 void MeshVS_NodalColorPrsBuilder::SetInvalidColor(
725   const Quantity_Color& theInvalidColor )
726 {
727   myInvalidColor = theInvalidColor;
728 }
729
730 //================================================================
731 // Function : GetInvalidColor
732 // Purpose  : Return color representing invalid texture coordinate
733 //            (laying outside range [0, 1])
734 //================================================================
735 Quantity_Color MeshVS_NodalColorPrsBuilder::GetInvalidColor() const
736 {
737   return myInvalidColor;
738 }
739
740 //================================================================
741 // Function : SetTextureCoords
742 // Purpose  : Specify correspondence between node IDs and texture
743 //            coordinates (range [0, 1])
744 //================================================================
745 void MeshVS_NodalColorPrsBuilder::SetTextureCoords (
746   const TColStd_DataMapOfIntegerReal& theMap )
747 {
748   myTextureCoords = theMap;
749 }
750
751 //================================================================
752 // Function : GetTextureCoords
753 // Purpose  : Get correspondence between node IDs and texture
754 //            coordinates (range [0, 1])
755 //================================================================
756 const TColStd_DataMapOfIntegerReal& MeshVS_NodalColorPrsBuilder::GetTextureCoords() const
757 {
758   return myTextureCoords;
759 }
760
761 //================================================================
762 // Function : SetTextureCoord
763 // Purpose  : Specify correspondence between node ID and texture
764 //            coordinate (range [0, 1])
765 //================================================================
766 void MeshVS_NodalColorPrsBuilder::SetTextureCoord( const Standard_Integer theID,
767                                                    const Standard_Real theCoord )
768 {
769   myTextureCoords.Bind( theID, theCoord );
770 }
771
772 //================================================================
773 // Function : GetTextureCoord
774 // Purpose  : Return correspondence between node IDs and texture
775 //            coordinate (range [0, 1])
776 //================================================================
777 Standard_Real MeshVS_NodalColorPrsBuilder::GetTextureCoord( const Standard_Integer theID )
778 {
779   return myTextureCoords.IsBound( theID ) ? myTextureCoords( theID ) : -1;
780 }
781
782 //================================================================
783 // Function : CreateTexture
784 // Purpose  : Create texture in accordance with myTextureColorMap
785 //================================================================
786 Handle(Graphic3d_Texture2D) MeshVS_NodalColorPrsBuilder::CreateTexture() const
787 {
788   const Standard_Integer aColorsNb = myTextureColorMap.Length();
789   if (aColorsNb == 0)
790   {
791     return NULL;
792   }
793
794   // create and fill image with colors
795   Handle(Image_PixMap) anImage = new Image_PixMap();
796   if (!anImage->InitTrash (Image_PixMap::ImgRGBA, Standard_Size(getNearestPow2 (aColorsNb)), 2))
797   {
798     return NULL;
799   }
800
801   anImage->SetTopDown (false);
802   for (Standard_Size aCol = 0; aCol < Standard_Size(aColorsNb); ++aCol)
803   {
804     const Quantity_Color& aSrcColor = myTextureColorMap.Value (Standard_Integer(aCol) + 1);
805     Image_ColorRGBA& aColor = anImage->ChangeValue<Image_ColorRGBA> (0, aCol);
806     aColor.r() = Standard_Byte(255.0 * aSrcColor.Red());
807     aColor.g() = Standard_Byte(255.0 * aSrcColor.Green());
808     aColor.b() = Standard_Byte(255.0 * aSrcColor.Blue());
809     aColor.a() = 0xFF;
810   }
811
812   // fill padding bytes
813   const Quantity_Color& aLastColorSrc = myTextureColorMap.Last();
814   const Image_ColorRGBA aLastColor =
815   {{
816     Standard_Byte(255.0 * aLastColorSrc.Red()),
817     Standard_Byte(255.0 * aLastColorSrc.Green()),
818     Standard_Byte(255.0 * aLastColorSrc.Blue()),
819     0xFF
820   }};
821
822   // fill second row
823   for (Standard_Size aCol = (Standard_Size )aColorsNb; aCol < anImage->SizeX(); ++aCol)
824   {
825     anImage->ChangeValue<Image_ColorRGBA> (0, aCol) = aLastColor;
826   }
827
828   const Image_ColorRGBA anInvalidColor =
829   {{
830     Standard_Byte(255.0 * myInvalidColor.Red()),
831     Standard_Byte(255.0 * myInvalidColor.Green()),
832     Standard_Byte(255.0 * myInvalidColor.Blue()),
833     0xFF
834   }};
835   for (Standard_Size aCol = 0; aCol < anImage->SizeX(); ++aCol)
836   {
837     anImage->ChangeValue<Image_ColorRGBA> (1, aCol) = anInvalidColor;
838   }
839
840   // create texture
841   return new MeshVS_ImageTexture2D (anImage);
842 }