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>
24 IMPLEMENT_STANDARD_HANDLE (OpenGl_Texture, OpenGl_Resource)
25 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_Resource)
27 //! Simple class to reset unpack alignment settings
28 struct OpenGl_UnpackAlignmentSentry
31 //! Reset unpack alignment settings to safe values
34 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
35 #if !defined(GL_ES_VERSION_2_0)
36 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
40 ~OpenGl_UnpackAlignmentSentry()
47 // =======================================================================
48 // function : OpenGl_Texture
50 // =======================================================================
51 OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams)
53 myTextureId (NO_TEXTURE),
54 myTarget (GL_TEXTURE_2D),
57 myTextFormat (GL_RGBA),
58 myHasMipmaps (Standard_False),
61 if (myParams.IsNull())
63 myParams = new Graphic3d_TextureParams();
67 // =======================================================================
68 // function : ~OpenGl_Texture
70 // =======================================================================
71 OpenGl_Texture::~OpenGl_Texture()
76 // =======================================================================
77 // function : HasMipmaps
79 // =======================================================================
80 const Standard_Boolean OpenGl_Texture::HasMipmaps() const
85 // =======================================================================
86 // function : GetParams
88 // =======================================================================
89 const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const
94 // =======================================================================
95 // function : SetParams
97 // =======================================================================
98 void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams)
100 myParams = theParams;
103 // =======================================================================
106 // =======================================================================
107 bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& )
109 if (myTextureId == NO_TEXTURE)
111 glGenTextures (1, &myTextureId);
113 return myTextureId != NO_TEXTURE;
116 // =======================================================================
117 // function : Release
119 // =======================================================================
120 void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
122 if (myTextureId == NO_TEXTURE)
127 // application can not handle this case by exception - this is bug in code
128 Standard_ASSERT_RETURN (theGlCtx != NULL,
129 "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
131 if (theGlCtx->IsValid())
133 glDeleteTextures (1, &myTextureId);
135 myTextureId = NO_TEXTURE;
136 mySizeX = mySizeY = 0;
139 // =======================================================================
142 // =======================================================================
143 void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
144 const GLenum theTextureUnit) const
146 if (theCtx->IsGlGreaterEqual (1, 5))
148 theCtx->core15fwd->glActiveTexture (theTextureUnit);
150 glBindTexture (myTarget, myTextureId);
153 // =======================================================================
156 // =======================================================================
157 void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
158 const GLenum theTextureUnit) const
160 if (theCtx->IsGlGreaterEqual (1, 5))
162 theCtx->core15fwd->glActiveTexture (theTextureUnit);
164 glBindTexture (myTarget, NO_TEXTURE);
167 //=======================================================================
168 //function : GetDataFormat
170 //=======================================================================
171 bool OpenGl_Texture::GetDataFormat (const Handle(OpenGl_Context)& theCtx,
172 const Image_PixMap& theData,
173 GLint& theTextFormat,
174 GLenum& thePixelFormat,
177 theTextFormat = GL_RGBA8;
180 switch (theData.Format())
182 case Image_PixMap::ImgGrayF:
184 theTextFormat = GL_ALPHA8; // GL_R8, GL_R32F
185 thePixelFormat = GL_ALPHA; // GL_RED
186 theDataType = GL_FLOAT;
189 case Image_PixMap::ImgRGBAF:
191 theTextFormat = GL_RGBA8; // GL_RGBA32F
192 thePixelFormat = GL_RGBA;
193 theDataType = GL_FLOAT;
196 case Image_PixMap::ImgBGRAF:
198 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
202 theTextFormat = GL_RGBA8; // GL_RGBA32F
203 thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
204 theDataType = GL_FLOAT;
207 case Image_PixMap::ImgRGBF:
209 theTextFormat = GL_RGB8; // GL_RGB32F
210 thePixelFormat = GL_RGB;
211 theDataType = GL_FLOAT;
214 case Image_PixMap::ImgBGRF:
216 #if !defined(GL_ES_VERSION_2_0)
217 theTextFormat = GL_RGB8; // GL_RGB32F
218 thePixelFormat = GL_BGR; // equals to GL_BGR_EXT
219 theDataType = GL_FLOAT;
225 case Image_PixMap::ImgRGBA:
227 theTextFormat = GL_RGBA8;
228 thePixelFormat = GL_RGBA;
229 theDataType = GL_UNSIGNED_BYTE;
232 case Image_PixMap::ImgBGRA:
234 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
238 theTextFormat = GL_RGBA8;
239 thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
240 theDataType = GL_UNSIGNED_BYTE;
243 case Image_PixMap::ImgRGB32:
245 theTextFormat = GL_RGB8;
246 thePixelFormat = GL_RGBA;
247 theDataType = GL_UNSIGNED_BYTE;
250 case Image_PixMap::ImgBGR32:
252 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
256 theTextFormat = GL_RGB8;
257 thePixelFormat = GL_BGRA_EXT; // equals to GL_BGRA
258 theDataType = GL_UNSIGNED_BYTE;
261 case Image_PixMap::ImgRGB:
263 theTextFormat = GL_RGB8;
264 thePixelFormat = GL_RGB;
265 theDataType = GL_UNSIGNED_BYTE;
268 case Image_PixMap::ImgBGR:
270 #if !defined(GL_ES_VERSION_2_0)
271 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
275 theTextFormat = GL_RGB8;
276 thePixelFormat = GL_BGR; // equals to GL_BGR_EXT
277 theDataType = GL_UNSIGNED_BYTE;
283 case Image_PixMap::ImgGray:
285 theTextFormat = GL_ALPHA8; // GL_R8
286 thePixelFormat = GL_ALPHA; // GL_RED
287 theDataType = GL_UNSIGNED_BYTE;
297 // =======================================================================
300 // =======================================================================
301 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
302 const Standard_Integer theTextFormat,
303 const GLenum thePixelFormat,
304 const GLenum theDataType,
305 const Standard_Integer theSizeX,
306 const Standard_Integer theSizeY,
307 const Graphic3d_TypeOfTexture theType,
308 const Image_PixMap* theImage)
310 if (!Create (theCtx))
312 Release (theCtx.operator->());
315 myHasMipmaps = Standard_False;
316 myTextFormat = thePixelFormat;
317 #if !defined(GL_ES_VERSION_2_0)
318 const GLint anIntFormat = theTextFormat;
320 // ES does not support sized formats and format conversions - them detected from data type
321 const GLint anIntFormat = thePixelFormat;
323 const GLsizei aWidth = theSizeX;
324 const GLsizei aHeight = theSizeY;
325 const GLsizei aMaxSize = theCtx->MaxTextureSize();
327 // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
328 // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
329 // Trying to create NPOT textures on such hardware will not fail
330 // but driver will fall back into software rendering,
331 const bool toForceP2 = !theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW;
332 const GLsizei aWidthOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aWidth, aMaxSize) : Min (aWidth, aMaxSize);
333 const GLsizei aHeightOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aHeight, aMaxSize) : Min (aHeight, aMaxSize);
335 #if !defined(GL_ES_VERSION_2_0)
336 GLint aTestWidth = 0;
337 GLint aTestHeight = 0;
339 GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
341 // setup the alignment
342 OpenGl_UnpackAlignmentSentry anUnpackSentry;
343 if (aDataPtr != NULL)
345 const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
346 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
348 #if !defined(GL_ES_VERSION_2_0)
349 // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
350 const GLint anExtraBytes = GLint(theImage->RowExtraBytes());
351 const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes());
352 glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
358 case Graphic3d_TOT_1D:
360 #if !defined(GL_ES_VERSION_2_0)
361 myTarget = GL_TEXTURE_1D;
363 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
364 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
367 if (aDataPtr != NULL)
369 if (aWidth != aWidthOut)
371 glPixelStorei (GL_PACK_ALIGNMENT, 1);
372 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
373 if (!aCopy.InitTrash (theImage->Format(), Standard_Size(aWidthOut), 1)
374 || gluScaleImage (thePixelFormat,
375 aWidth, 1, theDataType, theImage->Data(),
376 aWidthOut, 1, theDataType, aCopy.ChangeData()) != 0)
379 Release (theCtx.operator->());
383 aDataPtr = (GLvoid* )aCopy.Data();
384 anUnpackSentry.Reset();
388 // use proxy to check texture could be created or not
389 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat,
391 thePixelFormat, theDataType, NULL);
392 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
395 // no memory or broken input parameters
397 Release (theCtx.operator->());
401 glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat,
403 thePixelFormat, theDataType, aDataPtr);
404 if (glGetError() != GL_NO_ERROR)
407 Release (theCtx.operator->());
420 case Graphic3d_TOT_2D:
422 myTarget = GL_TEXTURE_2D;
424 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
425 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
428 if (aDataPtr != NULL)
430 if (aWidth != aWidthOut || aHeight != aHeightOut)
432 #if !defined(GL_ES_VERSION_2_0)
434 glPixelStorei (GL_PACK_ALIGNMENT, 1);
435 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
436 if (!aCopy.InitTrash (theImage->Format(), Standard_Size(aWidthOut), Standard_Size(aHeightOut))
437 || gluScaleImage (thePixelFormat,
438 aWidth, aHeight, theDataType, theImage->Data(),
439 aWidthOut, aHeightOut, theDataType, aCopy.ChangeData()) != 0)
442 Release (theCtx.operator->());
446 aDataPtr = (GLvoid* )aCopy.Data();
447 anUnpackSentry.Reset();
450 Release (theCtx.operator->());
456 #if !defined(GL_ES_VERSION_2_0)
457 // use proxy to check texture could be created or not
458 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
459 aWidthOut, aHeightOut, 0,
460 thePixelFormat, theDataType, NULL);
461 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
462 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
463 if (aTestWidth == 0 || aTestHeight == 0)
465 // no memory or broken input parameters
467 Release (theCtx.operator->());
472 glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
473 aWidthOut, aHeightOut, 0,
474 thePixelFormat, theDataType, aDataPtr);
475 if (glGetError() != GL_NO_ERROR)
478 Release (theCtx.operator->());
483 mySizeY = aHeightOut;
488 case Graphic3d_TOT_2D_MIPMAP:
490 myTarget = GL_TEXTURE_2D;
491 myHasMipmaps = Standard_True;
493 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
494 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
496 if (theCtx->arbFBO != NULL
497 && aWidth == aWidthOut && aHeight == aHeightOut)
499 #if !defined(GL_ES_VERSION_2_0)
500 // use proxy to check texture could be created or not
501 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
502 aWidthOut, aHeightOut, 0,
503 thePixelFormat, theDataType, NULL);
504 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
505 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
506 if (aTestWidth == 0 || aTestHeight == 0)
508 // no memory or broken input parameters
510 Release (theCtx.operator->());
515 // upload main picture
516 glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
517 aWidthOut, aHeightOut, 0,
518 thePixelFormat, theDataType, theImage->Data());
519 if (glGetError() != GL_NO_ERROR)
522 Release (theCtx.operator->());
527 mySizeY = aHeightOut;
530 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
531 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
538 #if !defined(GL_ES_VERSION_2_0)
539 bool isCreated = gluBuild2DMipmaps (GL_TEXTURE_2D, anIntFormat,
541 thePixelFormat, theDataType, theImage->Data()) == 0;
544 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &mySizeX);
545 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &mySizeY);
558 Release (theCtx.operator->());
564 // =======================================================================
567 // =======================================================================
568 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
569 const Image_PixMap& theImage,
570 const Graphic3d_TypeOfTexture theType)
572 if (theImage.IsEmpty())
574 Release (theCtx.operator->());
581 if (!GetDataFormat (theCtx, theImage, aTextFormat, aPixelFormat, aDataType))
583 Release (theCtx.operator->());
588 aTextFormat, aPixelFormat, aDataType,
589 (Standard_Integer)theImage.SizeX(),
590 (Standard_Integer)theImage.SizeY(),
594 // =======================================================================
595 // function : InitRectangle
597 // =======================================================================
598 bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
599 const Standard_Integer theSizeX,
600 const Standard_Integer theSizeY,
601 const OpenGl_TextureFormat& theFormat)
603 if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
608 #if !defined(GL_ES_VERSION_2_0)
609 myTarget = GL_TEXTURE_RECTANGLE;
611 const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
612 const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
616 if (myParams->Filter() == Graphic3d_TOTF_NEAREST)
618 glTexParameteri (myTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
619 glTexParameteri (myTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
623 glTexParameteri (myTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
624 glTexParameteri (myTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
627 const GLint anIntFormat = theFormat.Internal();
628 myTextFormat = theFormat.Format();
630 glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE,
640 GLint aTestSizeX = 0;
641 GLint aTestSizeY = 0;
643 glGetTexLevelParameteriv (
644 GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
645 glGetTexLevelParameteriv (
646 GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
648 if (aTestSizeX == 0 || aTestSizeY == 0)
654 glTexImage2D (myTarget,
664 if (glGetError() != GL_NO_ERROR)