61dcca9b0d425ccf0c982368c422d5644a25e119
[occt.git] / src / Graphic3d / Graphic3d_LightSet.cxx
1 // Copyright (c) 2017 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <Graphic3d_LightSet.hxx>
15
16 #include <NCollection_LocalArray.hxx>
17
18 IMPLEMENT_STANDARD_RTTIEXT(Graphic3d_LightSet, Standard_Transient)
19
20 namespace
21 {
22   //! Suffixes identifying light source type.
23   static const char THE_LIGHT_KEY_LETTERS[Graphic3d_TypeOfLightSource_NB] =
24   {
25     'a', // Graphic3d_TOLS_AMBIENT
26     'd', // Graphic3d_TOLS_DIRECTIONAL
27     'p', // Graphic3d_TOLS_POSITIONAL
28     's'  // Graphic3d_TOLS_SPOT
29   };
30 }
31
32 // =======================================================================
33 // function : Graphic3d_LightSet
34 // purpose  :
35 // =======================================================================
36 Graphic3d_LightSet::Graphic3d_LightSet()
37 : myAmbient (0.0f, 0.0f, 0.0f, 0.0f),
38   myNbEnabled (0),
39   myNbCastShadows (0),
40   myRevision (1),
41   myCacheRevision (0)
42 {
43   memset (myLightTypes,        0, sizeof(myLightTypes));
44   memset (myLightTypesEnabled, 0, sizeof(myLightTypesEnabled));
45 }
46
47 // =======================================================================
48 // function : Add
49 // purpose  :
50 // =======================================================================
51 Standard_Boolean Graphic3d_LightSet::Add (const Handle(Graphic3d_CLight)& theLight)
52 {
53   if (theLight.IsNull())
54   {
55     throw Standard_ProgramError ("Graphic3d_LightSet::Add(), NULL argument");
56   }
57
58   const Standard_Integer anOldExtent = myLights.Extent();
59   const Standard_Integer anIndex     = myLights.Add (theLight, 0);
60   if (anIndex <= anOldExtent)
61   {
62     return Standard_False;
63   }
64
65   myLightTypes[theLight->Type()] += 1;
66   myLights.ChangeFromIndex (anIndex) = theLight->Revision();
67   ++myRevision;
68   return Standard_True;
69 }
70
71 // =======================================================================
72 // function : Remove
73 // purpose  :
74 // =======================================================================
75 Standard_Boolean Graphic3d_LightSet::Remove (const Handle(Graphic3d_CLight)& theLight)
76 {
77   const Standard_Integer anIndToRemove = myLights.FindIndex (theLight);
78   if (anIndToRemove <= 0)
79   {
80     return Standard_False;
81   }
82
83   ++myRevision;
84   myLights.RemoveFromIndex (anIndToRemove);
85   myLightTypes[theLight->Type()] -= 1;
86   return Standard_True;
87 }
88
89 // =======================================================================
90 // function : UpdateRevision
91 // purpose  :
92 // =======================================================================
93 Standard_Size Graphic3d_LightSet::UpdateRevision()
94 {
95   if (myCacheRevision == myRevision)
96   {
97     // check implicit updates of light sources
98     for (NCollection_IndexedDataMap<Handle(Graphic3d_CLight), Standard_Size>::Iterator aLightIter (myLights); aLightIter.More(); aLightIter.Next())
99     {
100       const Handle(Graphic3d_CLight)& aLight = aLightIter.Key();
101       if (aLightIter.Value() != aLight->Revision())
102       {
103         ++myRevision;
104         break;
105       }
106     }
107   }
108   if (myCacheRevision == myRevision)
109   {
110     return myRevision;
111   }
112
113   myCacheRevision = myRevision;
114   myNbCastShadows = 0;
115   myAmbient.SetValues (0.0f, 0.0f, 0.0f, 0.0f);
116   memset (myLightTypesEnabled, 0, sizeof(myLightTypesEnabled));
117   NCollection_LocalArray<char, 32> aKeyLong (myLights.Extent() + 1);
118   Standard_Integer aLightLast = 0;
119   for (NCollection_IndexedDataMap<Handle(Graphic3d_CLight), Standard_Size>::Iterator aLightIter (myLights); aLightIter.More(); aLightIter.Next())
120   {
121     const Handle(Graphic3d_CLight)& aLight = aLightIter.Key();
122     aLightIter.ChangeValue() = aLight->Revision();
123     if (!aLight->IsEnabled())
124     {
125       continue;
126     }
127
128     myLightTypesEnabled[aLight->Type()] += 1;
129     if (aLight->Type() == Graphic3d_TOLS_AMBIENT)
130     {
131       myAmbient += aLight->PackedColor() * aLight->Intensity();
132     }
133     else
134     {
135       if (aLight->ToCastShadows())
136       {
137         ++myNbCastShadows;
138         aKeyLong[aLightLast++] = UpperCase (THE_LIGHT_KEY_LETTERS[aLight->Type()]);
139       }
140       else
141       {
142         aKeyLong[aLightLast++] = THE_LIGHT_KEY_LETTERS[aLight->Type()];
143       }
144     }
145   }
146   aKeyLong[aLightLast] = '\0';
147   myAmbient.a() = 1.0f;
148   myNbEnabled = myLightTypesEnabled[Graphic3d_TOLS_DIRECTIONAL]
149               + myLightTypesEnabled[Graphic3d_TOLS_POSITIONAL]
150               + myLightTypesEnabled[Graphic3d_TOLS_SPOT];
151   myKeyEnabledLong  = aKeyLong;
152   myKeyEnabledShort = TCollection_AsciiString (myLightTypesEnabled[Graphic3d_TOLS_DIRECTIONAL] > 0 ? THE_LIGHT_KEY_LETTERS[Graphic3d_TOLS_DIRECTIONAL] : '\0')
153                     + TCollection_AsciiString (myLightTypesEnabled[Graphic3d_TOLS_POSITIONAL]  > 0 ? THE_LIGHT_KEY_LETTERS[Graphic3d_TOLS_POSITIONAL]  : '\0')
154                     + TCollection_AsciiString (myLightTypesEnabled[Graphic3d_TOLS_SPOT]        > 0 ? THE_LIGHT_KEY_LETTERS[Graphic3d_TOLS_SPOT]        : '\0');
155   return myRevision;
156 }