0f08435216fde2f4aa2e6e6dcf4df28be4263274
[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_GlCore15.hxx>
20 #include <Graphic3d_TextureParams.hxx>
21 #include <Standard_Assert.hxx>
22 #include <Image_PixMap.hxx>
23
24
25 //! Simple class to reset unpack alignment settings
26 struct OpenGl_UnpackAlignmentSentry
27 {
28
29   //! Reset unpack alignment settings to safe values
30   void Reset()
31   {
32     glPixelStorei (GL_UNPACK_ALIGNMENT,  1);
33   #if !defined(GL_ES_VERSION_2_0)
34     glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
35   #endif
36   }
37
38   ~OpenGl_UnpackAlignmentSentry()
39   {
40     Reset();
41   }
42
43 };
44
45 // =======================================================================
46 // function : OpenGl_Texture
47 // purpose  :
48 // =======================================================================
49 OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams)
50 : OpenGl_Resource(),
51   myTextureId (NO_TEXTURE),
52   myTarget (GL_TEXTURE_2D),
53   mySizeX (0),
54   mySizeY (0),
55   myTextFormat (GL_RGBA),
56   myHasMipmaps (Standard_False),
57   myIsAlpha    (false),
58   myParams     (theParams)
59 {
60   if (myParams.IsNull())
61   {
62     myParams = new Graphic3d_TextureParams();
63   }
64 }
65
66 // =======================================================================
67 // function : ~OpenGl_Texture
68 // purpose  :
69 // =======================================================================
70 OpenGl_Texture::~OpenGl_Texture()
71 {
72   Release (NULL);
73 }
74
75 // =======================================================================
76 // function : HasMipmaps
77 // purpose  :
78 // =======================================================================
79 const Standard_Boolean OpenGl_Texture::HasMipmaps() const
80 {
81   return myHasMipmaps;
82 }
83
84 // =======================================================================
85 // function : GetParams
86 // purpose  :
87 // =======================================================================
88 const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const
89 {
90   return myParams;
91 }
92
93 // =======================================================================
94 // function : SetParams
95 // purpose  :
96 // =======================================================================
97 void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams)
98 {
99   myParams = theParams;
100 }
101
102 // =======================================================================
103 // function : Create
104 // purpose  :
105 // =======================================================================
106 bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& )
107 {
108   if (myTextureId == NO_TEXTURE)
109   {
110     glGenTextures (1, &myTextureId);
111   }
112   return myTextureId != NO_TEXTURE;
113 }
114
115 // =======================================================================
116 // function : Release
117 // purpose  :
118 // =======================================================================
119 void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
120 {
121   if (myTextureId == NO_TEXTURE)
122   {
123     return;
124   }
125
126   // application can not handle this case by exception - this is bug in code
127   Standard_ASSERT_RETURN (theGlCtx != NULL,
128     "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
129
130   if (theGlCtx->IsValid())
131   {
132     glDeleteTextures (1, &myTextureId);
133   }
134   myTextureId = NO_TEXTURE;
135   mySizeX = mySizeY = 0;
136 }
137
138 // =======================================================================
139 // function : Bind
140 // purpose  :
141 // =======================================================================
142 void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
143                            const GLenum theTextureUnit) const
144 {
145   if (theCtx->core15fwd != NULL)
146   {
147     theCtx->core15fwd->glActiveTexture (theTextureUnit);
148   }
149   glBindTexture (myTarget, myTextureId);
150 }
151
152 // =======================================================================
153 // function : Unbind
154 // purpose  :
155 // =======================================================================
156 void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
157                              const GLenum theTextureUnit) const
158 {
159   if (theCtx->core15fwd != NULL)
160   {
161     theCtx->core15fwd->glActiveTexture (theTextureUnit);
162   }
163   glBindTexture (myTarget, NO_TEXTURE);
164 }
165
166 //=======================================================================
167 //function : GetDataFormat
168 //purpose  :
169 //=======================================================================
170 bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx,
171                                     const Image_PixMap&           theData,
172                                     GLint&                        theTextFormat,
173                                     GLenum&                       thePixelFormat,
174                                     GLenum&                       theDataType)
175 {
176   theTextFormat  = GL_RGBA8;
177   thePixelFormat = 0;
178   theDataType    = 0;
179   switch (theData.Format())
180   {
181     case Image_PixMap::ImgGrayF:
182     {
183       if (theCtx->core11 == NULL)
184       {
185         theTextFormat  = GL_R8;  // GL_R32F
186         thePixelFormat = GL_RED;
187       }
188       else
189       {
190         theTextFormat  = GL_LUMINANCE8;
191         thePixelFormat = GL_LUMINANCE;
192       }
193       theDataType = GL_FLOAT;
194       return true;
195     }
196     case Image_PixMap::ImgAlphaF:
197     {
198       if (theCtx->core11 == NULL)
199       {
200         theTextFormat  = GL_R8;  // GL_R32F
201         thePixelFormat = GL_RED;
202       }
203       else
204       {
205         theTextFormat  = GL_ALPHA8;
206         thePixelFormat = GL_ALPHA;
207       }
208       theDataType = GL_FLOAT;
209       return true;
210     }
211     case Image_PixMap::ImgRGBAF:
212     {
213       theTextFormat  = GL_RGBA8; // GL_RGBA32F
214       thePixelFormat = GL_RGBA;
215       theDataType    = GL_FLOAT;
216       return true;
217     }
218     case Image_PixMap::ImgBGRAF:
219     {
220       if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
221       {
222         return false;
223       }
224       theTextFormat  = GL_RGBA8;    // GL_RGBA32F
225       thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
226       theDataType    = GL_FLOAT;
227       return true;
228     }
229     case Image_PixMap::ImgRGBF:
230     {
231       theTextFormat  = GL_RGB8; // GL_RGB32F
232       thePixelFormat = GL_RGB;
233       theDataType    = GL_FLOAT;
234       return true;
235     }
236     case Image_PixMap::ImgBGRF:
237     {
238     #if !defined(GL_ES_VERSION_2_0)
239       theTextFormat  = GL_RGB8; // GL_RGB32F
240       thePixelFormat = GL_BGR;  // equals to GL_BGR_EXT
241       theDataType    = GL_FLOAT;
242       return true;
243     #else
244       return false;
245     #endif
246     }
247     case Image_PixMap::ImgRGBA:
248     {
249       theTextFormat = GL_RGBA8;
250       thePixelFormat = GL_RGBA;
251       theDataType    = GL_UNSIGNED_BYTE;
252       return true;
253     }
254     case Image_PixMap::ImgBGRA:
255     {
256       if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
257       {
258         return false;
259       }
260       theTextFormat  = GL_RGBA8;
261       thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
262       theDataType    = GL_UNSIGNED_BYTE;
263       return true;
264     }
265     case Image_PixMap::ImgRGB32:
266     {
267       theTextFormat = GL_RGB8;
268       thePixelFormat = GL_RGBA;
269       theDataType    = GL_UNSIGNED_BYTE;
270       return true;
271     }
272     case Image_PixMap::ImgBGR32:
273     {
274       if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
275       {
276         return false;
277       }
278       theTextFormat  = GL_RGB8;
279       thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
280       theDataType    = GL_UNSIGNED_BYTE;
281       return true;
282     }
283     case Image_PixMap::ImgRGB:
284     {
285       theTextFormat = GL_RGB8;
286       thePixelFormat = GL_RGB;
287       theDataType    = GL_UNSIGNED_BYTE;
288       return true;
289     }
290     case Image_PixMap::ImgBGR:
291     {
292     #if !defined(GL_ES_VERSION_2_0)
293       if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
294       {
295         return false;
296       }
297       theTextFormat = GL_RGB8;
298       thePixelFormat = GL_BGR; // equals to GL_BGR_EXT
299       theDataType    = GL_UNSIGNED_BYTE;
300       return true;
301     #else
302       return false;
303     #endif
304     }
305     case Image_PixMap::ImgGray:
306     {
307       if (theCtx->core11 == NULL)
308       {
309         theTextFormat  = GL_R8;
310         thePixelFormat = GL_RED;
311       }
312       else
313       {
314         theTextFormat  = GL_LUMINANCE8;
315         thePixelFormat = GL_LUMINANCE;
316       }
317       theDataType = GL_UNSIGNED_BYTE;
318       return true;
319     }
320     case Image_PixMap::ImgAlpha:
321     {
322       if (theCtx->core11 == NULL)
323       {
324         theTextFormat  = GL_R8;
325         thePixelFormat = GL_RED;
326       }
327       else
328       {
329         theTextFormat  = GL_ALPHA8;
330         thePixelFormat = GL_ALPHA;
331       }
332       theDataType = GL_UNSIGNED_BYTE;
333       return true;
334     }
335     case Image_PixMap::ImgUNKNOWN:
336     {
337       return false;
338     }
339   }
340   return false;
341 }
342
343 // =======================================================================
344 // function : Init
345 // purpose  :
346 // =======================================================================
347 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
348                            const Standard_Integer        theTextFormat,
349                            const GLenum                  thePixelFormat,
350                            const GLenum                  theDataType,
351                            const Standard_Integer        theSizeX,
352                            const Standard_Integer        theSizeY,
353                            const Graphic3d_TypeOfTexture theType,
354                            const Image_PixMap*           theImage)
355 {
356   if (!Create (theCtx))
357   {
358     Release (theCtx.operator->());
359     return false;
360   }
361
362   if (theImage != NULL)
363   {
364     myIsAlpha = theImage->Format() == Image_PixMap::ImgAlpha
365              || theImage->Format() == Image_PixMap::ImgAlphaF;
366   }
367   else
368   {
369     myIsAlpha = thePixelFormat == GL_ALPHA;
370   }
371
372   myHasMipmaps             = Standard_False;
373   myTextFormat             = thePixelFormat;
374 #if !defined(GL_ES_VERSION_2_0)
375   const GLint anIntFormat  = theTextFormat;
376 #else
377   // ES does not support sized formats and format conversions - them detected from data type
378   const GLint anIntFormat  = thePixelFormat;
379 #endif
380   const GLsizei aWidth     = theSizeX;
381   const GLsizei aHeight    = theSizeY;
382   const GLsizei aMaxSize   = theCtx->MaxTextureSize();
383
384   // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
385   // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
386   // Trying to create NPOT textures on such hardware will not fail
387   // but driver will fall back into software rendering,
388   const bool    toForceP2  = !theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW;
389   const GLsizei aWidthOut  = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aWidth,  aMaxSize) : Min (aWidth,  aMaxSize);
390   const GLsizei aHeightOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aHeight, aMaxSize) : Min (aHeight, aMaxSize);
391   const GLenum  aFilter    = (myParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR;
392   const GLenum  aWrapMode  = myParams->IsRepeat() ? GL_REPEAT : theCtx->TextureWrapClamp();
393
394 #if !defined(GL_ES_VERSION_2_0)
395   GLint aTestWidth  = 0;
396   GLint aTestHeight = 0;
397 #endif
398   GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
399
400   // setup the alignment
401   OpenGl_UnpackAlignmentSentry anUnpackSentry;
402   if (aDataPtr != NULL)
403   {
404     const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
405     glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
406
407   #if !defined(GL_ES_VERSION_2_0)
408     // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
409     const GLint anExtraBytes = GLint(theImage->RowExtraBytes());
410     const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes());
411     glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
412   #endif
413   }
414
415   switch (theType)
416   {
417     case Graphic3d_TOT_1D:
418     {
419     #if !defined(GL_ES_VERSION_2_0)
420       myTarget = GL_TEXTURE_1D;
421       Bind (theCtx);
422       glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, aFilter);
423       glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, aFilter);
424       glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S,     aWrapMode);
425
426       Image_PixMap aCopy;
427       if (aDataPtr != NULL)
428       {
429         if (aWidth != aWidthOut)
430         {
431           glPixelStorei (GL_PACK_ALIGNMENT,  1);
432           glPixelStorei (GL_PACK_ROW_LENGTH, 0);
433           if (!aCopy.InitTrash (theImage->Format(), Standard_Size(aWidthOut), 1)
434             || gluScaleImage (thePixelFormat,
435                               aWidth,    1, theDataType, theImage->Data(),
436                               aWidthOut, 1, theDataType, aCopy.ChangeData()) != 0)
437           {
438             Unbind (theCtx);
439             Release (theCtx.operator->());
440             return false;
441           }
442
443           aDataPtr = (GLvoid* )aCopy.Data();
444           anUnpackSentry.Reset();
445         }
446       }
447
448       // use proxy to check texture could be created or not
449       glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat,
450                     aWidthOut, 0,
451                     thePixelFormat, theDataType, NULL);
452       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
453       if (aTestWidth == 0)
454       {
455         // no memory or broken input parameters
456         Unbind (theCtx);
457         Release (theCtx.operator->());
458         return false;
459       }
460
461       glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat,
462                     aWidthOut, 0,
463                     thePixelFormat, theDataType, aDataPtr);
464       if (glGetError() != GL_NO_ERROR)
465       {
466         Unbind (theCtx);
467         Release (theCtx.operator->());
468         return false;
469       }
470
471       mySizeX = aWidthOut;
472       mySizeY = 1;
473
474       Unbind (theCtx);
475       return true;
476     #else
477       return false;
478     #endif
479     }
480     case Graphic3d_TOT_2D:
481     {
482       myTarget = GL_TEXTURE_2D;
483       Bind (theCtx);
484       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, aFilter);
485       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilter);
486       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,     aWrapMode);
487       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,     aWrapMode);
488
489       Image_PixMap aCopy;
490       if (aDataPtr != NULL)
491       {
492         if (aWidth != aWidthOut || aHeight != aHeightOut)
493         {
494         #if !defined(GL_ES_VERSION_2_0)
495           // scale texture
496           glPixelStorei (GL_PACK_ALIGNMENT,  1);
497           glPixelStorei (GL_PACK_ROW_LENGTH, 0);
498           if (!aCopy.InitTrash (theImage->Format(), Standard_Size(aWidthOut), Standard_Size(aHeightOut))
499             || gluScaleImage (thePixelFormat,
500                               aWidth,    aHeight,    theDataType, theImage->Data(),
501                               aWidthOut, aHeightOut, theDataType, aCopy.ChangeData()) != 0)
502           {
503             Unbind (theCtx);
504             Release (theCtx.operator->());
505             return false;
506           }
507
508           aDataPtr = (GLvoid* )aCopy.Data();
509           anUnpackSentry.Reset();
510         #else
511           Unbind (theCtx);
512           Release (theCtx.operator->());
513           return false;
514         #endif
515         }
516       }
517
518     #if !defined(GL_ES_VERSION_2_0)
519       // use proxy to check texture could be created or not
520       glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
521                     aWidthOut, aHeightOut, 0,
522                     thePixelFormat, theDataType, NULL);
523       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,  &aTestWidth);
524       glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
525       if (aTestWidth == 0 || aTestHeight == 0)
526       {
527         // no memory or broken input parameters
528         Unbind (theCtx);
529         Release (theCtx.operator->());
530         return false;
531       }
532     #endif
533
534       glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
535                     aWidthOut, aHeightOut, 0,
536                     thePixelFormat, theDataType, aDataPtr);
537       if (glGetError() != GL_NO_ERROR)
538       {
539         Unbind (theCtx);
540         Release (theCtx.operator->());
541         return false;
542       }
543
544       mySizeX = aWidthOut;
545       mySizeY = aHeightOut;
546
547       Unbind (theCtx);
548       return true;
549     }
550     case Graphic3d_TOT_2D_MIPMAP:
551     {
552       myTarget     = GL_TEXTURE_2D;
553       myHasMipmaps = Standard_True;
554
555       GLenum aFilterMin = aFilter;
556       aFilterMin = GL_NEAREST_MIPMAP_NEAREST;
557       if (myParams->Filter() == Graphic3d_TOTF_BILINEAR)
558       {
559         aFilterMin = GL_LINEAR_MIPMAP_NEAREST;
560       }
561       else if (myParams->Filter() == Graphic3d_TOTF_TRILINEAR)
562       {
563         aFilterMin = GL_LINEAR_MIPMAP_LINEAR;
564       }
565
566       Bind (theCtx);
567       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, aFilterMin);
568       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, aFilter);
569       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,     aWrapMode);
570       glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,     aWrapMode);
571
572       if (theCtx->arbFBO != NULL
573        && aWidth == aWidthOut && aHeight == aHeightOut)
574       {
575       #if !defined(GL_ES_VERSION_2_0)
576         // use proxy to check texture could be created or not
577         glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
578                       aWidthOut, aHeightOut, 0,
579                       thePixelFormat, theDataType, NULL);
580         glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,  &aTestWidth);
581         glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
582         if (aTestWidth == 0 || aTestHeight == 0)
583         {
584           // no memory or broken input parameters
585           Unbind (theCtx);
586           Release (theCtx.operator->());
587           return false;
588         }
589       #endif
590
591         // upload main picture
592         glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
593                       aWidthOut, aHeightOut, 0,
594                       thePixelFormat, theDataType, theImage->Data());
595         if (glGetError() != GL_NO_ERROR)
596         {
597           Unbind (theCtx);
598           Release (theCtx.operator->());
599           return false;
600         }
601
602         mySizeX = aWidthOut;
603         mySizeY = aHeightOut;
604
605         // generate mipmaps
606         //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
607         theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
608
609         Unbind (theCtx);
610         return true;
611       }
612       else
613       {
614       #if !defined(GL_ES_VERSION_2_0)
615         bool isCreated = gluBuild2DMipmaps (GL_TEXTURE_2D, anIntFormat,
616                                             aWidth, aHeight,
617                                             thePixelFormat, theDataType, theImage->Data()) == 0;
618         if (isCreated)
619         {
620           glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH,  &mySizeX);
621           glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &mySizeY);
622         }
623
624         Unbind (theCtx);
625         return isCreated;
626       #else
627         Unbind (theCtx);
628         return false;
629       #endif
630       }
631     }
632     default:
633     {
634       Release (theCtx.operator->());
635       return false;
636     }
637   }
638 }
639
640 // =======================================================================
641 // function : Init
642 // purpose  :
643 // =======================================================================
644 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
645                            const Image_PixMap&           theImage,
646                            const Graphic3d_TypeOfTexture theType)
647 {
648   if (theImage.IsEmpty())
649   {
650     Release (theCtx.operator->());
651     return false;
652   }
653
654   GLenum aPixelFormat;
655   GLenum aDataType;
656   GLint aTextFormat;
657   if (!GetDataFormat (theCtx, theImage, aTextFormat, aPixelFormat, aDataType))
658   {
659     Release (theCtx.operator->());
660     return false;
661   }
662
663   return Init (theCtx,
664                aTextFormat, aPixelFormat, aDataType,
665                (Standard_Integer)theImage.SizeX(),
666                (Standard_Integer)theImage.SizeY(),
667                theType, &theImage);
668 }
669
670 // =======================================================================
671 // function : InitRectangle
672 // purpose  :
673 // =======================================================================
674 bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
675                                     const Standard_Integer        theSizeX,
676                                     const Standard_Integer        theSizeY,
677                                     const OpenGl_TextureFormat&   theFormat)
678 {
679   if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
680   {
681     return false;
682   }
683
684 #if !defined(GL_ES_VERSION_2_0)
685   myTarget = GL_TEXTURE_RECTANGLE;
686
687   const GLsizei aSizeX    = Min (theCtx->MaxTextureSize(), theSizeX);
688   const GLsizei aSizeY    = Min (theCtx->MaxTextureSize(), theSizeY);
689   const GLenum  aFilter   = (myParams->Filter() == Graphic3d_TOTF_NEAREST) ? GL_NEAREST : GL_LINEAR;
690   const GLenum  aWrapMode = myParams->IsRepeat() ? GL_REPEAT : theCtx->TextureWrapClamp();
691
692   Bind (theCtx);
693   glTexParameteri (myTarget, GL_TEXTURE_MIN_FILTER, aFilter);
694   glTexParameteri (myTarget, GL_TEXTURE_MAG_FILTER, aFilter);
695   glTexParameteri (myTarget, GL_TEXTURE_WRAP_S,     aWrapMode);
696   glTexParameteri (myTarget, GL_TEXTURE_WRAP_T,     aWrapMode);
697
698   const GLint anIntFormat = theFormat.Internal();
699   myTextFormat = theFormat.Format();
700
701   glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE,
702                 0,
703                 anIntFormat,
704                 aSizeX,
705                 aSizeY,
706                 0,
707                 theFormat.Format(),
708                 GL_FLOAT,
709                 NULL);
710
711   GLint aTestSizeX = 0;
712   GLint aTestSizeY = 0;
713
714   glGetTexLevelParameteriv (
715     GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH,  &aTestSizeX);
716   glGetTexLevelParameteriv (
717     GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
718
719   if (aTestSizeX == 0 || aTestSizeY == 0)
720   {
721     Unbind (theCtx);
722     return false;
723   }
724
725   glTexImage2D (myTarget,
726                 0,
727                 anIntFormat,
728                 aSizeX,
729                 aSizeY,
730                 0,
731                 theFormat.Format(),
732                 GL_FLOAT,
733                 NULL);
734
735   if (glGetError() != GL_NO_ERROR)
736   {
737     Unbind (theCtx);
738     return false;
739   }
740
741   mySizeX = aSizeX;
742   mySizeY = aSizeY;
743
744   Unbind (theCtx);
745   return true;
746 #else
747   return false;
748 #endif
749 }