0029570: Visualization, Graphic3d_Aspect - merge Graphic3d_Group aspects
[occt.git] / src / OpenGl / OpenGl_AspectFace.cxx
1 // Created on: 2011-07-13
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-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 #include <Aspect_PolygonOffsetMode.hxx>
17 #include <NCollection_Vec3.hxx>
18
19 #include <OpenGl_AspectFace.hxx>
20 #include <OpenGl_Context.hxx>
21 #include <OpenGl_Sampler.hxx>
22 #include <OpenGl_ShaderManager.hxx>
23 #include <OpenGl_ShaderProgram.hxx>
24 #include <OpenGl_Texture.hxx>
25 #include <OpenGl_Workspace.hxx>
26
27 #include <Graphic3d_ShaderProgram.hxx>
28 #include <Graphic3d_TextureMap.hxx>
29 #include <Graphic3d_TextureParams.hxx>
30 #include <Graphic3d_TypeOfReflection.hxx>
31 #include <Graphic3d_MaterialAspect.hxx>
32
33 #include <Image_PixMap.hxx>
34
35 namespace
36 {
37   //! Initialize default material in this way for backward compatibility.
38   inline Graphic3d_MaterialAspect initDefaultMaterial()
39   {
40     Graphic3d_MaterialAspect aMat;
41     aMat.SetMaterialType (Graphic3d_MATERIAL_ASPECT);
42     aMat.SetAmbient  (0.2f);
43     aMat.SetDiffuse  (0.8f);
44     aMat.SetSpecular (0.1f);
45     aMat.SetEmissive (0.0f);
46     aMat.SetAmbientColor (Quantity_NOC_WHITE);
47     aMat.SetDiffuseColor (Quantity_NOC_WHITE);
48     aMat.SetEmissiveColor(Quantity_NOC_WHITE);
49     aMat.SetSpecularColor(Quantity_NOC_WHITE);
50     aMat.SetShininess (10.0f / 128.0f);
51     aMat.SetRefractionIndex (1.0f);
52     return aMat;
53   }
54
55   static const TCollection_AsciiString  THE_EMPTY_KEY;
56   static const Graphic3d_MaterialAspect THE_DEFAULT_MATERIAL = initDefaultMaterial();
57 }
58
59 // =======================================================================
60 // function : OpenGl_AspectFace
61 // purpose  :
62 // =======================================================================
63 OpenGl_AspectFace::OpenGl_AspectFace()
64 : myAspect (new Graphic3d_AspectFillArea3d (Aspect_IS_SOLID, Quantity_NOC_WHITE,
65                                             Quantity_NOC_WHITE, Aspect_TOL_SOLID, 1.0,
66                                             THE_DEFAULT_MATERIAL, THE_DEFAULT_MATERIAL)),
67   myShadingModel (Graphic3d_TOSM_UNLIT)
68 {
69   myAspect->SetShadingModel (myShadingModel);
70   myAspect->SetHatchStyle (Handle(Graphic3d_HatchStyle)());
71 }
72
73 // =======================================================================
74 // function : OpenGl_AspectFace
75 // purpose  :
76 // =======================================================================
77 OpenGl_AspectFace::OpenGl_AspectFace (const Handle(Graphic3d_AspectFillArea3d)& theAspect)
78 : myShadingModel (Graphic3d_TOSM_DEFAULT)
79 {
80   SetAspect (theAspect);
81 }
82
83 // =======================================================================
84 // function : SetAspect
85 // purpose  :
86 // =======================================================================
87 void OpenGl_AspectFace::SetAspect (const Handle(Graphic3d_AspectFillArea3d)& theAspect)
88 {
89   myAspect = theAspect;
90
91   const Graphic3d_MaterialAspect& aMat = theAspect->FrontMaterial();
92   myShadingModel = theAspect->ShadingModel() != Graphic3d_TOSM_UNLIT
93                 && (aMat.ReflectionMode (Graphic3d_TOR_AMBIENT)
94                  || aMat.ReflectionMode (Graphic3d_TOR_DIFFUSE)
95                  || aMat.ReflectionMode (Graphic3d_TOR_SPECULAR)
96                  || aMat.ReflectionMode (Graphic3d_TOR_EMISSION))
97                  ? theAspect->ShadingModel()
98                  : Graphic3d_TOSM_UNLIT;
99
100   myAspectEdge.Aspect()->SetColor (theAspect->EdgeColor());
101   myAspectEdge.Aspect()->SetType  (theAspect->EdgeLineType());
102   myAspectEdge.Aspect()->SetWidth (theAspect->EdgeWidth());
103
104   // update texture binding
105   myResources.UpdateTexturesRediness (myAspect->TextureSet());
106
107   // update shader program binding
108   const TCollection_AsciiString& aShaderKey = myAspect->ShaderProgram().IsNull() ? THE_EMPTY_KEY : myAspect->ShaderProgram()->GetId();
109   if (aShaderKey.IsEmpty() || myResources.ShaderProgramId != aShaderKey)
110   {
111     myResources.ResetShaderReadiness();
112   }
113 }
114
115 // =======================================================================
116 // function : Render
117 // purpose  :
118 // =======================================================================
119 void OpenGl_AspectFace::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
120 {
121   theWorkspace->SetAspectFace (this);
122 }
123
124 // =======================================================================
125 // function : Release
126 // purpose  :
127 // =======================================================================
128 void OpenGl_AspectFace::Release (OpenGl_Context* theContext)
129 {
130   myResources.ReleaseTextures (theContext);
131   if (!myResources.ShaderProgram.IsNull()
132    && theContext)
133   {
134     theContext->ShaderManager()->Unregister (myResources.ShaderProgramId,
135                                              myResources.ShaderProgram);
136   }
137   myResources.ShaderProgramId.Clear();
138   myResources.ResetShaderReadiness();
139 }
140
141 // =======================================================================
142 // function : ReleaseTextures
143 // purpose  :
144 // =======================================================================
145 void OpenGl_AspectFace::Resources::ReleaseTextures (OpenGl_Context* theCtx)
146 {
147   if (myTextures.IsNull())
148   {
149     return;
150   }
151
152   for (OpenGl_TextureSet::Iterator aTextureIter (myTextures); aTextureIter.More(); aTextureIter.Next())
153   {
154     Handle(OpenGl_Texture)& aTextureRes = aTextureIter.ChangeValue();
155     if (aTextureRes.IsNull())
156     {
157       continue;
158     }
159
160     if (theCtx != NULL)
161     {
162       if (aTextureRes->ResourceId().IsEmpty())
163       {
164         theCtx->DelayedRelease (aTextureRes);
165       }
166       else
167       {
168         const TCollection_AsciiString aName = aTextureRes->ResourceId();
169         aTextureRes.Nullify(); // we need nullify all handles before ReleaseResource() call
170         theCtx->ReleaseResource (aName, Standard_True);
171       }
172     }
173     aTextureRes.Nullify();
174   }
175   myIsTextureReady = Standard_False;
176 }
177
178 // =======================================================================
179 // function : UpdateTexturesRediness
180 // purpose  :
181 // =======================================================================
182 void OpenGl_AspectFace::Resources::UpdateTexturesRediness (const Handle(Graphic3d_TextureSet)& theTextures)
183 {
184   const Standard_Integer aNbTexturesOld = !myTextures.IsNull()  ? myTextures->Size()  : 0;
185   const Standard_Integer aNbTexturesNew = !theTextures.IsNull() ? theTextures->Size() : 0;
186   if (aNbTexturesOld != aNbTexturesNew)
187   {
188     myIsTextureReady = Standard_False;
189     return;
190   }
191   if (aNbTexturesOld == 0)
192   {
193     return;
194   }
195
196   Graphic3d_TextureSet::Iterator aTextureIter (theTextures);
197   OpenGl_TextureSet::Iterator aResIter (myTextures);
198   for (; aResIter.More(); aResIter.Next(), aTextureIter.Next())
199   {
200     const Handle(OpenGl_Texture)&       aResource = aResIter.Value();
201     const Handle(Graphic3d_TextureMap)& aTexture  = aTextureIter.Value();
202     if (aTexture.IsNull() != aResource.IsNull())
203     {
204       myIsTextureReady = Standard_False;
205       return;
206     }
207     else if (aTexture.IsNull())
208     {
209       continue;
210     }
211
212     const TCollection_AsciiString& aTextureKey = aTexture->GetId();
213     if (aTextureKey.IsEmpty() || aResource->ResourceId() != aTextureKey)
214     {
215       myIsTextureReady = Standard_False;
216       return;
217     }
218     else if (aResource->Revision() != aTexture->Revision())
219     {
220       myIsTextureReady = Standard_False;
221       return;
222     }
223     else
224     {
225       // just invalidate texture parameters
226       aResource->Sampler()->SetParameters (aTexture->GetParams());
227     }
228   }
229 }
230
231 // =======================================================================
232 // function : BuildTextures
233 // purpose  :
234 // =======================================================================
235 void OpenGl_AspectFace::Resources::BuildTextures (const Handle(OpenGl_Context)& theCtx,
236                                                   const Handle(Graphic3d_TextureSet)& theTextures)
237 {
238   // release old texture resources
239   const Standard_Integer aNbTexturesOld = !myTextures.IsNull()  ? myTextures->Size()  : 0;
240   const Standard_Integer aNbTexturesNew = !theTextures.IsNull() ? theTextures->Size() : 0;
241   if (aNbTexturesOld != aNbTexturesNew)
242   {
243     ReleaseTextures (theCtx.get());
244     if (aNbTexturesNew > 0)
245     {
246       myTextures = new OpenGl_TextureSet (theTextures->Size());
247     }
248     else
249     {
250       myTextures.Nullify();
251     }
252   }
253   if (myTextures.IsNull())
254   {
255     return;
256   }
257
258   Graphic3d_TextureSet::Iterator aTextureIter (theTextures);
259   OpenGl_TextureSet::Iterator aResIter (myTextures);
260   for (; aResIter.More(); aResIter.Next(), aTextureIter.Next())
261   {
262     Handle(OpenGl_Texture)& aResource = aResIter.ChangeValue();
263     const Handle(Graphic3d_TextureMap)& aTexture = aTextureIter.Value();
264     if (!aResource.IsNull())
265     {
266       if (!aTexture.IsNull()
267        &&  aTexture->GetId()    == aResource->ResourceId()
268        &&  aTexture->Revision() != aResource->Revision())
269       {
270         if (Handle(Image_PixMap) anImage = aTexture->GetImage())
271         {
272           aResource->Sampler()->SetParameters (aTexture->GetParams());
273           aResource->Init (theCtx, *anImage.operator->(), aTexture->Type());
274           aResource->SetRevision (aTexture->Revision());
275           continue;
276         }
277       }
278
279       if (aResource->ResourceId().IsEmpty())
280       {
281         theCtx->DelayedRelease (aResource);
282         aResource.Nullify();
283       }
284       else
285       {
286         const TCollection_AsciiString aTextureKey = aResource->ResourceId();
287         aResource.Nullify(); // we need nullify all handles before ReleaseResource() call
288         theCtx->ReleaseResource (aTextureKey, Standard_True);
289       }
290     }
291
292     if (!aTexture.IsNull())
293     {
294       const TCollection_AsciiString& aTextureKeyNew = aTexture->GetId();
295       if (aTextureKeyNew.IsEmpty()
296       || !theCtx->GetResource<Handle(OpenGl_Texture)> (aTextureKeyNew, aResource))
297       {
298         aResource = new OpenGl_Texture (aTextureKeyNew, aTexture->GetParams());
299         if (Handle(Image_PixMap) anImage = aTexture->GetImage())
300         {
301           aResource->Init (theCtx, *anImage.operator->(), aTexture->Type());
302           aResource->SetRevision (aTexture->Revision());
303         }
304         if (!aTextureKeyNew.IsEmpty())
305         {
306           theCtx->ShareResource (aTextureKeyNew, aResource);
307         }
308       }
309       else
310       {
311         aResource->Sampler()->SetParameters (aTexture->GetParams());
312       }
313     }
314   }
315 }
316
317 // =======================================================================
318 // function : BuildShader
319 // purpose  :
320 // =======================================================================
321 void OpenGl_AspectFace::Resources::BuildShader (const Handle(OpenGl_Context)&          theCtx,
322                                                 const Handle(Graphic3d_ShaderProgram)& theShader)
323 {
324   if (theCtx->core20fwd == NULL)
325   {
326     return;
327   }
328
329   // release old shader program resources
330   if (!ShaderProgram.IsNull())
331   {
332     theCtx->ShaderManager()->Unregister (ShaderProgramId, ShaderProgram);
333     ShaderProgramId.Clear();
334     ShaderProgram.Nullify();
335   }
336   if (theShader.IsNull())
337   {
338     return;
339   }
340
341   theCtx->ShaderManager()->Create (theShader, ShaderProgramId, ShaderProgram);
342 }