0031642: Visualization - crash in Graphic3d_Structure::SetVisual() on redisplaying...
[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   Standard_Integer aPrevTextureUnit = -1;
199   if (theAspect->ToMapTexture())
200   {
201     Graphic3d_TextureSet::Iterator aTextureIter (aNewTextureSet);
202     OpenGl_TextureSet::Iterator aResIter0 (myTextures[0]);
203     for (; aTextureIter.More(); aResIter0.Next(), aTextureIter.Next())
204     {
205       Handle(OpenGl_Texture)& aResource = aResIter0.ChangeValue();
206       const Handle(Graphic3d_TextureMap)& aTexture = aTextureIter.Value();
207       if (!aResource.IsNull())
208       {
209         if (!aTexture.IsNull()
210          &&  aTexture->GetId()    == aResource->ResourceId()
211          &&  aTexture->Revision() != aResource->Revision())
212         {
213           if (aResource->Init(theCtx, aTexture))
214           {
215             aResIter0.ChangeUnit() = aResource->Sampler()->Parameters()->TextureUnit();
216             if (aResIter0.Unit() < aPrevTextureUnit)
217             {
218               throw Standard_ProgramError("Graphic3d_TextureMap defines texture units in non-ascending order");
219             }
220             aPrevTextureUnit = aResIter0.Unit();
221             aResource->Sampler()->SetParameters(aTexture->GetParams());
222             aResource->SetRevision (aTexture->Revision());
223           }
224         }
225
226         if (aResource->ResourceId().IsEmpty())
227         {
228           theCtx->DelayedRelease (aResource);
229           aResource.Nullify();
230         }
231         else
232         {
233           const TCollection_AsciiString aTextureKey = aResource->ResourceId();
234           aResource.Nullify(); // we need nullify all handles before ReleaseResource() call
235           theCtx->ReleaseResource (aTextureKey, Standard_True);
236         }
237       }
238
239       if (!aTexture.IsNull())
240       {
241         const TCollection_AsciiString& aTextureKeyNew = aTexture->GetId();
242         if (aTextureKeyNew.IsEmpty()
243         || !theCtx->GetResource<Handle(OpenGl_Texture)> (aTextureKeyNew, aResource))
244         {
245           aResource = new OpenGl_Texture (aTextureKeyNew, aTexture->GetParams());
246
247           if (aResource->Init(theCtx, aTexture))
248           {
249             aResource->SetRevision (aTexture->Revision());
250           }
251           if (!aTextureKeyNew.IsEmpty())
252           {
253             theCtx->ShareResource (aTextureKeyNew, aResource);
254           }
255         }
256         else
257         {
258           if (aTexture->Revision() != aResource->Revision())
259           {
260             if (aResource->Init(theCtx, aTexture))
261             {
262               aResource->SetRevision (aTexture->Revision());
263             }
264           }
265           aResource->Sampler()->SetParameters (aTexture->GetParams());
266         }
267
268         // update occupation of texture units
269         const Graphic3d_TextureUnit aTexUnit = aResource->Sampler()->Parameters()->TextureUnit();
270         aResIter0.ChangeUnit() = aTexUnit;
271         if (aResIter0.Unit() < aPrevTextureUnit)
272         {
273           throw Standard_ProgramError("Graphic3d_TextureMap defines texture units in non-ascending order");
274         }
275         aPrevTextureUnit = aResIter0.Unit();
276         if (aTexUnit >= Graphic3d_TextureUnit_0 && aTexUnit <= Graphic3d_TextureUnit_5)
277         {
278           aTextureSetBits |= (1 << int(aTexUnit));
279         }
280       }
281     }
282   }
283
284   if (hasSprite)
285   {
286     myTextures[0]->ChangeLast() = theSprite;
287     myTextures[0]->ChangeLastUnit() = theCtx->SpriteTextureUnit();
288     // Graphic3d_TextureUnit_PointSprite
289     if (!theSprite.IsNull())
290     {
291       theSprite ->Sampler()->Parameters()->SetTextureUnit (theCtx->SpriteTextureUnit());
292     }
293     if (!theSpriteA.IsNull())
294     {
295       theSpriteA->Sampler()->Parameters()->SetTextureUnit (theCtx->SpriteTextureUnit());
296     }
297   }
298   if (myTextures[1].IsNull())
299   {
300     return;
301   }
302
303   myTextures[1]->ChangeTextureSetBits() = aTextureSetBits;
304   for (OpenGl_TextureSet::Iterator aResIter0 (myTextures[0]), aResIter1 (myTextures[1]); aResIter0.More(); aResIter0.Next(), aResIter1.Next())
305   {
306     aResIter1.ChangeValue() = aResIter0.Value();
307     aResIter1.ChangeUnit()  = aResIter0.Unit();
308   }
309   if (hasSprite)
310   {
311     myTextures[1]->ChangeLast() = theSpriteA;
312     myTextures[1]->ChangeLastUnit() = theCtx->SpriteTextureUnit();
313   }
314 }