1 // Created by: Kirill GAVRILOV
2 // Copyright (c) 2013-2014 OPEN CASCADE SAS
4 // This file is part of Open CASCADE Technology software library.
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.
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
15 #include <OpenGl_Texture.hxx>
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>
25 //! Simple class to reset unpack alignment settings
26 struct OpenGl_UnpackAlignmentSentry
29 //! Reset unpack alignment settings to safe values
32 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
33 #if !defined(GL_ES_VERSION_2_0)
34 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
38 ~OpenGl_UnpackAlignmentSentry()
45 // =======================================================================
46 // function : OpenGl_Texture
48 // =======================================================================
49 OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams)
51 myTextureId (NO_TEXTURE),
52 myTarget (GL_TEXTURE_2D),
55 myTextFormat (GL_RGBA),
56 myHasMipmaps (Standard_False),
60 if (myParams.IsNull())
62 myParams = new Graphic3d_TextureParams();
66 // =======================================================================
67 // function : ~OpenGl_Texture
69 // =======================================================================
70 OpenGl_Texture::~OpenGl_Texture()
75 // =======================================================================
76 // function : HasMipmaps
78 // =======================================================================
79 const Standard_Boolean OpenGl_Texture::HasMipmaps() const
84 // =======================================================================
85 // function : GetParams
87 // =======================================================================
88 const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const
93 // =======================================================================
94 // function : SetParams
96 // =======================================================================
97 void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams)
102 // =======================================================================
105 // =======================================================================
106 bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& )
108 if (myTextureId == NO_TEXTURE)
110 glGenTextures (1, &myTextureId);
112 return myTextureId != NO_TEXTURE;
115 // =======================================================================
116 // function : Release
118 // =======================================================================
119 void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
121 if (myTextureId == NO_TEXTURE)
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...",);
130 if (theGlCtx->IsValid())
132 glDeleteTextures (1, &myTextureId);
134 myTextureId = NO_TEXTURE;
135 mySizeX = mySizeY = 0;
138 // =======================================================================
141 // =======================================================================
142 void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
143 const GLenum theTextureUnit) const
145 if (theCtx->core15fwd != NULL)
147 theCtx->core15fwd->glActiveTexture (theTextureUnit);
149 glBindTexture (myTarget, myTextureId);
152 // =======================================================================
155 // =======================================================================
156 void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
157 const GLenum theTextureUnit) const
159 if (theCtx->core15fwd != NULL)
161 theCtx->core15fwd->glActiveTexture (theTextureUnit);
163 glBindTexture (myTarget, NO_TEXTURE);
166 //=======================================================================
167 //function : GetDataFormat
169 //=======================================================================
170 bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx,
171 const Image_PixMap& theData,
172 GLint& theTextFormat,
173 GLenum& thePixelFormat,
176 theTextFormat = GL_RGBA8;
179 switch (theData.Format())
181 case Image_PixMap::ImgGrayF:
183 if (theCtx->core11 == NULL)
185 theTextFormat = GL_R8; // GL_R32F
186 thePixelFormat = GL_RED;
190 theTextFormat = GL_LUMINANCE8;
191 thePixelFormat = GL_LUMINANCE;
193 theDataType = GL_FLOAT;
196 case Image_PixMap::ImgAlphaF:
198 if (theCtx->core11 == NULL)
200 theTextFormat = GL_R8; // GL_R32F
201 thePixelFormat = GL_RED;
205 theTextFormat = GL_ALPHA8;
206 thePixelFormat = GL_ALPHA;
208 theDataType = GL_FLOAT;
211 case Image_PixMap::ImgRGBAF:
213 theTextFormat = GL_RGBA8; // GL_RGBA32F
214 thePixelFormat = GL_RGBA;
215 theDataType = GL_FLOAT;
218 case Image_PixMap::ImgBGRAF:
220 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
224 theTextFormat = GL_RGBA8; // GL_RGBA32F
225 thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
226 theDataType = GL_FLOAT;
229 case Image_PixMap::ImgRGBF:
231 theTextFormat = GL_RGB8; // GL_RGB32F
232 thePixelFormat = GL_RGB;
233 theDataType = GL_FLOAT;
236 case Image_PixMap::ImgBGRF:
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;
247 case Image_PixMap::ImgRGBA:
249 theTextFormat = GL_RGBA8;
250 thePixelFormat = GL_RGBA;
251 theDataType = GL_UNSIGNED_BYTE;
254 case Image_PixMap::ImgBGRA:
256 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
260 theTextFormat = GL_RGBA8;
261 thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
262 theDataType = GL_UNSIGNED_BYTE;
265 case Image_PixMap::ImgRGB32:
267 theTextFormat = GL_RGB8;
268 thePixelFormat = GL_RGBA;
269 theDataType = GL_UNSIGNED_BYTE;
272 case Image_PixMap::ImgBGR32:
274 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
278 theTextFormat = GL_RGB8;
279 thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
280 theDataType = GL_UNSIGNED_BYTE;
283 case Image_PixMap::ImgRGB:
285 theTextFormat = GL_RGB8;
286 thePixelFormat = GL_RGB;
287 theDataType = GL_UNSIGNED_BYTE;
290 case Image_PixMap::ImgBGR:
292 #if !defined(GL_ES_VERSION_2_0)
293 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
297 theTextFormat = GL_RGB8;
298 thePixelFormat = GL_BGR; // equals to GL_BGR_EXT
299 theDataType = GL_UNSIGNED_BYTE;
305 case Image_PixMap::ImgGray:
307 if (theCtx->core11 == NULL)
309 theTextFormat = GL_R8;
310 thePixelFormat = GL_RED;
314 theTextFormat = GL_LUMINANCE8;
315 thePixelFormat = GL_LUMINANCE;
317 theDataType = GL_UNSIGNED_BYTE;
320 case Image_PixMap::ImgAlpha:
322 if (theCtx->core11 == NULL)
324 theTextFormat = GL_R8;
325 thePixelFormat = GL_RED;
329 theTextFormat = GL_ALPHA8;
330 thePixelFormat = GL_ALPHA;
332 theDataType = GL_UNSIGNED_BYTE;
335 case Image_PixMap::ImgUNKNOWN:
343 // =======================================================================
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)
356 if (!Create (theCtx))
358 Release (theCtx.operator->());
362 if (theImage != NULL)
364 myIsAlpha = theImage->Format() == Image_PixMap::ImgAlpha
365 || theImage->Format() == Image_PixMap::ImgAlphaF;
369 myIsAlpha = thePixelFormat == GL_ALPHA;
372 myHasMipmaps = Standard_False;
373 myTextFormat = thePixelFormat;
374 #if !defined(GL_ES_VERSION_2_0)
375 const GLint anIntFormat = theTextFormat;
377 // ES does not support sized formats and format conversions - them detected from data type
378 const GLint anIntFormat = thePixelFormat;
380 const GLsizei aWidth = theSizeX;
381 const GLsizei aHeight = theSizeY;
382 const GLsizei aMaxSize = theCtx->MaxTextureSize();
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();
394 #if !defined(GL_ES_VERSION_2_0)
395 GLint aTestWidth = 0;
396 GLint aTestHeight = 0;
398 GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
400 // setup the alignment
401 OpenGl_UnpackAlignmentSentry anUnpackSentry;
402 if (aDataPtr != NULL)
404 const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
405 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
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);
417 case Graphic3d_TOT_1D:
419 #if !defined(GL_ES_VERSION_2_0)
420 myTarget = GL_TEXTURE_1D;
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);
427 if (aDataPtr != NULL)
429 if (aWidth != aWidthOut)
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)
439 Release (theCtx.operator->());
443 aDataPtr = (GLvoid* )aCopy.Data();
444 anUnpackSentry.Reset();
448 // use proxy to check texture could be created or not
449 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat,
451 thePixelFormat, theDataType, NULL);
452 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
455 // no memory or broken input parameters
457 Release (theCtx.operator->());
461 glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat,
463 thePixelFormat, theDataType, aDataPtr);
464 if (glGetError() != GL_NO_ERROR)
467 Release (theCtx.operator->());
480 case Graphic3d_TOT_2D:
482 myTarget = GL_TEXTURE_2D;
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);
490 if (aDataPtr != NULL)
492 if (aWidth != aWidthOut || aHeight != aHeightOut)
494 #if !defined(GL_ES_VERSION_2_0)
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)
504 Release (theCtx.operator->());
508 aDataPtr = (GLvoid* )aCopy.Data();
509 anUnpackSentry.Reset();
512 Release (theCtx.operator->());
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)
527 // no memory or broken input parameters
529 Release (theCtx.operator->());
534 glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
535 aWidthOut, aHeightOut, 0,
536 thePixelFormat, theDataType, aDataPtr);
537 if (glGetError() != GL_NO_ERROR)
540 Release (theCtx.operator->());
545 mySizeY = aHeightOut;
550 case Graphic3d_TOT_2D_MIPMAP:
552 myTarget = GL_TEXTURE_2D;
553 myHasMipmaps = Standard_True;
555 GLenum aFilterMin = aFilter;
556 aFilterMin = GL_NEAREST_MIPMAP_NEAREST;
557 if (myParams->Filter() == Graphic3d_TOTF_BILINEAR)
559 aFilterMin = GL_LINEAR_MIPMAP_NEAREST;
561 else if (myParams->Filter() == Graphic3d_TOTF_TRILINEAR)
563 aFilterMin = GL_LINEAR_MIPMAP_LINEAR;
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);
572 if (theCtx->arbFBO != NULL
573 && aWidth == aWidthOut && aHeight == aHeightOut)
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)
584 // no memory or broken input parameters
586 Release (theCtx.operator->());
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)
598 Release (theCtx.operator->());
603 mySizeY = aHeightOut;
606 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
607 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
614 #if !defined(GL_ES_VERSION_2_0)
615 bool isCreated = gluBuild2DMipmaps (GL_TEXTURE_2D, anIntFormat,
617 thePixelFormat, theDataType, theImage->Data()) == 0;
620 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &mySizeX);
621 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &mySizeY);
634 Release (theCtx.operator->());
640 // =======================================================================
643 // =======================================================================
644 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
645 const Image_PixMap& theImage,
646 const Graphic3d_TypeOfTexture theType)
648 if (theImage.IsEmpty())
650 Release (theCtx.operator->());
657 if (!GetDataFormat (theCtx, theImage, aTextFormat, aPixelFormat, aDataType))
659 Release (theCtx.operator->());
664 aTextFormat, aPixelFormat, aDataType,
665 (Standard_Integer)theImage.SizeX(),
666 (Standard_Integer)theImage.SizeY(),
670 // =======================================================================
671 // function : InitRectangle
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)
679 if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
684 #if !defined(GL_ES_VERSION_2_0)
685 myTarget = GL_TEXTURE_RECTANGLE;
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();
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);
698 const GLint anIntFormat = theFormat.Internal();
699 myTextFormat = theFormat.Format();
701 glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE,
711 GLint aTestSizeX = 0;
712 GLint aTestSizeY = 0;
714 glGetTexLevelParameteriv (
715 GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
716 glGetTexLevelParameteriv (
717 GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
719 if (aTestSizeX == 0 || aTestSizeY == 0)
725 glTexImage2D (myTarget,
735 if (glGetError() != GL_NO_ERROR)