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