0027180: Visualization - improve selection logic of MeshVS_Mesh
[occt.git] / src / MeshVS / MeshVS_ElementalColorPrsBuilder.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
17 #include <Graphic3d_ArrayOfPolygons.hxx>
18 #include <Graphic3d_ArrayOfPolylines.hxx>
19 #include <Graphic3d_ArrayOfSegments.hxx>
20 #include <Graphic3d_ArrayOfTriangles.hxx>
21 #include <Graphic3d_AspectFillArea3d.hxx>
22 #include <Graphic3d_AspectLine3d.hxx>
23 #include <Graphic3d_Group.hxx>
24 #include <MeshVS_Buffer.hxx>
25 #include <MeshVS_DataMapIteratorOfDataMapOfColorMapOfInteger.hxx>
26 #include <MeshVS_DataMapIteratorOfDataMapOfIntegerColor.hxx>
27 #include <MeshVS_DataMapIteratorOfDataMapOfIntegerTwoColors.hxx>
28 #include <MeshVS_DataMapIteratorOfDataMapOfTwoColorsMapOfInteger.hxx>
29 #include <MeshVS_DataMapOfColorMapOfInteger.hxx>
30 #include <MeshVS_DataMapOfTwoColorsMapOfInteger.hxx>
31 #include <MeshVS_DataSource.hxx>
32 #include <MeshVS_DisplayModeFlags.hxx>
33 #include <MeshVS_Drawer.hxx>
34 #include <MeshVS_DrawerAttribute.hxx>
35 #include <MeshVS_ElementalColorPrsBuilder.hxx>
36 #include <MeshVS_HArray1OfSequenceOfInteger.hxx>
37 #include <MeshVS_Mesh.hxx>
38 #include <MeshVS_MeshPrsBuilder.hxx>
39 #include <Prs3d_LineAspect.hxx>
40 #include <Prs3d_Presentation.hxx>
41 #include <Prs3d_Root.hxx>
42 #include <Prs3d_ShadingAspect.hxx>
43 #include <Quantity_Color.hxx>
44 #include <Standard_Type.hxx>
45 #include <TColStd_Array1OfReal.hxx>
46 #include <TColStd_HArray1OfReal.hxx>
47 #include <TColStd_HPackedMapOfInteger.hxx>
48 #include <TColStd_ListIteratorOfListOfInteger.hxx>
49 #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
50 #include <TColStd_MapOfInteger.hxx>
51 #include <TColStd_PackedMapOfInteger.hxx>
52 #include <TColStd_SequenceOfInteger.hxx>
53
54 IMPLEMENT_STANDARD_RTTIEXT(MeshVS_ElementalColorPrsBuilder,MeshVS_PrsBuilder)
55
56 //================================================================
57 // Function : Constructor MeshVS_ElementalColorPrsBuilder
58 // Purpose  :
59 //================================================================
60 MeshVS_ElementalColorPrsBuilder::MeshVS_ElementalColorPrsBuilder
61   ( const Handle(MeshVS_Mesh)& Parent,
62     const MeshVS_DisplayModeFlags& Flags,
63     const Handle (MeshVS_DataSource)& DS,
64     const Standard_Integer Id,
65     const MeshVS_BuilderPriority& Priority )
66 : MeshVS_PrsBuilder ( Parent, Flags, DS, Id, Priority )
67 {
68   SetExcluding ( Standard_True );
69 }
70
71 //================================================================
72 // Function : Build
73 // Purpose  :
74 //================================================================
75 void MeshVS_ElementalColorPrsBuilder::Build ( const Handle(Prs3d_Presentation)& Prs,
76                                               const TColStd_PackedMapOfInteger& IDs,
77                                               TColStd_PackedMapOfInteger& IDsToExclude,
78                                               const Standard_Boolean IsElement,
79                                               const Standard_Integer DisplayMode) const
80 {
81   Handle (MeshVS_DataSource) aSource = GetDataSource();
82   Handle (MeshVS_Drawer)     aDrawer = GetDrawer();
83
84   if ( aSource.IsNull() || aDrawer.IsNull() )
85     return;
86
87   Standard_Integer aMaxFaceNodes;
88   if ( !aDrawer->GetInteger ( MeshVS_DA_MaxFaceNodes, aMaxFaceNodes ) && aMaxFaceNodes<=0 )
89     return;
90
91   MeshVS_DataMapOfIntegerColor* anElemColorMap = (MeshVS_DataMapOfIntegerColor*) &myElemColorMap1;
92   MeshVS_DataMapOfIntegerTwoColors* anElemTwoColorsMap = (MeshVS_DataMapOfIntegerTwoColors*)&myElemColorMap2;
93
94   MeshVS_DataMapOfColorMapOfInteger     aColorsOfElements;
95   MeshVS_DataMapOfTwoColorsMapOfInteger aTwoColorsOfElements;
96
97   MeshVS_Buffer aCoordsBuf (3*aMaxFaceNodes*sizeof(Standard_Real));
98   TColStd_Array1OfReal aCoords (aCoordsBuf, 1, 3*aMaxFaceNodes);
99   Standard_Integer NbNodes;
100   MeshVS_EntityType aType;
101
102   if ( !( DisplayMode & GetFlags() ) || !IsElement ||
103        ( myElemColorMap1.IsEmpty() && myElemColorMap2.IsEmpty() ) )
104     return;
105
106   // subtract the hidden elements and ids to exclude (to minimise allocated memory)
107   TColStd_PackedMapOfInteger anIDs;
108   anIDs.Assign( IDs );
109   Handle(TColStd_HPackedMapOfInteger) aHiddenElems = myParentMesh->GetHiddenElems();
110   if ( !aHiddenElems.IsNull() )
111     anIDs.Subtract( aHiddenElems->Map() );
112   anIDs.Subtract( IDsToExclude );
113
114   // STEP 0: We looking for two colored elements, who has equal two colors and move it
115   // to map of elements with one assigned color
116   TColStd_ListOfInteger aColorOne;
117   for ( MeshVS_DataMapIteratorOfDataMapOfIntegerTwoColors anIter ( *anElemTwoColorsMap ); anIter.More(); anIter.Next () )
118   {
119     Standard_Integer aKey   = anIter.Key ();
120     MeshVS_TwoColors aValue = anIter.Value ();
121     Quantity_Color   aCol1, aCol2;
122     ExtractColors ( aValue, aCol1, aCol2 );
123     if ( aCol1 == aCol2 )
124     {
125       aColorOne.Append ( aKey );
126       anElemColorMap->Bind ( aKey, aCol1 );
127     }
128   }
129
130   for ( TColStd_ListIteratorOfListOfInteger aLIter ( aColorOne ); aLIter.More(); aLIter.Next() )
131     anElemTwoColorsMap->UnBind ( aLIter.Value() );
132
133   // The map is to resort itself by colors.
134   // STEP 1: We start sorting elements with one assigned color
135   for ( MeshVS_DataMapIteratorOfDataMapOfIntegerColor anIterM ( *anElemColorMap ); anIterM.More(); anIterM.Next () )
136   {
137     Standard_Integer aMKey = anIterM.Key ();
138     // The ID of current element
139     Standard_Boolean IsExist = Standard_False;
140     for ( MeshVS_DataMapIteratorOfDataMapOfColorMapOfInteger anIterC ( aColorsOfElements );
141           anIterC.More() && !IsExist; anIterC.Next () )
142       if ( anIterC.Key()==anIterM.Value() )
143       {
144         TColStd_MapOfInteger& aChangeValue = (TColStd_MapOfInteger&) anIterC.Value();
145         aChangeValue.Add ( aMKey );
146         IsExist = Standard_True;
147       }
148
149     if ( !IsExist )
150     {
151       TColStd_MapOfInteger aNewMap; aNewMap.Add ( aMKey );
152       aColorsOfElements.Bind ( anIterM.Value(), aNewMap );
153     }
154   }
155
156   // STEP 2: We start sorting elements with two assigned colors
157   for ( MeshVS_DataMapIteratorOfDataMapOfIntegerTwoColors anIterM2 ( *anElemTwoColorsMap ); anIterM2.More();
158         anIterM2.Next () )
159   {
160     Standard_Integer aMKey = anIterM2.Key ();
161     // The ID of current element
162     Standard_Boolean IsExist = Standard_False;
163     for ( MeshVS_DataMapIteratorOfDataMapOfTwoColorsMapOfInteger anIterC2 ( aTwoColorsOfElements );
164           anIterC2.More() && !IsExist; anIterC2.Next () )
165       if ( IsEqual ( anIterC2.Key(), anIterM2.Value() ) )
166       {
167         TColStd_MapOfInteger& aChangeValue = (TColStd_MapOfInteger&) anIterC2.Value();
168         aChangeValue.Add ( aMKey );
169         IsExist = Standard_True;
170       }
171
172     if ( !IsExist )
173     {
174       TColStd_MapOfInteger aNewMap; aNewMap.Add ( aMKey );
175       aTwoColorsOfElements.Bind ( anIterM2.Value(), aNewMap );
176     }
177   }
178
179   //Now we are ready to draw faces with equal colors
180   Aspect_TypeOfLine    anEdgeType = Aspect_TOL_SOLID;
181   Aspect_TypeOfLine    aLineType = Aspect_TOL_SOLID;
182   Standard_Integer     anEdgeInt, aLineInt;
183   Standard_Real        anEdgeWidth, aLineWidth;
184   Quantity_Color       anInteriorColor;
185   Quantity_Color       anEdgeColor, aLineColor;
186   Standard_Boolean     anEdgeOn = Standard_True, IsReflect = Standard_False,
187                        IsMeshSmoothShading = Standard_False;
188
189   aDrawer->GetColor  ( MeshVS_DA_InteriorColor, anInteriorColor );
190   aDrawer->GetColor  ( MeshVS_DA_EdgeColor, anEdgeColor );
191   aDrawer->GetColor  ( MeshVS_DA_BeamColor, aLineColor );
192   aDrawer->GetDouble ( MeshVS_DA_EdgeWidth, anEdgeWidth );
193   aDrawer->GetDouble ( MeshVS_DA_BeamWidth, aLineWidth );
194   aDrawer->GetBoolean( MeshVS_DA_ShowEdges, anEdgeOn );
195   aDrawer->GetBoolean( MeshVS_DA_ColorReflection, IsReflect );
196   aDrawer->GetBoolean( MeshVS_DA_SmoothShading, IsMeshSmoothShading );
197
198   if ( aDrawer->GetInteger ( MeshVS_DA_EdgeType, anEdgeInt) )
199     anEdgeType = (Aspect_TypeOfLine) anEdgeInt;
200
201   if ( aDrawer->GetInteger ( MeshVS_DA_BeamType, aLineInt) )
202     aLineType = (Aspect_TypeOfLine) aLineInt;
203
204   Handle( MeshVS_HArray1OfSequenceOfInteger ) aTopo;
205   Standard_Integer PolygonVerticesFor3D = 0, PolygonBoundsFor3D = 0;
206   TColStd_MapIteratorOfPackedMapOfInteger it (anIDs);
207   for( ; it.More(); it.Next() )
208   {
209     Standard_Integer aKey = it.Key();
210     if( aSource->Get3DGeom( aKey, NbNodes, aTopo ) )
211         MeshVS_MeshPrsBuilder::HowManyPrimitives
212           ( aTopo, Standard_True, Standard_False, NbNodes,
213             PolygonVerticesFor3D, PolygonBoundsFor3D );
214   }
215
216   Graphic3d_MaterialAspect aMaterial[2];
217   for (Standard_Integer i = 0; i < 2; i++)
218   {
219     // OCC20644 "plastic" is most suitable here, as it is "non-physic"
220     // so TelUpdateMaterial() from OpenGl_attri.c uses the interior
221     // color from AspectFillArea3d to calculate all material colors
222     aMaterial[i] = Graphic3d_MaterialAspect ( Graphic3d_NOM_PLASTIC );
223
224     // OCC21720 For single-colored elements turning all material components off is a good idea,
225     // as anyhow the normals are not computed and the lighting will be off,
226     // the element color will be taken from Graphic3d_AspectFillArea3d's interior color,
227     // and there is no need to spend time on updating material properties 
228     if ( !IsReflect )
229     {
230       aMaterial[i].SetReflectionModeOff(Graphic3d_TOR_AMBIENT);
231       aMaterial[i].SetReflectionModeOff(Graphic3d_TOR_DIFFUSE);
232       aMaterial[i].SetReflectionModeOff(Graphic3d_TOR_SPECULAR);
233       aMaterial[i].SetReflectionModeOff(Graphic3d_TOR_EMISSION);
234     }
235     else
236     {
237       // OCC20644 This stuff is important in order for elemental and nodal colors
238       // to produce similar visual impression and also to make colors match
239       // those in the color scale most exactly (the sum of all reflection 
240       // coefficients is equal to 1). See also MeshVS_NodalColorPrsBuilder
241       // class for more explanations.
242       aMaterial[i].SetAmbient( .5 );
243       aMaterial[i].SetDiffuse( .5 );
244       aMaterial[i].SetSpecular( 0. );
245       aMaterial[i].SetEmissive( 0. );
246     }
247   }
248
249   // Draw elements with one color
250   for ( MeshVS_DataMapIteratorOfDataMapOfColorMapOfInteger aColIter ( aColorsOfElements ); aColIter.More();
251         aColIter.Next() )
252   {
253     Standard_Integer aSize = aColIter.Value().Extent();
254     if ( aSize<=0 )
255       continue;
256
257     TColStd_PackedMapOfInteger aCustomElements;
258
259     Prs3d_Root::NewGroup ( Prs );
260     Handle ( Graphic3d_Group ) aGGroup = Prs3d_Root::CurrentGroup ( Prs );
261     Prs3d_Root::NewGroup ( Prs );
262     Handle ( Graphic3d_Group ) aLGroup = Prs3d_Root::CurrentGroup ( Prs );
263     Prs3d_Root::NewGroup ( Prs );
264     Handle ( Graphic3d_Group ) aSGroup = Prs3d_Root::CurrentGroup ( Prs );
265
266     Standard_Integer aNbFacePrimitives = 0;
267     Standard_Integer aNbVolmPrimitives = 0;
268     Standard_Integer aNbEdgePrimitives = 0;
269     Standard_Integer aNbLinkPrimitives = 0;
270
271     for (it.Reset(); it.More(); it.Next())
272     {
273       Standard_Integer aNbNodes = 0;
274
275       if (!aColIter.Value().Contains (it.Key()))
276         continue;
277
278       if (!aSource->GetGeom (it.Key(), Standard_True, aCoords, aNbNodes, aType))
279         continue;
280
281       if (aType == MeshVS_ET_Volume)
282       {
283         if (aSource->Get3DGeom (it.Key(), aNbNodes, aTopo))
284         {
285           for (Standard_Integer aFaceIdx = aTopo->Lower(); aFaceIdx <= aTopo->Upper(); ++aFaceIdx)
286           {
287             const TColStd_SequenceOfInteger& aFaceNodes = aTopo->Value (aFaceIdx);
288
289             if (anEdgeOn) // add edge segments
290             {
291               aNbEdgePrimitives += aFaceNodes.Length();
292             }
293
294             aNbVolmPrimitives += aFaceNodes.Length() - 2;
295           }
296         }
297       }
298       else if (aType == MeshVS_ET_Link)
299       {
300         if (anEdgeOn)
301         {
302           aNbLinkPrimitives += aNbNodes - 1; // add link segments
303         }
304       }
305       else if (aType == MeshVS_ET_Face)
306       {
307         if (anEdgeOn)
308         {
309           aNbEdgePrimitives += aNbNodes; // add edge segments
310         }
311           
312         aNbFacePrimitives += aNbNodes - 2; // add face triangles
313       }
314     }
315
316     // Here we do not use indices arrays because they are not effective for some mesh
317     // drawing modes: shrinking mode (displaces the vertices inside the polygon), 3D
318     // cell rendering (normal interpolation is not always applicable - flat shading),
319     // elemental coloring (color interpolation is impossible)
320
321     Handle (Graphic3d_ArrayOfTriangles) aFaceTriangles = new Graphic3d_ArrayOfTriangles (
322      (aNbFacePrimitives + aNbVolmPrimitives) * 3, 0, IsReflect );
323     Standard_Boolean IsPolyG = Standard_False;
324
325     Handle (Graphic3d_ArrayOfSegments) anEdgeSegments = new Graphic3d_ArrayOfSegments (aNbEdgePrimitives * 2);
326     Handle (Graphic3d_ArrayOfSegments) aLinkSegments = new Graphic3d_ArrayOfSegments (aNbLinkPrimitives * 2);
327     Standard_Boolean IsPolyL = Standard_False;
328
329     // OCC20644 NOTE: aColIter.Key() color is then scaled by TelUpdateMaterial() in OpenGl_attri.c
330     // using the material reflection coefficients. This affects the visual result.
331     Handle(Graphic3d_AspectFillArea3d) aFillAspect =
332       new Graphic3d_AspectFillArea3d ( Aspect_IS_SOLID, aColIter.Key(), anEdgeColor,
333                                        anEdgeType, anEdgeWidth, aMaterial[0], aMaterial[1] );
334
335     Handle(Graphic3d_AspectLine3d) aLinkAspect =
336       new Graphic3d_AspectLine3d ( aColIter.Key(), aLineType, aLineWidth );
337
338     Handle(Graphic3d_AspectLine3d) anEdgeAspect =
339       new Graphic3d_AspectLine3d ( anEdgeColor, anEdgeType, anEdgeWidth );
340
341     aFillAspect->SetDistinguishOff ();
342     aFillAspect->SetInteriorColor ( aColIter.Key() );
343     if (anEdgeOn)
344       aFillAspect->SetEdgeOn();
345     else
346       aFillAspect->SetEdgeOff();
347
348     for (it.Reset(); it.More(); it.Next())
349     {
350       Standard_Integer aKey = it.Key();
351       
352       if (aColIter.Value().Contains (aKey))
353       {
354         if (!aSource->GetGeom (aKey, Standard_True, aCoords, NbNodes, aType))
355           continue;
356         
357         if (aType != MeshVS_ET_Face && aType != MeshVS_ET_Link && aType != MeshVS_ET_Volume)
358         {
359           aCustomElements.Add (aKey);
360           continue;
361         }
362         
363         if (IsExcludingOn())
364           IDsToExclude.Add (aKey);
365           
366         if (aType == MeshVS_ET_Volume)
367         {
368           if (!aSource->Get3DGeom (aKey, NbNodes, aTopo))
369           {
370             continue;
371           }
372           
373           MeshVS_MeshPrsBuilder::AddVolumePrs (aTopo, aCoords,
374             NbNodes, aFaceTriangles, IsReflect, Standard_False, Standard_False, 1.0);
375
376           if (anEdgeOn)
377           {
378             MeshVS_MeshPrsBuilder::AddVolumePrs (aTopo, aCoords,
379               NbNodes, anEdgeSegments, IsReflect, Standard_False, Standard_False, 1.0);
380           }
381
382           IsPolyG = Standard_True;
383         }
384         else if (aType == MeshVS_ET_Face)
385         {
386           // Preparing normals
387           Handle(TColStd_HArray1OfReal) aNormals;
388           Standard_Boolean aHasNormals = IsReflect && aSource->GetNormalsByElement (aKey, IsMeshSmoothShading, aMaxFaceNodes, aNormals);
389
390           for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes - 2; ++aNodeIdx)
391           {
392             for (Standard_Integer anIdx = 0; anIdx < 3; ++anIdx)
393             {
394               if (IsReflect)
395               {
396                 aFaceTriangles->AddVertex (aCoords (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 1),
397                                            aCoords (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 2),
398                                            aCoords (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 3),
399                                            aHasNormals ? aNormals->Value (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 1) : 0.0,
400                                            aHasNormals ? aNormals->Value (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 2) : 0.0,
401                                            aHasNormals ? aNormals->Value (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 3) : 1.0);
402               }
403               else
404               {
405                 aFaceTriangles->AddVertex (aCoords (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 1),
406                                            aCoords (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 2),
407                                            aCoords (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 3));
408               }
409             }
410           }
411
412           if (anEdgeOn)
413           {
414             for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes; ++aNodeIdx)
415             {
416               const Standard_Integer aNextIdx = (aNodeIdx + 1) % NbNodes;
417
418               anEdgeSegments->AddVertex (aCoords (3 * aNodeIdx + 1),
419                                          aCoords (3 * aNodeIdx + 2),
420                                          aCoords (3 * aNodeIdx + 3));
421               
422               anEdgeSegments->AddVertex (aCoords (3 * aNextIdx + 1),
423                                          aCoords (3 * aNextIdx + 2),
424                                          aCoords (3 * aNextIdx + 3));
425             }
426           }
427
428           IsPolyG = Standard_True;
429         }
430         else if (aType == MeshVS_ET_Link)
431         {
432           for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes - 1; ++aNodeIdx)
433           {
434             const Standard_Integer aNextIdx = aNodeIdx + 1;
435
436             aLinkSegments->AddVertex (aCoords (3 * aNodeIdx + 1),
437                                       aCoords (3 * aNodeIdx + 2),
438                                       aCoords (3 * aNodeIdx + 3));
439
440             aLinkSegments->AddVertex (aCoords (3 * aNextIdx + 1),
441                                       aCoords (3 * aNextIdx + 2),
442                                       aCoords (3 * aNextIdx + 3));
443
444             IsPolyL = Standard_True;
445           }
446         }
447       }
448     }
449
450     if (IsPolyG)
451     {
452       aFillAspect->SetEdgeOff();
453       aGGroup->SetPrimitivesAspect (aFillAspect);
454       aGGroup->AddPrimitiveArray (aFaceTriangles);
455       
456       if (anEdgeOn)
457       {
458         aFillAspect->SetEdgeOff();
459         aSGroup->AddPrimitiveArray (anEdgeSegments);
460         aSGroup->SetGroupPrimitivesAspect (anEdgeAspect);
461       }
462     }
463     if (IsPolyL)
464     {
465       aFillAspect->SetEdgeOff();
466       aLGroup->SetPrimitivesAspect (aFillAspect);
467       aLGroup->SetPrimitivesAspect (aLinkAspect);
468       aLGroup->AddPrimitiveArray (aLinkSegments);
469       if (anEdgeOn)
470         aFillAspect->SetEdgeOn();
471       else
472         aFillAspect->SetEdgeOff();
473     }
474
475     if (!aCustomElements.IsEmpty())
476       CustomBuild(Prs, aCustomElements, IDsToExclude, DisplayMode);
477   }
478
479   Graphic3d_MaterialAspect aMaterial2[2];
480   for (Standard_Integer i = 0; i < 2; i++)
481   {
482     // OCC20644 "plastic" is most suitable here, as it is "non-physic"
483     // so TelUpdateMaterial() from OpenGl_attri.c uses the interior
484     // color from AspectFillArea3d to calculate all material colors
485     aMaterial2[i] = Graphic3d_MaterialAspect ( Graphic3d_NOM_PLASTIC );
486
487     if ( !IsReflect )
488     {
489       // OCC21720 Cannot turn ALL material components off, as such a material
490       // would be ignored by TelUpdateMaterial(), but we need it in order
491       // to have different materials for front and back sides!
492       // Instead, trying to make material color "nondirectional" with 
493       // only ambient component on.
494       aMaterial2[i].SetReflectionModeOn ( Graphic3d_TOR_AMBIENT );
495       aMaterial2[i].SetReflectionModeOff( Graphic3d_TOR_DIFFUSE );
496       aMaterial2[i].SetReflectionModeOff( Graphic3d_TOR_SPECULAR );
497       aMaterial2[i].SetReflectionModeOff( Graphic3d_TOR_EMISSION );
498       aMaterial2[i].SetAmbient ( 1. );
499       aMaterial2[i].SetDiffuse ( 0. );
500       aMaterial2[i].SetSpecular( 0. );
501       aMaterial2[i].SetEmissive( 0. );
502     }
503     else
504     {
505       // OCC20644 This stuff is important in order for elemental and nodal colors
506       // to produce similar visual impression and also to make colors match
507       // those in the color scale most exactly (the sum of all reflection 
508       // coefficients is equal to 1). See also MeshVS_NodalColorPrsBuilder
509       // class for more explanations.
510       aMaterial2[i].SetAmbient( .5 );
511       aMaterial2[i].SetDiffuse( .5 );
512       aMaterial2[i].SetSpecular( 0. );
513       aMaterial2[i].SetEmissive( 0. );
514     }
515   }
516
517   // Draw faces with two color
518   for ( MeshVS_DataMapIteratorOfDataMapOfTwoColorsMapOfInteger aColIter2 ( aTwoColorsOfElements );
519         aColIter2.More(); aColIter2.Next() )
520   {
521     Prs3d_Root::NewGroup ( Prs );
522     Handle ( Graphic3d_Group ) aGroup2 = Prs3d_Root::CurrentGroup ( Prs );
523     Prs3d_Root::NewGroup ( Prs );
524     Handle ( Graphic3d_Group ) aGroup3 = Prs3d_Root::CurrentGroup ( Prs );
525
526     Standard_Integer aSize = aColIter2.Value().Extent();
527     if ( aSize<=0 )
528       continue;
529
530     Standard_Integer aNbFacePrimitives = 0;
531     Standard_Integer aNbEdgePrimitives = 0;
532     
533     for (it.Reset(); it.More(); it.Next())
534     {
535       Standard_Integer aNbNodes = 0;
536
537       if (!aColIter2.Value().Contains (it.Key()))
538         continue;
539
540       if (!aSource->GetGeom (it.Key(), Standard_True, aCoords, aNbNodes, aType))
541         continue;
542
543       if ( aType == MeshVS_ET_Face && aNbNodes > 0 )
544       {
545         if (anEdgeOn)
546         {
547           aNbEdgePrimitives += aNbNodes; // add edge segments
548         }
549
550         aNbFacePrimitives += aNbNodes - 2; // add face triangles
551       }
552     }
553
554     Handle (Graphic3d_ArrayOfTriangles) aFaceTriangles = new Graphic3d_ArrayOfTriangles
555       (aNbFacePrimitives * 3, 0, IsReflect);
556
557     Handle (Graphic3d_ArrayOfSegments) anEdgeSegments = new Graphic3d_ArrayOfSegments
558       (aNbEdgePrimitives * 2);
559
560     MeshVS_TwoColors aTC = aColIter2.Key();
561     Quantity_Color aMyIntColor, aMyBackColor;
562     ExtractColors ( aTC, aMyIntColor, aMyBackColor );
563
564     // OCC20644 NOTE: aMyIntColor color is then scaled by TelUpdateMaterial() in OpenGl_attri.c
565     // using the material reflection coefficients. This affects the visual result.
566     Handle(Graphic3d_AspectFillArea3d) anAsp =
567       new Graphic3d_AspectFillArea3d ( Aspect_IS_SOLID, aMyIntColor, anEdgeColor,
568                                          anEdgeType, anEdgeWidth, aMaterial2[0], aMaterial2[1] );
569     anAsp->SetDistinguishOn ();
570     anAsp->SetInteriorColor ( aMyIntColor );
571     anAsp->SetBackInteriorColor ( aMyBackColor );
572     /*if (anEdgeOn)
573       anAsp->SetEdgeOn();
574     else
575       anAsp->SetEdgeOff();*/
576
577     Handle(Graphic3d_AspectLine3d) anEdgeAspect =
578       new Graphic3d_AspectLine3d (anEdgeColor, anEdgeType, anEdgeWidth);
579
580     for( it.Reset(); it.More(); it.Next() )
581     {
582       Standard_Integer aKey = it.Key();
583       if( aColIter2.Value().Contains( aKey ) )
584       {
585         if ( !aSource->GetGeom ( aKey, Standard_True, aCoords, NbNodes, aType ) )
586           continue;
587
588         if( IsExcludingOn() )
589           IDsToExclude.Add( aKey );
590
591         if (aType == MeshVS_ET_Face && NbNodes > 0)
592         {
593           // Preparing normal(s) to show reflections if requested
594           Handle(TColStd_HArray1OfReal) aNormals;
595           // OCC21720 Always passing normals to OpenGL to make materials work
596           // For OpenGL: "No normals" -> "No lighting" -> "no materials taken into account"
597           Standard_Boolean aHasNormals = /*IsReflect &&*/
598             aSource->GetNormalsByElement (aKey, IsMeshSmoothShading, aMaxFaceNodes, aNormals);
599
600           for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes - 2; ++aNodeIdx)
601           {
602             for (Standard_Integer anIdx = 0; anIdx < 3; ++anIdx)
603             {
604               if (IsReflect)
605               {
606                 aFaceTriangles->AddVertex (aCoords (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 1),
607                                            aCoords (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 2),
608                                            aCoords (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 3),
609                                            aHasNormals ? aNormals->Value (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 1) : 0.0,
610                                            aHasNormals ? aNormals->Value (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 2) : 0.0,
611                                            aHasNormals ? aNormals->Value (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 3) : 1.0);
612               }
613               else
614               {
615                 aFaceTriangles->AddVertex (aCoords (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 1),
616                                            aCoords (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 2),
617                                            aCoords (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 3));
618               }
619             }
620           }
621
622           if (anEdgeOn)
623           {
624             for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes; ++aNodeIdx)
625             {
626               const Standard_Integer aNextIdx = (aNodeIdx + 1) % NbNodes;
627
628               anEdgeSegments->AddVertex (aCoords (3 * aNodeIdx + 1),
629                                          aCoords (3 * aNodeIdx + 2),
630                                          aCoords (3 * aNodeIdx + 3));
631
632               anEdgeSegments->AddVertex (aCoords (3 * aNextIdx + 1),
633                                          aCoords (3 * aNextIdx + 2),
634                                          aCoords (3 * aNextIdx + 3));
635             }
636           }
637         }
638       }
639     }
640
641     aGroup2->AddPrimitiveArray (aFaceTriangles);
642     aGroup2->SetGroupPrimitivesAspect (anAsp);
643     aGroup3->AddPrimitiveArray (anEdgeSegments);
644     aGroup3->SetGroupPrimitivesAspect (anEdgeAspect);
645   }
646 }
647
648 //================================================================
649 // Function : SetColors
650 // Purpose  :
651 //================================================================
652 void MeshVS_ElementalColorPrsBuilder::SetColors1 ( const MeshVS_DataMapOfIntegerColor& theColorMap )
653 {
654   myElemColorMap1 = theColorMap;
655 }
656
657 //================================================================
658 // Function : GetColors
659 // Purpose  :
660 //================================================================
661 const MeshVS_DataMapOfIntegerColor& MeshVS_ElementalColorPrsBuilder::GetColors1 () const
662 {
663   return myElemColorMap1;
664 }
665
666 //================================================================
667 // Function : HasColors1
668 // Purpose  :
669 //================================================================
670 Standard_Boolean MeshVS_ElementalColorPrsBuilder::HasColors1 () const
671 {
672   return ( myElemColorMap1.Extent() >0 );
673 }
674
675 //================================================================
676 // Function : GetColor1
677 // Purpose  :
678 //================================================================
679 Standard_Boolean MeshVS_ElementalColorPrsBuilder::GetColor1 ( const Standard_Integer ID,
680                                                               Quantity_Color& theColor ) const
681 {
682   Standard_Boolean aRes = myElemColorMap1.IsBound ( ID );
683   if ( aRes )
684     theColor = myElemColorMap1.Find ( ID );
685
686   return aRes;
687 }
688
689 //================================================================
690 // Function : SetColor1
691 // Purpose  :
692 //================================================================
693 void MeshVS_ElementalColorPrsBuilder::SetColor1 ( const Standard_Integer theID,
694                                                   const Quantity_Color& theCol )
695 {
696   Standard_Boolean aRes = myElemColorMap1.IsBound ( theID );
697   if ( aRes )
698     myElemColorMap1.ChangeFind ( theID ) = theCol;
699   else
700     myElemColorMap1.Bind ( theID, theCol );
701 }
702
703 //================================================================
704 // Function : SetColors2
705 // Purpose  :
706 //================================================================
707 void MeshVS_ElementalColorPrsBuilder::SetColors2 ( const MeshVS_DataMapOfIntegerTwoColors& theColorMap )
708 {
709   myElemColorMap2 = theColorMap;
710 }
711
712 //================================================================
713 // Function : GetColors2
714 // Purpose  :
715 //================================================================
716 const MeshVS_DataMapOfIntegerTwoColors& MeshVS_ElementalColorPrsBuilder::GetColors2 () const
717 {
718   return myElemColorMap2;
719 }
720
721 //================================================================
722 // Function : HasColors2
723 // Purpose  :
724 //================================================================
725 Standard_Boolean MeshVS_ElementalColorPrsBuilder::HasColors2 () const
726 {
727   return (myElemColorMap2.Extent()>0);
728 }
729
730 //================================================================
731 // Function : GetColor2
732 // Purpose  :
733 //================================================================
734 Standard_Boolean MeshVS_ElementalColorPrsBuilder::GetColor2 ( const Standard_Integer ID,
735                                                               MeshVS_TwoColors& theColor ) const
736 {
737   Standard_Boolean aRes = myElemColorMap2.IsBound ( ID );
738   if ( aRes )
739     theColor = myElemColorMap2.Find ( ID );
740
741   return aRes;
742 }
743
744 //================================================================
745 // Function : GetColor2
746 // Purpose  :
747 //================================================================
748 Standard_Boolean MeshVS_ElementalColorPrsBuilder::GetColor2 ( const Standard_Integer ID,
749                                                               Quantity_Color& theColor1,
750                                                               Quantity_Color& theColor2 ) const
751 {
752   MeshVS_TwoColors aTC;
753   Standard_Boolean aRes = GetColor2 ( ID, aTC );
754   if ( aRes)
755     ExtractColors ( aTC, theColor1, theColor2 );
756   return aRes;
757 }
758
759 //================================================================
760 // Function : SetColor2
761 // Purpose  :
762 //================================================================
763 void MeshVS_ElementalColorPrsBuilder::SetColor2 ( const Standard_Integer theID,
764                                                   const Quantity_Color& theCol1,
765                                                   const Quantity_Color& theCol2 )
766 {
767   SetColor2 ( theID, BindTwoColors ( theCol1, theCol2 ) );
768 }
769
770 //================================================================
771 // Function : SetColor2
772 // Purpose  :
773 //================================================================
774 void MeshVS_ElementalColorPrsBuilder::SetColor2 ( const Standard_Integer theID,
775                                                   const MeshVS_TwoColors& theCol )
776 {
777   Standard_Boolean aRes = myElemColorMap2.IsBound ( theID );
778   if ( aRes )
779     myElemColorMap2.ChangeFind ( theID ) = theCol;
780   else
781     myElemColorMap2.Bind ( theID, theCol );
782 }