0028441: Coding Rules - move out nested Image_PixMap::ImgFormat enumeration to dedica...
[occt.git] / src / OpenGl / OpenGl_Texture.cxx
1 // Created by: Kirill GAVRILOV
2 // Copyright (c) 2013-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #include <OpenGl_Texture.hxx>
16
17 #include <OpenGl_ArbFBO.hxx>
18 #include <OpenGl_Context.hxx>
19 #include <OpenGl_GlCore32.hxx>
20 #include <Graphic3d_TextureParams.hxx>
21 #include <TCollection_ExtendedString.hxx>
22 #include <Standard_Assert.hxx>
23 #include <Image_PixMap.hxx>
24
25
26 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture,OpenGl_Resource)
27
28 //! Simple class to reset unpack alignment settings
29 struct OpenGl_UnpackAlignmentSentry
30 {
31
32   //! Reset unpack alignment settings to safe values
33   void Reset()
34   {
35     glPixelStorei (GL_UNPACK_ALIGNMENT,  1);
36   #if !defined(GL_ES_VERSION_2_0)
37     glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
38   #endif
39   }
40
41   ~OpenGl_UnpackAlignmentSentry()
42   {
43     Reset();
44   }
45
46 };
47
48 // =======================================================================
49 // function : OpenGl_Texture
50 // purpose  :
51 // =======================================================================
52 OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams)
53 : OpenGl_Resource(),
54   myRevision (0),
55   myTextureId (NO_TEXTURE),
56   myTarget (GL_TEXTURE_2D),
57   mySizeX (0),
58   mySizeY (0),
59   mySizeZ (0),
60   myTextFormat (GL_RGBA),
61   myHasMipmaps (Standard_False),
62   myIsAlpha    (false),
63   myParams     (theParams)
64 {
65   if (myParams.IsNull())
66   {
67     myParams = new Graphic3d_TextureParams();
68   }
69 }
70
71 // =======================================================================
72 // function : ~OpenGl_Texture
73 // purpose  :
74 // =======================================================================
75 OpenGl_Texture::~OpenGl_Texture()
76 {
77   Release (NULL);
78 }
79
80 // =======================================================================
81 // function : HasMipmaps
82 // purpose  :
83 // =======================================================================
84 Standard_Boolean OpenGl_Texture::HasMipmaps() const
85 {
86   return myHasMipmaps;
87 }
88
89 // =======================================================================
90 // function : GetParams
91 // purpose  :
92 // =======================================================================
93 const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const
94 {
95   return myParams;
96 }
97
98 // =======================================================================
99 // function : SetParams
100 // purpose  :
101 // =======================================================================
102 void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams)
103 {
104   myParams = theParams;
105 }
106
107 // =======================================================================
108 // function : Create
109 // purpose  :
110 // =======================================================================
111 bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& )
112 {
113   if (myTextureId == NO_TEXTURE)
114   {
115     glGenTextures (1, &myTextureId);
116   }
117   return myTextureId != NO_TEXTURE;
118 }
119
120 // =======================================================================
121 // function : Release
122 // purpose  :
123 // =======================================================================
124 void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
125 {
126   if (myTextureId == NO_TEXTURE)
127   {
128     return;
129   }
130
131   // application can not handle this case by exception - this is bug in code
132   Standard_ASSERT_RETURN (theGlCtx != NULL,
133     "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
134
135   if (theGlCtx->IsValid())
136   {
137     glDeleteTextures (1, &myTextureId);
138   }
139   myTextureId = NO_TEXTURE;
140   mySizeX = mySizeY = mySizeZ = 0;
141 }
142
143 // =======================================================================
144 // function : Bind
145 // purpose  :
146 // =======================================================================
147 void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
148                            const GLenum theTextureUnit) const
149 {
150   if (theCtx->core15fwd != NULL)
151   {
152     theCtx->core15fwd->glActiveTexture (theTextureUnit);
153   }
154   glBindTexture (myTarget, myTextureId);
155 }
156
157 // =======================================================================
158 // function : Unbind
159 // purpose  :
160 // =======================================================================
161 void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
162                              const GLenum theTextureUnit) const
163 {
164   if (theCtx->core15fwd != NULL)
165   {
166     theCtx->core15fwd->glActiveTexture (theTextureUnit);
167   }
168   glBindTexture (myTarget, NO_TEXTURE);
169 }
170
171 //=======================================================================
172 //function : GetDataFormat
173 //purpose  :
174 //=======================================================================
175 bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx,
176                                     const Image_PixMap&           theData,
177                                     GLint&                        theTextFormat,
178                                     GLenum&                       thePixelFormat,
179                                     GLenum&                       theDataType)
180 {
181   theTextFormat  = GL_RGBA8;
182   thePixelFormat = 0;
183   theDataType    = 0;
184   switch (theData.Format())
185   {
186     case Image_Format_GrayF:
187     {
188       if (theCtx->core11 == NULL)
189       {
190         theTextFormat  = GL_R8;  // GL_R32F
191         thePixelFormat = GL_RED;
192       }
193       else
194       {
195         theTextFormat  = GL_LUMINANCE8;
196         thePixelFormat = GL_LUMINANCE;
197       }
198       theDataType = GL_FLOAT;
199       return true;
200     }
201     case Image_Format_AlphaF:
202     {
203       if (theCtx->core11 == NULL)
204       {
205         theTextFormat  = GL_R8;  // GL_R32F
206         thePixelFormat = GL_RED;
207       }
208       else
209       {
210         theTextFormat  = GL_ALPHA8;
211         thePixelFormat = GL_ALPHA;
212       }
213       theDataType = GL_FLOAT;
214       return true;
215     }
216     case Image_Format_RGBAF:
217     {
218       theTextFormat  = GL_RGBA8; // GL_RGBA32F
219       thePixelFormat = GL_RGBA;
220       theDataType    = GL_FLOAT;
221       return true;
222     }
223     case Image_Format_BGRAF:
224     {
225       if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
226       {
227         return false;
228       }
229       theTextFormat  = GL_RGBA8;    // GL_RGBA32F
230       thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
231       theDataType    = GL_FLOAT;
232       return true;
233     }
234     case Image_Format_RGBF:
235     {
236       theTextFormat  = GL_RGB8; // GL_RGB32F
237       thePixelFormat = GL_RGB;
238       theDataType    = GL_FLOAT;
239       return true;
240     }
241     case Image_Format_BGRF:
242     {
243     #if !defined(GL_ES_VERSION_2_0)
244       theTextFormat  = GL_RGB8; // GL_RGB32F
245       thePixelFormat = GL_BGR;  // equals to GL_BGR_EXT
246       theDataType    = GL_FLOAT;
247       return true;
248     #else
249       return false;
250     #endif
251     }
252     case Image_Format_RGBA:
253     {
254       theTextFormat = GL_RGBA8;
255       thePixelFormat = GL_RGBA;
256       theDataType    = GL_UNSIGNED_BYTE;
257       return true;
258     }
259     case Image_Format_BGRA:
260     {
261       if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
262       {
263         return false;
264       }
265       theTextFormat  = GL_RGBA8;
266       thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
267       theDataType    = GL_UNSIGNED_BYTE;
268       return true;
269     }
270     case Image_Format_RGB32:
271     {
272       theTextFormat = GL_RGB8;
273       thePixelFormat = GL_RGBA;
274       theDataType    = GL_UNSIGNED_BYTE;
275       return true;
276     }
277     case Image_Format_BGR32:
278     {
279       if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
280       {
281         return false;
282       }
283       theTextFormat  = GL_RGB8;
284       thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
285       theDataType    = GL_UNSIGNED_BYTE;
286       return true;
287     }
288     case Image_Format_RGB:
289     {
290       theTextFormat = GL_RGB8;
291       thePixelFormat = GL_RGB;
292       theDataType    = GL_UNSIGNED_BYTE;
293       return true;
294     }
295     case Image_Format_BGR:
296     {
297     #if !defined(GL_ES_VERSION_2_0)
298       if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
299       {
300         return false;
301       }
302       theTextFormat = GL_RGB8;
303       thePixelFormat = GL_BGR; // equals to GL_BGR_EXT
304       theDataType    = GL_UNSIGNED_BYTE;
305       return true;
306     #else
307       return false;
308     #endif
309     }
310     case Image_Format_Gray:
311     {
312       if (theCtx->core11 == NULL)
313       {
314         theTextFormat  = GL_R8;
315         thePixelFormat = GL_RED;
316       }
317       else
318       {
319         theTextFormat  = GL_LUMINANCE8;
320         thePixelFormat = GL_LUMINANCE;
321       }
322       theDataType = GL_UNSIGNED_BYTE;
323       return true;
324     }
325     case Image_Format_Alpha:
326     {
327       if (theCtx->core11 == NULL)
328       {
329         theTextFormat  = GL_R8;
330         thePixelFormat = GL_RED;
331       }
332       else
333       {
334         theTextFormat  = GL_ALPHA8;
335         thePixelFormat = GL_ALPHA;
336       }
337       theDataType = GL_UNSIGNED_BYTE;
338       return true;
339     }
340     case Image_Format_UNKNOWN:
341     {
342       return false;
343     }
344   }
345   return false;
346 }
347
348 // =======================================================================
349 // function : Init
350 // purpose  :
351 // =======================================================================
352 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
353                            const Standard_Integer        theTextFormat,
354                            const GLenum                  thePixelFormat,
355                            const GLenum                  theDataType,
356                            const Standard_Integer        theSizeX,
357                            const Standard_Integer        theSizeY,
358                            const Graphic3d_TypeOfTexture theType,
359                            const Image_PixMap*           theImage)
360 {
361 #if !defined(GL_ES_VERSION_2_0)
362   const GLenum aTarget = theType == Graphic3d_TOT_1D
363                        ? GL_TEXTURE_1D
364                        : GL_TEXTURE_2D;
365 #else
366   const GLenum aTarget = GL_TEXTURE_2D;
367 #endif
368   const Standard_Boolean toCreateMipMaps = (theType == Graphic3d_TOT_2D_MIPMAP);
369   const bool toPatchExisting = IsValid()
370                             && myTextFormat == thePixelFormat
371                             && myTarget == aTarget
372                             && myHasMipmaps == toCreateMipMaps
373                             && mySizeX  == theSizeX
374                             && (mySizeY == theSizeY || theType == Graphic3d_TOT_1D);
375   if (!Create (theCtx))
376   {
377     Release (theCtx.operator->());
378     return false;
379   }
380
381   if (theImage != NULL)
382   {
383     myIsAlpha = theImage->Format() == Image_Format_Alpha
384              || theImage->Format() == Image_Format_AlphaF;
385   }
386   else
387   {
388     myIsAlpha = thePixelFormat == GL_ALPHA;
389   }
390
391   myHasMipmaps             = toCreateMipMaps;
392   myTextFormat             = thePixelFormat;
393 #if !defined(GL_ES_VERSION_2_0)
394   const GLint anIntFormat  = theTextFormat;
395 #else
396   // ES does not support sized formats and format conversions - them detected from data type
397   const GLint anIntFormat  = thePixelFormat;
398   (void) theTextFormat;
399 #endif
400
401   const GLsizei aMaxSize = theCtx->MaxTextureSize();
402   if (theSizeX > aMaxSize
403    || theSizeY > aMaxSize)
404   {
405     TCollection_ExtendedString aWarnMessage = TCollection_ExtendedString ("Error: Texture dimension - ")
406       + theSizeX + "x" + theSizeY + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")";
407
408     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
409     Release (theCtx.operator->());
410     return false;
411   }
412 #if !defined(GL_ES_VERSION_2_0)
413   else if (!theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW)
414   {
415     // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
416     // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
417     // Trying to create NPOT textures on such hardware will not fail
418     // but driver will fall back into software rendering,
419     const GLsizei aWidthP2  = OpenGl_Context::GetPowerOfTwo (theSizeX, aMaxSize);
420     const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeY, aMaxSize);
421
422     if (theSizeX != aWidthP2
423      || (theType != Graphic3d_TOT_1D && theSizeY != aHeightP2))
424     {
425       TCollection_ExtendedString aWarnMessage =
426         TCollection_ExtendedString ("Error: NPOT Textures (") + theSizeX + "x" + theSizeY + ") are not supported by hardware.";
427
428       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
429
430       Release (theCtx.operator->());
431       return false;
432     }
433   }
434 #else
435   else if (!theCtx->IsGlGreaterEqual (3, 0) && theType == Graphic3d_TOT_2D_MIPMAP)
436   {
437     // Mipmap NPOT textures are not supported by OpenGL ES 2.0.
438     const GLsizei aWidthP2  = OpenGl_Context::GetPowerOfTwo (theSizeX, aMaxSize);
439     const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeY, aMaxSize);
440
441     if (theSizeX != aWidthP2
442      || theSizeY != aHeightP2)
443     {
444       TCollection_ExtendedString aWarnMessage =
445         TCollection_ExtendedString ("Error: Mipmap NPOT Textures (") + theSizeX + "x" + theSizeY + ") are not supported by OpenGL ES 2.0";
446
447       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
448
449       Release (theCtx.operator->());
450       return false;
451     }
452   }
453 #endif
454
455   const GLenum  aFilter   = (myParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR;
456   const GLenum  aWrapMode = myParams->IsRepeat() ? GL_REPEAT : theCtx->TextureWrapClamp();
457
458 #if !defined(GL_ES_VERSION_2_0)
459   GLint aTestWidth  = 0;
460   GLint aTestHeight = 0;
461 #endif
462   GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
463
464   // setup the alignment
465   OpenGl_UnpackAlignmentSentry anUnpackSentry;
466   (void)anUnpackSentry; // avoid compiler warning
467
468   if (aDataPtr != NULL)
469   {
470     const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
471     glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
472
473   #if !defined(GL_ES_VERSION_2_0)
474     // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
475     const GLint anExtraBytes = GLint(theImage->RowExtraBytes());
476     const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes());
477     glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
478   #endif
479   }
480
481   myTarget = aTarget;
482   switch (theType)
483   {
484     case Graphic3d_TOT_1D:
485     {
486     #if !defined(GL_ES_VERSION_2_0)
487       Bind (theCtx);
488       glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, aFilter);
489       glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, aFilter);
490       glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S,     aWrapMode);
491       if (toPatchExisting)
492       {
493         glTexSubImage1D (GL_TEXTURE_1D, 0, 0,
494                          theSizeX, thePixelFormat, theDataType, aDataPtr);
495         Unbind (theCtx);
496         return true;
497       }
498
499       // use proxy to check texture could be created or not
500       glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat,
501                     theSizeX, 0,
502                     thePixelFormat, theDataType, NULL);
503       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
504       if (aTestWidth == 0)
505       {
506         // no memory or broken input parameters
507         Unbind (theCtx);
508         Release (theCtx.operator->());
509         return false;
510       }
511
512       glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat,
513                     theSizeX, 0,
514                     thePixelFormat, theDataType, aDataPtr);
515       if (glGetError() != GL_NO_ERROR)
516       {
517         Unbind (theCtx);
518         Release (theCtx.operator->());
519         return false;
520       }
521
522       mySizeX = theSizeX;
523       mySizeY = 1;
524
525       Unbind (theCtx);
526       return true;
527     #else
528       Release (theCtx.operator->());
529       return false;
530     #endif
531     }
532     case Graphic3d_TOT_2D:
533     {
534       Bind (theCtx);
535       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, aFilter);
536       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilter);
537       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,     aWrapMode);
538       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,     aWrapMode);
539       if (toPatchExisting)
540       {
541         glTexSubImage2D (GL_TEXTURE_2D, 0,
542                          0, 0,
543                          theSizeX, theSizeY,
544                          thePixelFormat, theDataType, aDataPtr);
545         Unbind (theCtx);
546         return true;
547       }
548
549     #if !defined(GL_ES_VERSION_2_0)
550       // use proxy to check texture could be created or not
551       glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
552                     theSizeX, theSizeY, 0,
553                     thePixelFormat, theDataType, NULL);
554       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,  &aTestWidth);
555       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
556       if (aTestWidth == 0 || aTestHeight == 0)
557       {
558         // no memory or broken input parameters
559         Unbind (theCtx);
560         Release (theCtx.operator->());
561         return false;
562       }
563     #endif
564
565       glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
566                     theSizeX, theSizeY, 0,
567                     thePixelFormat, theDataType, aDataPtr);
568       if (glGetError() != GL_NO_ERROR)
569       {
570         Unbind (theCtx);
571         Release (theCtx.operator->());
572         return false;
573       }
574
575       mySizeX = theSizeX;
576       mySizeY = theSizeY;
577
578       Unbind (theCtx);
579       return true;
580     }
581     case Graphic3d_TOT_2D_MIPMAP:
582     {
583       GLenum aFilterMin = aFilter;
584       aFilterMin = GL_NEAREST_MIPMAP_NEAREST;
585       if (myParams->Filter() == Graphic3d_TOTF_BILINEAR)
586       {
587         aFilterMin = GL_LINEAR_MIPMAP_NEAREST;
588       }
589       else if (myParams->Filter() == Graphic3d_TOTF_TRILINEAR)
590       {
591         aFilterMin = GL_LINEAR_MIPMAP_LINEAR;
592       }
593
594       Bind (theCtx);
595       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, aFilterMin);
596       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilter);
597       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,     aWrapMode);
598       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,     aWrapMode);
599       if (toPatchExisting)
600       {
601         glTexSubImage2D (GL_TEXTURE_2D, 0,
602                          0, 0,
603                          theSizeX, theSizeY,
604                          thePixelFormat, theDataType, aDataPtr);
605         if (theCtx->arbFBO != NULL)
606         {
607           // generate mipmaps
608           theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
609           if (glGetError() != GL_NO_ERROR)
610           {
611             Unbind (theCtx);
612             Release (theCtx.operator->());
613             return false;
614           }
615         }
616
617         Unbind (theCtx);
618         return true;
619       }
620
621     #if !defined(GL_ES_VERSION_2_0)
622       // use proxy to check texture could be created or not
623       glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
624                     theSizeX, theSizeY, 0,
625                     thePixelFormat, theDataType, NULL);
626       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,  &aTestWidth);
627       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
628       if (aTestWidth == 0 || aTestHeight == 0)
629       {
630         // no memory or broken input parameters
631         Unbind (theCtx);
632         Release (theCtx.operator->());
633         return false;
634       }
635     #endif
636
637       // upload main picture
638       glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
639                     theSizeX, theSizeY, 0,
640                     thePixelFormat, theDataType, theImage->Data());
641       if (glGetError() != GL_NO_ERROR)
642       {
643         Unbind (theCtx);
644         Release (theCtx.operator->());
645         return false;
646       }
647
648       mySizeX = theSizeX;
649       mySizeY = theSizeY;
650
651       if (theCtx->arbFBO != NULL)
652       {
653         // generate mipmaps
654         //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
655         theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
656
657         if (glGetError() != GL_NO_ERROR)
658         {
659           Unbind (theCtx);
660           Release (theCtx.operator->());
661           return false;
662         }
663       }
664       else
665       {
666         const TCollection_ExtendedString aWarnMessage ("Warning: generating mipmaps requires GL_ARB_framebuffer_object extension which is missing.");
667
668         theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, aWarnMessage);
669
670         Unbind (theCtx);
671         Release (theCtx.operator->());
672         return false;
673       }
674
675       Unbind (theCtx);
676       return true;
677     }
678   }
679
680   Release (theCtx.operator->());
681   return false;
682 }
683
684 // =======================================================================
685 // function : Init
686 // purpose  :
687 // =======================================================================
688 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
689                            const Image_PixMap&           theImage,
690                            const Graphic3d_TypeOfTexture theType)
691 {
692   if (theImage.IsEmpty())
693   {
694     Release (theCtx.operator->());
695     return false;
696   }
697
698   GLenum aPixelFormat;
699   GLenum aDataType;
700   GLint aTextFormat;
701   if (!GetDataFormat (theCtx, theImage, aTextFormat, aPixelFormat, aDataType))
702   {
703     Release (theCtx.operator->());
704     return false;
705   }
706
707   return Init (theCtx,
708                aTextFormat, aPixelFormat, aDataType,
709                (Standard_Integer)theImage.SizeX(),
710                (Standard_Integer)theImage.SizeY(),
711                theType, &theImage);
712 }
713
714 // =======================================================================
715 // function : Init2DMultisample
716 // purpose  :
717 // =======================================================================
718 bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
719                                         const GLsizei                 theNbSamples,
720                                         const GLint                   theTextFormat,
721                                         const GLsizei                 theSizeX,
722                                         const GLsizei                 theSizeY)
723 {
724   if (!Create (theCtx)
725     || theNbSamples > theCtx->MaxMsaaSamples()
726     || theNbSamples < 1)
727   {
728     return false;
729   }
730
731   const GLsizei aNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
732   myTarget = GL_TEXTURE_2D_MULTISAMPLE;
733   if(theSizeX > theCtx->MaxTextureSize()
734   || theSizeY > theCtx->MaxTextureSize())
735   {
736     return false;
737   }
738
739   Bind (theCtx);
740   //myTextFormat = theTextFormat;
741 #if !defined(GL_ES_VERSION_2_0)
742   if (theCtx->Functions()->glTexStorage2DMultisample != NULL)
743   {
744     theCtx->Functions()->glTexStorage2DMultisample (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
745   }
746   else
747   {
748     theCtx->Functions()->glTexImage2DMultisample   (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
749   }
750 #else
751   theCtx->Functions()  ->glTexStorage2DMultisample (myTarget, aNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
752 #endif
753   if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
754   {
755     Unbind (theCtx);
756     return false;
757   }
758
759   mySizeX = theSizeX;
760   mySizeY = theSizeY;
761
762   Unbind (theCtx);
763   return true;
764 }
765
766 // =======================================================================
767 // function : InitRectangle
768 // purpose  :
769 // =======================================================================
770 bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
771                                     const Standard_Integer        theSizeX,
772                                     const Standard_Integer        theSizeY,
773                                     const OpenGl_TextureFormat&   theFormat)
774 {
775   if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
776   {
777     return false;
778   }
779
780 #if !defined(GL_ES_VERSION_2_0)
781   myTarget = GL_TEXTURE_RECTANGLE;
782
783   const GLsizei aSizeX    = Min (theCtx->MaxTextureSize(), theSizeX);
784   const GLsizei aSizeY    = Min (theCtx->MaxTextureSize(), theSizeY);
785   const GLenum  aFilter   = (myParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR;
786   const GLenum  aWrapMode = myParams->IsRepeat() ? GL_REPEAT : theCtx->TextureWrapClamp();
787
788   Bind (theCtx);
789   glTexParameteri (myTarget, GL_TEXTURE_MIN_FILTER, aFilter);
790   glTexParameteri (myTarget, GL_TEXTURE_MAG_FILTER, aFilter);
791   glTexParameteri (myTarget, GL_TEXTURE_WRAP_S,     aWrapMode);
792   glTexParameteri (myTarget, GL_TEXTURE_WRAP_T,     aWrapMode);
793
794   const GLint anIntFormat = theFormat.Internal();
795   myTextFormat = theFormat.Format();
796
797   glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE,
798                 0,
799                 anIntFormat,
800                 aSizeX,
801                 aSizeY,
802                 0,
803                 theFormat.Format(),
804                 GL_FLOAT,
805                 NULL);
806
807   GLint aTestSizeX = 0;
808   GLint aTestSizeY = 0;
809
810   glGetTexLevelParameteriv (
811     GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH,  &aTestSizeX);
812   glGetTexLevelParameteriv (
813     GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
814
815   if (aTestSizeX == 0 || aTestSizeY == 0)
816   {
817     Unbind (theCtx);
818     return false;
819   }
820
821   glTexImage2D (myTarget,
822                 0,
823                 anIntFormat,
824                 aSizeX,
825                 aSizeY,
826                 0,
827                 theFormat.Format(),
828                 GL_FLOAT,
829                 NULL);
830
831   if (glGetError() != GL_NO_ERROR)
832   {
833     Unbind (theCtx);
834     return false;
835   }
836
837   mySizeX = aSizeX;
838   mySizeY = aSizeY;
839
840   Unbind (theCtx);
841   return true;
842 #else
843   (void )theSizeX;
844   (void )theSizeY;
845   (void )theFormat;
846   return false;
847 #endif
848 }
849
850 // =======================================================================
851 // function : Init3D
852 // purpose  :
853 // =======================================================================
854 bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
855                              const GLint                   theTextFormat,
856                              const GLenum                  thePixelFormat,
857                              const GLenum                  theDataType,
858                              const Standard_Integer        theSizeX,
859                              const Standard_Integer        theSizeY,
860                              const Standard_Integer        theSizeZ,
861                              const void*                   thePixels)
862 {
863   if (theCtx->Functions()->glTexImage3D == NULL)
864   {
865     TCollection_ExtendedString aMsg ("Error: three-dimensional textures are not supported by hardware.");
866
867     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
868                          GL_DEBUG_TYPE_ERROR,
869                          0,
870                          GL_DEBUG_SEVERITY_HIGH,
871                          aMsg);
872
873     return false;
874   }
875
876   if (!Create(theCtx))
877   {
878     return false;
879   }
880
881   myTarget = GL_TEXTURE_3D;
882
883   const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
884   const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
885   const GLsizei aSizeZ = Min (theCtx->MaxTextureSize(), theSizeZ);
886
887   Bind (theCtx);
888
889   if (theDataType == GL_FLOAT && !theCtx->arbTexFloat)
890   {
891     TCollection_ExtendedString aMsg ("Error: floating-point textures are not supported by hardware.");
892
893     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
894                          GL_DEBUG_TYPE_ERROR,
895                          0,
896                          GL_DEBUG_SEVERITY_HIGH,
897                          aMsg);
898
899     Release (theCtx.operator->());
900     Unbind (theCtx);
901     return false;
902   }
903
904   const GLint anIntFormat = theTextFormat;
905
906 #if !defined (GL_ES_VERSION_2_0)
907   theCtx->core15fwd->glTexImage3D (GL_PROXY_TEXTURE_3D,
908                                    0,
909                                    anIntFormat,
910                                    aSizeX,
911                                    aSizeY,
912                                    aSizeZ,
913                                    0,
914                                    thePixelFormat,
915                                    theDataType,
916                                    NULL);
917
918   GLint aTestSizeX = 0;
919   GLint aTestSizeY = 0;
920   GLint aTestSizeZ = 0;
921
922   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
923   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
924   glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &aTestSizeZ);
925
926   if (aTestSizeX == 0 || aTestSizeY == 0 || aTestSizeZ == 0)
927   {
928     Unbind (theCtx);
929     Release (theCtx.operator->());
930     return false;
931   }
932 #endif
933
934   const GLenum aWrapMode = myParams->IsRepeat() ? GL_REPEAT :  theCtx->TextureWrapClamp();
935   const GLenum aFilter   = (myParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR;
936
937   glTexParameteri (myTarget, GL_TEXTURE_WRAP_S, aWrapMode);
938   glTexParameteri (myTarget, GL_TEXTURE_WRAP_T, aWrapMode);
939   glTexParameteri (myTarget, GL_TEXTURE_WRAP_R, aWrapMode);
940
941   glTexParameteri (myTarget, GL_TEXTURE_MIN_FILTER, aFilter);
942   glTexParameteri (myTarget, GL_TEXTURE_MAG_FILTER, aFilter);
943
944   theCtx->Functions()->glTexImage3D (myTarget,
945                                      0,
946                                      anIntFormat,
947                                      aSizeX,
948                                      aSizeY,
949                                      aSizeZ,
950                                      0,
951                                      thePixelFormat,
952                                      theDataType,
953                                      thePixels);
954
955   if (glGetError() != GL_NO_ERROR)
956   {
957     Unbind (theCtx);
958     Release (theCtx.operator->());
959     return false;
960   }
961
962   mySizeX = aSizeX;
963   mySizeY = aSizeY;
964   mySizeZ = aSizeZ;
965
966   Unbind (theCtx);
967   return true;
968 }