0031580: Visualization, TKOpenGl - cubemap initialization error on OpenGL ES 2.0
[occt.git] / src / OpenGl / OpenGl_Sampler.cxx
1 // Created on: 2014-10-08
2 // Created by: Denis BOGOLEPOV
3 // Copyright (c) 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 <OpenGl_Sampler.hxx>
17
18 #include <OpenGl_ArbSamplerObject.hxx>
19 #include <OpenGl_Texture.hxx>
20 #include <Standard_Assert.hxx>
21
22 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Sampler,OpenGl_Resource)
23
24 // =======================================================================
25 // function : OpenGl_Sampler
26 // purpose  :
27 // =======================================================================
28 OpenGl_Sampler::OpenGl_Sampler (const Handle(Graphic3d_TextureParams)& theParams)
29 : myParams (theParams),
30   mySamplerRevision (0),
31   mySamplerID (NO_SAMPLER),
32   myIsImmutable (false)
33 {
34   if (myParams.IsNull())
35   {
36     myParams = new Graphic3d_TextureParams();
37   }
38 }
39
40 // =======================================================================
41 // function : ~OpenGl_Sampler
42 // purpose  :
43 // =======================================================================
44 OpenGl_Sampler::~OpenGl_Sampler()
45 {
46   Release (NULL);
47 }
48
49 // =======================================================================
50 // function : Release
51 // purpose  :
52 // =======================================================================
53 void OpenGl_Sampler::Release (OpenGl_Context* theCtx)
54 {
55   myIsImmutable = false;
56   mySamplerRevision = myParams->SamplerRevision() - 1;
57   if (!isValidSampler())
58   {
59     return;
60   }
61
62   // application can not handle this case by exception - this is bug in code
63   Standard_ASSERT_RETURN (theCtx != NULL,
64     "OpenGl_Sampler destroyed without GL context! Possible GPU memory leakage...",);
65
66   if (theCtx->IsValid())
67   {
68     theCtx->arbSamplerObject->glDeleteSamplers (1, &mySamplerID);
69   }
70
71   mySamplerID = NO_SAMPLER;
72 }
73
74 // =======================================================================
75 // function : Create
76 // purpose  :
77 // =======================================================================
78 Standard_Boolean OpenGl_Sampler::Create (const Handle(OpenGl_Context)& theCtx)
79 {
80   if (isValidSampler())
81   {
82     return Standard_True;
83   }
84   else if (theCtx->arbSamplerObject == NULL)
85   {
86     return Standard_False;
87   }
88
89   theCtx->arbSamplerObject->glGenSamplers (1, &mySamplerID);
90   return Standard_True;
91 }
92
93 // =======================================================================
94 // function : Init
95 // purpose  :
96 // =======================================================================
97 Standard_Boolean OpenGl_Sampler::Init (const Handle(OpenGl_Context)& theCtx,
98                                        const OpenGl_Texture& theTexture)
99 {
100   if (isValidSampler())
101   {
102     if (!ToUpdateParameters())
103     {
104       return Standard_True;
105     }
106     else if (!myIsImmutable)
107     {
108       applySamplerParams (theCtx, myParams, this, theTexture.GetTarget(), theTexture.MaxMipmapLevel());
109       return Standard_True;
110     }
111     Release (theCtx.get());
112   }
113
114   if (!Create (theCtx))
115   {
116     return Standard_False;
117   }
118
119   applySamplerParams (theCtx, myParams, this, theTexture.GetTarget(), theTexture.MaxMipmapLevel());
120   return Standard_True;
121 }
122
123 // =======================================================================
124 // function : Bind
125 // purpose  : Binds sampler object to the given texture unit
126 // =======================================================================
127 void OpenGl_Sampler::Bind (const Handle(OpenGl_Context)& theCtx,
128                            const Graphic3d_TextureUnit   theUnit)
129 {
130   if (isValidSampler())
131   {
132     theCtx->arbSamplerObject->glBindSampler (theUnit, mySamplerID);
133   }
134 }
135
136 // =======================================================================
137 // function : Unbind
138 // purpose  : Unbinds sampler object from the given texture unit
139 // =======================================================================
140 void OpenGl_Sampler::Unbind (const Handle(OpenGl_Context)& theCtx,
141                              const Graphic3d_TextureUnit   theUnit)
142 {
143   if (isValidSampler())
144   {
145     theCtx->arbSamplerObject->glBindSampler (theUnit, NO_SAMPLER);
146   }
147 }
148
149 // =======================================================================
150 // function : setParameter
151 // purpose  :
152 // =======================================================================
153 void OpenGl_Sampler::setParameter (const Handle(OpenGl_Context)& theCtx,
154                                    OpenGl_Sampler* theSampler,
155                                    GLenum theTarget,
156                                    GLenum theParam,
157                                    GLint  theValue)
158 {
159   if (theSampler != NULL && theSampler->isValidSampler())
160   {
161     theCtx->arbSamplerObject->glSamplerParameteri (theSampler->mySamplerID, theParam, theValue);
162   }
163   else
164   {
165     theCtx->core11fwd->glTexParameteri (theTarget, theParam, theValue);
166   }
167 }
168
169 // =======================================================================
170 // function : SetParameters
171 // purpose  :
172 // =======================================================================
173 void OpenGl_Sampler::SetParameters (const Handle(Graphic3d_TextureParams)& theParams)
174 {
175   if (myParams != theParams)
176   {
177     myParams = theParams;
178     mySamplerRevision = myParams->SamplerRevision() - 1;
179   }
180 }
181
182 // =======================================================================
183 // function : applySamplerParams
184 // purpose  :
185 // =======================================================================
186 void OpenGl_Sampler::applySamplerParams (const Handle(OpenGl_Context)& theCtx,
187                                          const Handle(Graphic3d_TextureParams)& theParams,
188                                          OpenGl_Sampler* theSampler,
189                                          const GLenum theTarget,
190                                          const Standard_Integer theMaxMipLevels)
191 {
192   if (theSampler != NULL && theSampler->Parameters() == theParams)
193   {
194     theSampler->mySamplerRevision = theParams->SamplerRevision();
195   }
196
197   // setup texture filtering
198   const GLenum aFilter = (theParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR;
199   GLenum aFilterMin = aFilter;
200   if (theMaxMipLevels > 0)
201   {
202     aFilterMin = GL_NEAREST_MIPMAP_NEAREST;
203     if (theParams->Filter() == Graphic3d_TOTF_BILINEAR)
204     {
205       aFilterMin = GL_LINEAR_MIPMAP_NEAREST;
206     }
207     else if (theParams->Filter() == Graphic3d_TOTF_TRILINEAR)
208     {
209       aFilterMin = GL_LINEAR_MIPMAP_LINEAR;
210     }
211   }
212
213   setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_MIN_FILTER, aFilterMin);
214   setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_MAG_FILTER, aFilter);
215
216   // setup texture wrapping
217   const GLenum aWrapMode = theParams->IsRepeat() ? GL_REPEAT : theCtx->TextureWrapClamp();
218   setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_WRAP_S, aWrapMode);
219 #if !defined(GL_ES_VERSION_2_0)
220   if (theTarget == GL_TEXTURE_1D)
221   {
222     return;
223   }
224 #endif
225   setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_WRAP_T, aWrapMode);
226   if (theTarget == GL_TEXTURE_3D
227    || theTarget == GL_TEXTURE_CUBE_MAP)
228   {
229     if (theCtx->HasTextureBaseLevel())
230     {
231       setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_WRAP_R, aWrapMode);
232     }
233     return;
234   }
235
236   if (theCtx->extAnis)
237   {
238     // setup degree of anisotropy filter
239     const GLint aMaxDegree = theCtx->MaxDegreeOfAnisotropy();
240     GLint aDegree;
241     switch (theParams->AnisoFilter())
242     {
243       case Graphic3d_LOTA_QUALITY:
244       {
245         aDegree = aMaxDegree;
246         break;
247       }
248       case Graphic3d_LOTA_MIDDLE:
249       {
250         aDegree = (aMaxDegree <= 4) ? 2 : (aMaxDegree / 2);
251         break;
252       }
253       case Graphic3d_LOTA_FAST:
254       {
255         aDegree = 2;
256         break;
257       }
258       case Graphic3d_LOTA_OFF:
259       default:
260       {
261         aDegree = 1;
262         break;
263       }
264     }
265
266     setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, aDegree);
267   }
268
269   if (theCtx->HasTextureBaseLevel()
270    && (theSampler == NULL || !theSampler->isValidSampler()))
271   {
272     const Standard_Integer aMaxLevel = Min (theMaxMipLevels, theParams->MaxLevel());
273     setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_BASE_LEVEL, theParams->BaseLevel());
274     setParameter (theCtx, theSampler, theTarget, GL_TEXTURE_MAX_LEVEL,  aMaxLevel);
275   }
276 }
277
278 // =======================================================================
279 // function : applyGlobalTextureParams
280 // purpose  :
281 // =======================================================================
282 void OpenGl_Sampler::applyGlobalTextureParams (const Handle(OpenGl_Context)& theCtx,
283                                                const OpenGl_Texture& theTexture,
284                                                const Handle(Graphic3d_TextureParams)& theParams)
285 {
286 #if defined(GL_ES_VERSION_2_0)
287   (void )theCtx;
288   (void )theTexture;
289   (void )theParams;
290 #else
291   if (theCtx->core11 == NULL
292    || theParams->TextureUnit() >= theCtx->MaxTextureUnitsFFP())
293   {
294     return;
295   }
296
297   GLint anEnvMode = GL_MODULATE; // lighting mode
298   if (!theParams->IsModulate())
299   {
300     anEnvMode = GL_DECAL;
301     if (theTexture.GetFormat() == GL_ALPHA
302      || theTexture.GetFormat() == GL_LUMINANCE)
303     {
304       anEnvMode = GL_REPLACE;
305     }
306   }
307
308   // setup generation of texture coordinates
309   switch (theParams->GenMode())
310   {
311     case Graphic3d_TOTM_OBJECT:
312     {
313       theCtx->core11->glTexGeni  (GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
314       theCtx->core11->glTexGenfv (GL_S, GL_OBJECT_PLANE,     theParams->GenPlaneS().GetData());
315       if (theTexture.GetTarget() != GL_TEXTURE_1D)
316       {
317         theCtx->core11->glTexGeni  (GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
318         theCtx->core11->glTexGenfv (GL_T, GL_OBJECT_PLANE,     theParams->GenPlaneT().GetData());
319       }
320       break;
321     }
322     case Graphic3d_TOTM_SPHERE:
323     {
324       theCtx->core11->glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
325       if (theTexture.GetTarget() != GL_TEXTURE_1D)
326       {
327         theCtx->core11->glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
328       }
329       break;
330     }
331     case Graphic3d_TOTM_EYE:
332     {
333       theCtx->WorldViewState.Push();
334       theCtx->WorldViewState.SetIdentity();
335       theCtx->ApplyWorldViewMatrix();
336
337       theCtx->core11->glTexGeni  (GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
338       theCtx->core11->glTexGenfv (GL_S, GL_EYE_PLANE,        theParams->GenPlaneS().GetData());
339       if (theTexture.GetTarget() != GL_TEXTURE_1D)
340       {
341         theCtx->core11->glTexGeni  (GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
342         theCtx->core11->glTexGenfv (GL_T, GL_EYE_PLANE,        theParams->GenPlaneT().GetData());
343       }
344
345       theCtx->WorldViewState.Pop();
346       break;
347     }
348     case Graphic3d_TOTM_SPRITE:
349     {
350       if (theCtx->core20fwd != NULL)
351       {
352         theCtx->core11fwd->glEnable (GL_POINT_SPRITE);
353         glTexEnvi (GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
354         anEnvMode = GL_REPLACE;
355       }
356       break;
357     }
358     case Graphic3d_TOTM_MANUAL:
359     default: break;
360   }
361
362   // setup lighting
363   glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, anEnvMode);
364
365   switch (theTexture.GetTarget())
366   {
367     case GL_TEXTURE_1D:
368     {
369       if (theParams->GenMode() != Graphic3d_TOTM_MANUAL)
370       {
371         theCtx->core11fwd->glEnable (GL_TEXTURE_GEN_S);
372       }
373       theCtx->core11fwd->glEnable (GL_TEXTURE_1D);
374       break;
375     }
376     case GL_TEXTURE_2D:
377     {
378       if (theParams->GenMode() != Graphic3d_TOTM_MANUAL)
379       {
380         theCtx->core11fwd->glEnable (GL_TEXTURE_GEN_S);
381         theCtx->core11fwd->glEnable (GL_TEXTURE_GEN_T);
382       }
383       theCtx->core11fwd->glEnable (GL_TEXTURE_2D);
384       break;
385     }
386     default: break;
387   }
388 #endif
389 }
390
391 // =======================================================================
392 // function : resetGlobalTextureParams
393 // purpose  :
394 // =======================================================================
395 void OpenGl_Sampler::resetGlobalTextureParams (const Handle(OpenGl_Context)& theCtx,
396                                                const OpenGl_Texture& theTexture,
397                                                const Handle(Graphic3d_TextureParams)& theParams)
398 {
399 #if defined(GL_ES_VERSION_2_0)
400   (void )theCtx;
401   (void )theTexture;
402   (void )theParams;
403 #else
404   if (theCtx->core11 == NULL)
405   {
406     return;
407   }
408
409   // reset texture matrix because some code may expect it is identity
410   GLint aMatrixMode = GL_TEXTURE;
411   theCtx->core11fwd->glGetIntegerv (GL_MATRIX_MODE, &aMatrixMode);
412   theCtx->core11->glMatrixMode (GL_TEXTURE);
413   theCtx->core11->glLoadIdentity();
414   theCtx->core11->glMatrixMode (aMatrixMode);
415
416   switch (theTexture.GetTarget())
417   {
418     case GL_TEXTURE_1D:
419     {
420       if (theParams->GenMode() != GL_NONE)
421       {
422         theCtx->core11fwd->glDisable (GL_TEXTURE_GEN_S);
423       }
424       theCtx->core11fwd->glDisable (GL_TEXTURE_1D);
425       break;
426     }
427     case GL_TEXTURE_2D:
428     {
429       if (theParams->GenMode() != GL_NONE)
430       {
431         theCtx->core11fwd->glDisable (GL_TEXTURE_GEN_S);
432         theCtx->core11fwd->glDisable (GL_TEXTURE_GEN_T);
433         if (theParams->GenMode() == Graphic3d_TOTM_SPRITE
434          && theCtx->core20fwd != NULL)
435         {
436           theCtx->core11fwd->glDisable (GL_POINT_SPRITE);
437         }
438       }
439       theCtx->core11fwd->glDisable (GL_TEXTURE_2D);
440       break;
441     }
442     default: break;
443   }
444 #endif
445 }