0022777: Visualization - Unsafe way to get attribute values from MeshVS_Drawer
[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_Real        anEdgeWidth = 1.0, aLineWidth = 1.0;
183   Quantity_Color       anInteriorColor;
184   Quantity_Color       anEdgeColor, aLineColor;
185   Standard_Boolean     anEdgeOn = Standard_True, IsReflect = Standard_False,
186                        IsMeshSmoothShading = Standard_False;
187   Standard_Boolean toSupressBackFaces = 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   aDrawer->GetBoolean (MeshVS_DA_SupressBackFaces, toSupressBackFaces);
198
199   Standard_Integer anEdgeInt = Aspect_TOL_SOLID;
200   if ( aDrawer->GetInteger ( MeshVS_DA_EdgeType, anEdgeInt) )
201     anEdgeType = (Aspect_TypeOfLine) anEdgeInt;
202
203   Standard_Integer aLineInt = Aspect_TOL_SOLID;
204   if ( aDrawer->GetInteger ( MeshVS_DA_BeamType, aLineInt) )
205     aLineType = (Aspect_TypeOfLine) aLineInt;
206
207   Handle( MeshVS_HArray1OfSequenceOfInteger ) aTopo;
208   Standard_Integer PolygonVerticesFor3D = 0, PolygonBoundsFor3D = 0;
209   TColStd_MapIteratorOfPackedMapOfInteger it (anIDs);
210   for( ; it.More(); it.Next() )
211   {
212     Standard_Integer aKey = it.Key();
213     if( aSource->Get3DGeom( aKey, NbNodes, aTopo ) )
214         MeshVS_MeshPrsBuilder::HowManyPrimitives
215           ( aTopo, Standard_True, Standard_False, NbNodes,
216             PolygonVerticesFor3D, PolygonBoundsFor3D );
217   }
218
219   Graphic3d_MaterialAspect aMaterial[2] = { Graphic3d_NOM_PLASTIC, Graphic3d_NOM_PLASTIC };
220   for (Standard_Integer i = 0; i < 2; i++)
221   {
222     // OCC20644 "plastic" is most suitable here, as it is "non-physic"
223     // so TelUpdateMaterial() from OpenGl_attri.c uses the interior
224     // color from AspectFillArea3d to calculate all material colors
225     aMaterial[i].SetSpecularColor (Quantity_NOC_BLACK);
226     aMaterial[i].SetEmissiveColor (Quantity_NOC_BLACK);
227
228     // OCC21720 For single-colored elements turning all material components off is a good idea,
229     // as anyhow the normals are not computed and the lighting will be off,
230     // the element color will be taken from Graphic3d_AspectFillArea3d's interior color,
231     // and there is no need to spend time on updating material properties 
232     if ( !IsReflect )
233     {
234       aMaterial[i].SetAmbientColor (Quantity_NOC_BLACK);
235       aMaterial[i].SetDiffuseColor (Quantity_NOC_BLACK);
236     }
237     else
238     {
239       // OCC20644 This stuff is important in order for elemental and nodal colors
240       // to produce similar visual impression and also to make colors match
241       // those in the color scale most exactly (the sum of all reflection 
242       // coefficients is equal to 1). See also MeshVS_NodalColorPrsBuilder
243       // class for more explanations.
244       aMaterial[i].SetAmbientColor (Quantity_Color (Graphic3d_Vec3 (0.5f)));
245       aMaterial[i].SetDiffuseColor (Quantity_Color (Graphic3d_Vec3 (0.5f)));
246     }
247   }
248
249   // Draw elements with one color
250   Handle(Graphic3d_Group) aGGroup, aGroup2, aLGroup, aSGroup;
251   if (!aTwoColorsOfElements.IsEmpty())
252   {
253     aGroup2 = Prs3d_Root::NewGroup (Prs);
254   }
255   if (!aColorsOfElements.IsEmpty())
256   {
257     Handle(Graphic3d_AspectFillArea3d) aGroupFillAspect = new Graphic3d_AspectFillArea3d (Aspect_IS_SOLID, anInteriorColor, anEdgeColor,
258                                                                                           anEdgeType, anEdgeWidth, aMaterial[0], aMaterial[1]);
259     aGGroup = Prs3d_Root::NewGroup (Prs);
260     aLGroup = Prs3d_Root::NewGroup (Prs);
261     aGGroup->SetClosed (toSupressBackFaces == Standard_True);
262     aGGroup->SetGroupPrimitivesAspect (aGroupFillAspect);
263   }
264
265   if (anEdgeOn)
266   {
267     Handle(Graphic3d_AspectLine3d) anEdgeAspect = new Graphic3d_AspectLine3d (anEdgeColor, anEdgeType, anEdgeWidth);
268     aSGroup = Prs3d_Root::NewGroup (Prs);
269     aSGroup->SetGroupPrimitivesAspect (anEdgeAspect);
270   }
271
272   for (MeshVS_DataMapIteratorOfDataMapOfColorMapOfInteger aColIter (aColorsOfElements);
273        aColIter.More(); aColIter.Next())
274   {
275     if (aColIter.Value().IsEmpty())
276     {
277       continue;
278     }
279
280     TColStd_PackedMapOfInteger aCustomElements;
281
282     Standard_Integer aNbFacePrimitives = 0;
283     Standard_Integer aNbVolmPrimitives = 0;
284     Standard_Integer aNbEdgePrimitives = 0;
285     Standard_Integer aNbLinkPrimitives = 0;
286
287     for (it.Reset(); it.More(); it.Next())
288     {
289       Standard_Integer aNbNodes = 0;
290
291       if (!aColIter.Value().Contains (it.Key()))
292         continue;
293
294       if (!aSource->GetGeom (it.Key(), Standard_True, aCoords, aNbNodes, aType))
295         continue;
296
297       if (aType == MeshVS_ET_Volume)
298       {
299         if (aSource->Get3DGeom (it.Key(), aNbNodes, aTopo))
300         {
301           for (Standard_Integer aFaceIdx = aTopo->Lower(); aFaceIdx <= aTopo->Upper(); ++aFaceIdx)
302           {
303             const TColStd_SequenceOfInteger& aFaceNodes = aTopo->Value (aFaceIdx);
304
305             if (anEdgeOn) // add edge segments
306             {
307               aNbEdgePrimitives += aFaceNodes.Length();
308             }
309
310             aNbVolmPrimitives += aFaceNodes.Length() - 2;
311           }
312         }
313       }
314       else if (aType == MeshVS_ET_Link)
315       {
316         if (anEdgeOn)
317         {
318           aNbLinkPrimitives += aNbNodes - 1; // add link segments
319         }
320       }
321       else if (aType == MeshVS_ET_Face)
322       {
323         if (anEdgeOn)
324         {
325           aNbEdgePrimitives += aNbNodes; // add edge segments
326         }
327           
328         aNbFacePrimitives += aNbNodes - 2; // add face triangles
329       }
330     }
331
332     // Here we do not use indices arrays because they are not effective for some mesh
333     // drawing modes: shrinking mode (displaces the vertices inside the polygon), 3D
334     // cell rendering (normal interpolation is not always applicable - flat shading),
335     // elemental coloring (color interpolation is impossible)
336
337     Handle (Graphic3d_ArrayOfTriangles) aFaceTriangles = new Graphic3d_ArrayOfTriangles (
338      (aNbFacePrimitives + aNbVolmPrimitives) * 3, 0, IsReflect );
339     Standard_Boolean IsPolyG = Standard_False;
340
341     Handle (Graphic3d_ArrayOfSegments) anEdgeSegments = new Graphic3d_ArrayOfSegments (aNbEdgePrimitives * 2);
342     Handle (Graphic3d_ArrayOfSegments) aLinkSegments = new Graphic3d_ArrayOfSegments (aNbLinkPrimitives * 2);
343     Standard_Boolean IsPolyL = Standard_False;
344
345     // OCC20644 NOTE: aColIter.Key() color is then scaled by TelUpdateMaterial() in OpenGl_attri.c
346     // using the material reflection coefficients. This affects the visual result.
347     Handle(Graphic3d_AspectFillArea3d) aFillAspect =
348       new Graphic3d_AspectFillArea3d ( Aspect_IS_SOLID, aColIter.Key(), anEdgeColor,
349                                        anEdgeType, anEdgeWidth, aMaterial[0], aMaterial[1] );
350
351     Handle(Graphic3d_AspectLine3d) aLinkAspect =
352       new Graphic3d_AspectLine3d ( aColIter.Key(), aLineType, aLineWidth );
353
354     aFillAspect->SetDistinguishOff ();
355     aFillAspect->SetInteriorColor ( aColIter.Key() );
356     aFillAspect->SetEdgeOff();
357
358     for (it.Reset(); it.More(); it.Next())
359     {
360       Standard_Integer aKey = it.Key();
361       
362       if (aColIter.Value().Contains (aKey))
363       {
364         if (!aSource->GetGeom (aKey, Standard_True, aCoords, NbNodes, aType))
365           continue;
366         
367         if (aType != MeshVS_ET_Face && aType != MeshVS_ET_Link && aType != MeshVS_ET_Volume)
368         {
369           aCustomElements.Add (aKey);
370           continue;
371         }
372         
373         if (IsExcludingOn())
374           IDsToExclude.Add (aKey);
375           
376         if (aType == MeshVS_ET_Volume)
377         {
378           if (!aSource->Get3DGeom (aKey, NbNodes, aTopo))
379           {
380             continue;
381           }
382           
383           MeshVS_MeshPrsBuilder::AddVolumePrs (aTopo, aCoords,
384             NbNodes, aFaceTriangles, IsReflect, Standard_False, Standard_False, 1.0);
385
386           if (anEdgeOn)
387           {
388             MeshVS_MeshPrsBuilder::AddVolumePrs (aTopo, aCoords,
389               NbNodes, anEdgeSegments, IsReflect, Standard_False, Standard_False, 1.0);
390           }
391
392           IsPolyG = Standard_True;
393         }
394         else if (aType == MeshVS_ET_Face)
395         {
396           // Preparing normals
397           Handle(TColStd_HArray1OfReal) aNormals;
398           Standard_Boolean aHasNormals = IsReflect && aSource->GetNormalsByElement (aKey, IsMeshSmoothShading, aMaxFaceNodes, aNormals);
399
400           for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes - 2; ++aNodeIdx)
401           {
402             for (Standard_Integer anIdx = 0; anIdx < 3; ++anIdx)
403             {
404               if (IsReflect)
405               {
406                 aFaceTriangles->AddVertex (aCoords (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 1),
407                                            aCoords (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 2),
408                                            aCoords (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 3),
409                                            aHasNormals ? aNormals->Value (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 1) : 0.0,
410                                            aHasNormals ? aNormals->Value (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 2) : 0.0,
411                                            aHasNormals ? aNormals->Value (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 3) : 1.0);
412               }
413               else
414               {
415                 aFaceTriangles->AddVertex (aCoords (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 1),
416                                            aCoords (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 2),
417                                            aCoords (3 * (anIdx == 0 ? 0 : (aNodeIdx + anIdx)) + 3));
418               }
419             }
420           }
421
422           if (anEdgeOn)
423           {
424             for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes; ++aNodeIdx)
425             {
426               const Standard_Integer aNextIdx = (aNodeIdx + 1) % NbNodes;
427
428               anEdgeSegments->AddVertex (aCoords (3 * aNodeIdx + 1),
429                                          aCoords (3 * aNodeIdx + 2),
430                                          aCoords (3 * aNodeIdx + 3));
431               
432               anEdgeSegments->AddVertex (aCoords (3 * aNextIdx + 1),
433                                          aCoords (3 * aNextIdx + 2),
434                                          aCoords (3 * aNextIdx + 3));
435             }
436           }
437
438           IsPolyG = Standard_True;
439         }
440         else if (aType == MeshVS_ET_Link)
441         {
442           for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes - 1; ++aNodeIdx)
443           {
444             const Standard_Integer aNextIdx = aNodeIdx + 1;
445
446             aLinkSegments->AddVertex (aCoords (3 * aNodeIdx + 1),
447                                       aCoords (3 * aNodeIdx + 2),
448                                       aCoords (3 * aNodeIdx + 3));
449
450             aLinkSegments->AddVertex (aCoords (3 * aNextIdx + 1),
451                                       aCoords (3 * aNextIdx + 2),
452                                       aCoords (3 * aNextIdx + 3));
453
454             IsPolyL = Standard_True;
455           }
456         }
457       }
458     }
459
460     if (IsPolyG)
461     {
462       aGGroup->SetPrimitivesAspect (aFillAspect);
463       aGGroup->AddPrimitiveArray (aFaceTriangles);
464       aGGroup->SetClosed (toSupressBackFaces == Standard_True);
465       
466       if (anEdgeOn)
467       {
468         aSGroup->AddPrimitiveArray (anEdgeSegments);
469       }
470     }
471     if (IsPolyL)
472     {
473       aLGroup->SetPrimitivesAspect (aFillAspect);
474       aLGroup->SetPrimitivesAspect (aLinkAspect);
475       aLGroup->AddPrimitiveArray (aLinkSegments);
476     }
477
478     if (!aCustomElements.IsEmpty())
479       CustomBuild(Prs, aCustomElements, IDsToExclude, DisplayMode);
480   }
481
482   Graphic3d_MaterialAspect aMaterial2[2] = { Graphic3d_NOM_PLASTIC, Graphic3d_NOM_PLASTIC };
483   for (Standard_Integer i = 0; i < 2; i++)
484   {
485     // OCC20644 "plastic" is most suitable here, as it is "non-physic"
486     // so TelUpdateMaterial() from OpenGl_attri.c uses the interior
487     // color from AspectFillArea3d to calculate all material colors
488     aMaterial2[i].SetSpecularColor (Quantity_NOC_BLACK);
489     aMaterial2[i].SetEmissiveColor (Quantity_NOC_BLACK);
490
491     if ( !IsReflect )
492     {
493       // OCC21720 Cannot turn ALL material components off, as such a material
494       // would be ignored by TelUpdateMaterial(), but we need it in order
495       // to have different materials for front and back sides!
496       // Instead, trying to make material color "nondirectional" with 
497       // only ambient component on.
498       aMaterial2[i].SetAmbientColor (Quantity_Color (Graphic3d_Vec3 (1.0f)));
499       aMaterial2[i].SetDiffuseColor (Quantity_NOC_BLACK);
500     }
501     else
502     {
503       // OCC20644 This stuff is important in order for elemental and nodal colors
504       // to produce similar visual impression and also to make colors match
505       // those in the color scale most exactly (the sum of all reflection 
506       // coefficients is equal to 1). See also MeshVS_NodalColorPrsBuilder
507       // class for more explanations.
508       aMaterial2[i].SetAmbientColor (Quantity_Color (Graphic3d_Vec3 (0.5f)));
509       aMaterial2[i].SetDiffuseColor (Quantity_Color (Graphic3d_Vec3 (0.5f)));
510     }
511   }
512
513   // Draw faces with two color
514   if (!aTwoColorsOfElements.IsEmpty())
515   {
516     Handle(Graphic3d_AspectFillArea3d) aGroupFillAspect2 = new Graphic3d_AspectFillArea3d (Aspect_IS_SOLID, anInteriorColor, anEdgeColor,
517                                                                                           anEdgeType, anEdgeWidth, aMaterial2[0], aMaterial2[1]);
518     aGroup2->SetClosed (Standard_False); // ignore toSupressBackFaces
519     aGroup2->SetGroupPrimitivesAspect (aGroupFillAspect2);
520   }
521   for ( MeshVS_DataMapIteratorOfDataMapOfTwoColorsMapOfInteger aColIter2 ( aTwoColorsOfElements );
522         aColIter2.More(); aColIter2.Next() )
523   {
524     if (aColIter2.Value().IsEmpty())
525     {
526       continue;
527     }
528
529     Standard_Integer aNbFacePrimitives = 0;
530     Standard_Integer aNbEdgePrimitives = 0;
531     
532     for (it.Reset(); it.More(); it.Next())
533     {
534       Standard_Integer aNbNodes = 0;
535
536       if (!aColIter2.Value().Contains (it.Key()))
537         continue;
538
539       if (!aSource->GetGeom (it.Key(), Standard_True, aCoords, aNbNodes, aType))
540         continue;
541
542       if ( aType == MeshVS_ET_Face && aNbNodes > 0 )
543       {
544         if (anEdgeOn)
545         {
546           aNbEdgePrimitives += aNbNodes; // add edge segments
547         }
548
549         aNbFacePrimitives += aNbNodes - 2; // add face triangles
550       }
551     }
552
553     Handle (Graphic3d_ArrayOfTriangles) aFaceTriangles = new Graphic3d_ArrayOfTriangles
554       (aNbFacePrimitives * 3, 0, IsReflect);
555
556     Handle (Graphic3d_ArrayOfSegments) anEdgeSegments = new Graphic3d_ArrayOfSegments
557       (aNbEdgePrimitives * 2);
558
559     MeshVS_TwoColors aTC = aColIter2.Key();
560     Quantity_Color aMyIntColor, aMyBackColor;
561     ExtractColors ( aTC, aMyIntColor, aMyBackColor );
562
563     // OCC20644 NOTE: aMyIntColor color is then scaled by TelUpdateMaterial() in OpenGl_attri.c
564     // using the material reflection coefficients. This affects the visual result.
565     Handle(Graphic3d_AspectFillArea3d) anAsp =
566       new Graphic3d_AspectFillArea3d ( Aspect_IS_SOLID, aMyIntColor, anEdgeColor,
567                                          anEdgeType, anEdgeWidth, aMaterial2[0], aMaterial2[1] );
568     anAsp->SetDistinguishOn ();
569     anAsp->SetInteriorColor ( aMyIntColor );
570     anAsp->SetBackInteriorColor ( aMyBackColor );
571     /*if (anEdgeOn)
572       anAsp->SetEdgeOn();
573     else
574       anAsp->SetEdgeOff();*/
575     aGroup2->SetPrimitivesAspect (anAsp);
576
577     for( it.Reset(); it.More(); it.Next() )
578     {
579       Standard_Integer aKey = it.Key();
580       if( aColIter2.Value().Contains( aKey ) )
581       {
582         if ( !aSource->GetGeom ( aKey, Standard_True, aCoords, NbNodes, aType ) )
583           continue;
584
585         if( IsExcludingOn() )
586           IDsToExclude.Add( aKey );
587
588         if (aType == MeshVS_ET_Face && NbNodes > 0)
589         {
590           // Preparing normal(s) to show reflections if requested
591           Handle(TColStd_HArray1OfReal) aNormals;
592           // OCC21720 Always passing normals to OpenGL to make materials work
593           // For OpenGL: "No normals" -> "No lighting" -> "no materials taken into account"
594           Standard_Boolean aHasNormals = /*IsReflect &&*/
595             aSource->GetNormalsByElement (aKey, IsMeshSmoothShading, aMaxFaceNodes, aNormals);
596
597           for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes - 2; ++aNodeIdx)
598           {
599             for (Standard_Integer anIdx = 0; anIdx < 3; ++anIdx)
600             {
601               if (IsReflect)
602               {
603                 aFaceTriangles->AddVertex (aCoords (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 1),
604                                            aCoords (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 2),
605                                            aCoords (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 3),
606                                            aHasNormals ? aNormals->Value (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 1) : 0.0,
607                                            aHasNormals ? aNormals->Value (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 2) : 0.0,
608                                            aHasNormals ? aNormals->Value (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 3) : 1.0);
609               }
610               else
611               {
612                 aFaceTriangles->AddVertex (aCoords (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 1),
613                                            aCoords (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 2),
614                                            aCoords (3 * (anIdx == 0 ? 0 : aNodeIdx + anIdx) + 3));
615               }
616             }
617           }
618
619           if (anEdgeOn)
620           {
621             for (Standard_Integer aNodeIdx = 0; aNodeIdx < NbNodes; ++aNodeIdx)
622             {
623               const Standard_Integer aNextIdx = (aNodeIdx + 1) % NbNodes;
624
625               anEdgeSegments->AddVertex (aCoords (3 * aNodeIdx + 1),
626                                          aCoords (3 * aNodeIdx + 2),
627                                          aCoords (3 * aNodeIdx + 3));
628
629               anEdgeSegments->AddVertex (aCoords (3 * aNextIdx + 1),
630                                          aCoords (3 * aNextIdx + 2),
631                                          aCoords (3 * aNextIdx + 3));
632             }
633           }
634         }
635       }
636     }
637
638     aGroup2->AddPrimitiveArray (aFaceTriangles);
639     aSGroup->AddPrimitiveArray (anEdgeSegments);
640   }
641 }
642
643 //================================================================
644 // Function : SetColors
645 // Purpose  :
646 //================================================================
647 void MeshVS_ElementalColorPrsBuilder::SetColors1 ( const MeshVS_DataMapOfIntegerColor& theColorMap )
648 {
649   myElemColorMap1 = theColorMap;
650 }
651
652 //================================================================
653 // Function : GetColors
654 // Purpose  :
655 //================================================================
656 const MeshVS_DataMapOfIntegerColor& MeshVS_ElementalColorPrsBuilder::GetColors1 () const
657 {
658   return myElemColorMap1;
659 }
660
661 //================================================================
662 // Function : HasColors1
663 // Purpose  :
664 //================================================================
665 Standard_Boolean MeshVS_ElementalColorPrsBuilder::HasColors1 () const
666 {
667   return ( myElemColorMap1.Extent() >0 );
668 }
669
670 //================================================================
671 // Function : GetColor1
672 // Purpose  :
673 //================================================================
674 Standard_Boolean MeshVS_ElementalColorPrsBuilder::GetColor1 ( const Standard_Integer ID,
675                                                               Quantity_Color& theColor ) const
676 {
677   Standard_Boolean aRes = myElemColorMap1.IsBound ( ID );
678   if ( aRes )
679     theColor = myElemColorMap1.Find ( ID );
680
681   return aRes;
682 }
683
684 //================================================================
685 // Function : SetColor1
686 // Purpose  :
687 //================================================================
688 void MeshVS_ElementalColorPrsBuilder::SetColor1 ( const Standard_Integer theID,
689                                                   const Quantity_Color& theCol )
690 {
691   Standard_Boolean aRes = myElemColorMap1.IsBound ( theID );
692   if ( aRes )
693     myElemColorMap1.ChangeFind ( theID ) = theCol;
694   else
695     myElemColorMap1.Bind ( theID, theCol );
696 }
697
698 //================================================================
699 // Function : SetColors2
700 // Purpose  :
701 //================================================================
702 void MeshVS_ElementalColorPrsBuilder::SetColors2 ( const MeshVS_DataMapOfIntegerTwoColors& theColorMap )
703 {
704   myElemColorMap2 = theColorMap;
705 }
706
707 //================================================================
708 // Function : GetColors2
709 // Purpose  :
710 //================================================================
711 const MeshVS_DataMapOfIntegerTwoColors& MeshVS_ElementalColorPrsBuilder::GetColors2 () const
712 {
713   return myElemColorMap2;
714 }
715
716 //================================================================
717 // Function : HasColors2
718 // Purpose  :
719 //================================================================
720 Standard_Boolean MeshVS_ElementalColorPrsBuilder::HasColors2 () const
721 {
722   return (myElemColorMap2.Extent()>0);
723 }
724
725 //================================================================
726 // Function : GetColor2
727 // Purpose  :
728 //================================================================
729 Standard_Boolean MeshVS_ElementalColorPrsBuilder::GetColor2 ( const Standard_Integer ID,
730                                                               MeshVS_TwoColors& theColor ) const
731 {
732   Standard_Boolean aRes = myElemColorMap2.IsBound ( ID );
733   if ( aRes )
734     theColor = myElemColorMap2.Find ( ID );
735
736   return aRes;
737 }
738
739 //================================================================
740 // Function : GetColor2
741 // Purpose  :
742 //================================================================
743 Standard_Boolean MeshVS_ElementalColorPrsBuilder::GetColor2 ( const Standard_Integer ID,
744                                                               Quantity_Color& theColor1,
745                                                               Quantity_Color& theColor2 ) const
746 {
747   MeshVS_TwoColors aTC;
748   Standard_Boolean aRes = GetColor2 ( ID, aTC );
749   if ( aRes)
750     ExtractColors ( aTC, theColor1, theColor2 );
751   return aRes;
752 }
753
754 //================================================================
755 // Function : SetColor2
756 // Purpose  :
757 //================================================================
758 void MeshVS_ElementalColorPrsBuilder::SetColor2 ( const Standard_Integer theID,
759                                                   const Quantity_Color& theCol1,
760                                                   const Quantity_Color& theCol2 )
761 {
762   SetColor2 ( theID, BindTwoColors ( theCol1, theCol2 ) );
763 }
764
765 //================================================================
766 // Function : SetColor2
767 // Purpose  :
768 //================================================================
769 void MeshVS_ElementalColorPrsBuilder::SetColor2 ( const Standard_Integer theID,
770                                                   const MeshVS_TwoColors& theCol )
771 {
772   Standard_Boolean aRes = myElemColorMap2.IsBound ( theID );
773   if ( aRes )
774     myElemColorMap2.ChangeFind ( theID ) = theCol;
775   else
776     myElemColorMap2.Bind ( theID, theCol );
777 }