0031096: Visualization, TKOpenGl - support metallic-roughness texture mapping
[occt.git] / src / OpenGl / OpenGl_AspectsTextureSet.cxx
1 // Copyright (c) 2019 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 <OpenGl_AspectsTextureSet.hxx>
15
16 #include <OpenGl_Context.hxx>
17 #include <OpenGl_Sampler.hxx>
18 #include <OpenGl_PointSprite.hxx>
19 #include <OpenGl_TextureSet.hxx>
20
21 #include <Graphic3d_TextureParams.hxx>
22
23 #include <Image_PixMap.hxx>
24
25 namespace
26 {
27   static const TCollection_AsciiString THE_EMPTY_KEY;
28 }
29
30 // =======================================================================
31 // function : Release
32 // purpose  :
33 // =======================================================================
34 void OpenGl_AspectsTextureSet::Release (OpenGl_Context* theCtx)
35 {
36   if (myTextures[0].IsNull())
37   {
38     return;
39   }
40
41   if (!myTextures[1].IsNull())
42   {
43     // ReleaseResource() will have no effect until nullifying all copies
44     myTextures[1]->InitZero();
45   }
46
47   for (OpenGl_TextureSet::Iterator aTextureIter (myTextures[0]); aTextureIter.More(); aTextureIter.Next())
48   {
49     Handle(OpenGl_Texture)& aTextureRes = aTextureIter.ChangeValue();
50     if (aTextureRes.IsNull())
51     {
52       continue;
53     }
54
55     if (theCtx != NULL)
56     {
57       if (aTextureRes->ResourceId().IsEmpty())
58       {
59         theCtx->DelayedRelease (aTextureRes);
60       }
61       else
62       {
63         // OpenGl_PointSprite will be actually released later by OpenGl_AspectsSprite,
64         // see order OpenGl_Aspects::Release()
65         const TCollection_AsciiString aName = aTextureRes->ResourceId();
66         aTextureRes.Nullify(); // we need nullify all handles before ReleaseResource() call
67         theCtx->ReleaseResource (aName, Standard_True);
68       }
69     }
70     aTextureRes.Nullify();
71   }
72   myIsTextureReady = Standard_False;
73 }
74
75 // =======================================================================
76 // function : UpdateRediness
77 // purpose  :
78 // =======================================================================
79 void OpenGl_AspectsTextureSet::UpdateRediness (const Handle(Graphic3d_Aspects)& theAspect)
80 {
81   const Handle(Graphic3d_TextureSet)& aNewTextureSet = theAspect->TextureSet();
82
83   const Standard_Integer aNbTexturesOld = !myTextures[0].IsNull() ? myTextures[0]->Size() : 0;
84   Standard_Integer aNbTexturesNew = !aNewTextureSet.IsNull() && theAspect->ToMapTexture()
85                                    ? aNewTextureSet->Size()
86                                    : 0;
87   if (theAspect->IsMarkerSprite())
88   {
89     ++aNbTexturesNew;
90   }
91
92   if (aNbTexturesOld != aNbTexturesNew)
93   {
94     myIsTextureReady = Standard_False;
95     return;
96   }
97   if (aNbTexturesOld == 0
98   || !theAspect->ToMapTexture())
99   {
100     return;
101   }
102
103   Graphic3d_TextureSet::Iterator aTextureIter (aNewTextureSet);
104   OpenGl_TextureSet::Iterator aResIter (myTextures[0]);
105   for (; aTextureIter.More(); aResIter.Next(), aTextureIter.Next())
106   {
107     const Handle(OpenGl_Texture)&       aResource = aResIter.Value();
108     const Handle(Graphic3d_TextureMap)& aTexture  = aTextureIter.Value();
109     if (aTexture.IsNull() != aResource.IsNull())
110     {
111       myIsTextureReady = Standard_False;
112       return;
113     }
114     else if (aTexture.IsNull())
115     {
116       continue;
117     }
118
119     const TCollection_AsciiString& aTextureKey = aTexture->GetId();
120     if (aTextureKey.IsEmpty() || aResource->ResourceId() != aTextureKey)
121     {
122       myIsTextureReady = Standard_False;
123       return;
124     }
125     else if (aResource->Revision() != aTexture->Revision())
126     {
127       myIsTextureReady = Standard_False;
128       return;
129     }
130     else
131     {
132       // just invalidate texture parameters
133       aResource->Sampler()->SetParameters (aTexture->GetParams());
134       aResIter.ChangeUnit() = aResource->Sampler()->Parameters()->TextureUnit();
135     }
136   }
137 }
138
139 // =======================================================================
140 // function : build
141 // purpose  :
142 // =======================================================================
143 void OpenGl_AspectsTextureSet::build (const Handle(OpenGl_Context)& theCtx,
144                                       const Handle(Graphic3d_Aspects)& theAspect,
145                                       const Handle(OpenGl_PointSprite)& theSprite,
146                                       const Handle(OpenGl_PointSprite)& theSpriteA)
147 {
148   const Handle(Graphic3d_TextureSet)& aNewTextureSet = theAspect->TextureSet();
149
150   const bool hasSprite = theAspect->IsMarkerSprite();
151   const Standard_Integer aNbTexturesOld = !myTextures[0].IsNull() ? myTextures[0]->Size() : 0;
152   Standard_Integer aNbTexturesNew = !aNewTextureSet.IsNull() && theAspect->ToMapTexture()
153                                   ? aNewTextureSet->Size()
154                                   : 0;
155   if (hasSprite)
156   {
157     ++aNbTexturesNew;
158   }
159
160   // release old texture resources
161   if (aNbTexturesOld != aNbTexturesNew)
162   {
163     Release (theCtx.get());
164     if (aNbTexturesNew > 0)
165     {
166       myTextures[0] = new OpenGl_TextureSet (aNbTexturesNew);
167     }
168     else
169     {
170       myTextures[0].Nullify();
171       myTextures[1].Nullify();
172     }
173   }
174   if (myTextures[0].IsNull())
175   {
176     return;
177   }
178
179   if (theSprite == theSpriteA)
180   {
181     myTextures[1].Nullify();
182   }
183   else
184   {
185     if (myTextures[1].IsNull()
186      || myTextures[1]->Size() != myTextures[0]->Size())
187     {
188       myTextures[1] = new OpenGl_TextureSet (aNbTexturesNew);
189     }
190     else
191     {
192       myTextures[1]->InitZero();
193     }
194   }
195
196   Standard_Integer& aTextureSetBits = myTextures[0]->ChangeTextureSetBits();
197   aTextureSetBits = Graphic3d_TextureSetBits_NONE;
198   if (theAspect->ToMapTexture())
199   {
200     Graphic3d_TextureSet::Iterator aTextureIter (aNewTextureSet);
201     OpenGl_TextureSet::Iterator aResIter0 (myTextures[0]);
202     for (; aTextureIter.More(); aResIter0.Next(), aTextureIter.Next())
203     {
204       Handle(OpenGl_Texture)& aResource = aResIter0.ChangeValue();
205       const Handle(Graphic3d_TextureMap)& aTexture = aTextureIter.Value();
206       if (!aResource.IsNull())
207       {
208         if (!aTexture.IsNull()
209          &&  aTexture->GetId()    == aResource->ResourceId()
210          &&  aTexture->Revision() != aResource->Revision())
211         {
212           if (aResource->Init(theCtx, aTexture))
213           {
214             aResIter0.ChangeUnit() = aResource->Sampler()->Parameters()->TextureUnit();
215             aResource->Sampler()->SetParameters(aTexture->GetParams());
216             aResource->SetRevision (aTexture->Revision());
217           }
218         }
219
220         if (aResource->ResourceId().IsEmpty())
221         {
222           theCtx->DelayedRelease (aResource);
223           aResource.Nullify();
224         }
225         else
226         {
227           const TCollection_AsciiString aTextureKey = aResource->ResourceId();
228           aResource.Nullify(); // we need nullify all handles before ReleaseResource() call
229           theCtx->ReleaseResource (aTextureKey, Standard_True);
230         }
231       }
232
233       if (!aTexture.IsNull())
234       {
235         const TCollection_AsciiString& aTextureKeyNew = aTexture->GetId();
236         if (aTextureKeyNew.IsEmpty()
237         || !theCtx->GetResource<Handle(OpenGl_Texture)> (aTextureKeyNew, aResource))
238         {
239           aResource = new OpenGl_Texture (aTextureKeyNew, aTexture->GetParams());
240
241           if (aResource->Init(theCtx, aTexture))
242           {
243             aResource->SetRevision (aTexture->Revision());
244           }
245           if (!aTextureKeyNew.IsEmpty())
246           {
247             theCtx->ShareResource (aTextureKeyNew, aResource);
248           }
249         }
250         else
251         {
252           if (aTexture->Revision() != aResource->Revision())
253           {
254             if (aResource->Init(theCtx, aTexture))
255             {
256               aResource->SetRevision (aTexture->Revision());
257             }
258           }
259           aResource->Sampler()->SetParameters (aTexture->GetParams());
260         }
261
262         // update occupation of texture units
263         const Graphic3d_TextureUnit aTexUnit = aResource->Sampler()->Parameters()->TextureUnit();
264         aResIter0.ChangeUnit() = aTexUnit;
265         if (aTexUnit >= Graphic3d_TextureUnit_0 && aTexUnit <= Graphic3d_TextureUnit_5)
266         {
267           aTextureSetBits |= (1 << int(aTexUnit));
268         }
269       }
270     }
271   }
272
273   if (hasSprite)
274   {
275     myTextures[0]->ChangeLast() = theSprite;
276     myTextures[0]->ChangeLastUnit() = theCtx->SpriteTextureUnit();
277     // Graphic3d_TextureUnit_PointSprite
278     if (!theSprite.IsNull())
279     {
280       theSprite ->Sampler()->Parameters()->SetTextureUnit (theCtx->SpriteTextureUnit());
281     }
282     if (!theSpriteA.IsNull())
283     {
284       theSpriteA->Sampler()->Parameters()->SetTextureUnit (theCtx->SpriteTextureUnit());
285     }
286   }
287   if (myTextures[1].IsNull())
288   {
289     return;
290   }
291
292   myTextures[1]->ChangeTextureSetBits() = aTextureSetBits;
293   for (OpenGl_TextureSet::Iterator aResIter0 (myTextures[0]), aResIter1 (myTextures[1]); aResIter0.More(); aResIter0.Next(), aResIter1.Next())
294   {
295     aResIter1.ChangeValue() = aResIter0.Value();
296     aResIter1.ChangeUnit()  = aResIter0.Unit();
297   }
298   if (hasSprite)
299   {
300     myTextures[1]->ChangeLast() = theSpriteA;
301     myTextures[1]->ChangeLastUnit() = theCtx->SpriteTextureUnit();
302   }
303 }