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 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_FLOAT),
56 myHasMipmaps (Standard_False),
59 if (myParams.IsNull())
61 myParams = new Graphic3d_TextureParams();
65 // =======================================================================
66 // function : ~OpenGl_Texture
68 // =======================================================================
69 OpenGl_Texture::~OpenGl_Texture()
74 // =======================================================================
75 // function : HasMipmaps
77 // =======================================================================
78 const Standard_Boolean OpenGl_Texture::HasMipmaps() const
83 // =======================================================================
84 // function : GetParams
86 // =======================================================================
87 const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const
92 // =======================================================================
93 // function : SetParams
95 // =======================================================================
96 void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams)
101 // =======================================================================
104 // =======================================================================
105 bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& )
107 if (myTextureId == NO_TEXTURE)
109 glGenTextures (1, &myTextureId);
111 return myTextureId != NO_TEXTURE;
114 // =======================================================================
115 // function : Release
117 // =======================================================================
118 void OpenGl_Texture::Release (const OpenGl_Context* theGlCtx)
120 if (myTextureId == NO_TEXTURE)
125 // application can not handle this case by exception - this is bug in code
126 Standard_ASSERT_RETURN (theGlCtx != NULL,
127 "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
129 if (theGlCtx->IsValid())
131 glDeleteTextures (1, &myTextureId);
133 myTextureId = NO_TEXTURE;
134 mySizeX = mySizeY = 0;
137 // =======================================================================
140 // =======================================================================
141 void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
142 const GLenum theTextureUnit) const
144 if (theCtx->IsGlGreaterEqual (1, 5))
146 theCtx->core15fwd->glActiveTexture (theTextureUnit);
148 glBindTexture (myTarget, myTextureId);
151 // =======================================================================
154 // =======================================================================
155 void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
156 const GLenum theTextureUnit) const
158 if (theCtx->IsGlGreaterEqual (1, 5))
160 theCtx->core15fwd->glActiveTexture (theTextureUnit);
162 glBindTexture (myTarget, NO_TEXTURE);
165 // =======================================================================
168 // =======================================================================
169 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
170 const Image_PixMap& theImage,
171 const Graphic3d_TypeOfTexture theType)
173 myHasMipmaps = Standard_False;
174 if (theImage.IsEmpty() || !Create (theCtx))
179 myTextFormat = GL_RGBA8;
180 GLenum aPixelFormat = 0;
181 GLenum aDataType = 0;
182 switch (theImage.Format())
184 case Image_PixMap::ImgGrayF:
186 myTextFormat = GL_ALPHA8; // GL_R8, GL_R32F
187 aPixelFormat = GL_ALPHA; // GL_RED
188 aDataType = GL_FLOAT;
191 case Image_PixMap::ImgRGBAF:
193 myTextFormat = GL_RGBA8; // GL_RGBA32F
194 aPixelFormat = GL_RGBA;
195 aDataType = GL_FLOAT;
198 case Image_PixMap::ImgBGRAF:
200 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
204 myTextFormat = GL_RGBA8; // GL_RGBA32F
205 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
206 aDataType = GL_FLOAT;
209 case Image_PixMap::ImgRGBF:
211 myTextFormat = GL_RGB8; // GL_RGB32F
212 aPixelFormat = GL_RGB;
213 aDataType = GL_FLOAT;
216 case Image_PixMap::ImgBGRF:
218 myTextFormat = GL_RGB8; // GL_RGB32F
219 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
220 aDataType = GL_FLOAT;
223 case Image_PixMap::ImgRGBA:
225 myTextFormat = GL_RGBA8;
226 aPixelFormat = GL_RGBA;
227 aDataType = GL_UNSIGNED_BYTE;
230 case Image_PixMap::ImgBGRA:
232 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
236 myTextFormat = GL_RGBA8;
237 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
238 aDataType = GL_UNSIGNED_BYTE;
241 case Image_PixMap::ImgRGB32:
243 myTextFormat = GL_RGB8;
244 aPixelFormat = GL_RGBA;
245 aDataType = GL_UNSIGNED_BYTE;
248 case Image_PixMap::ImgBGR32:
250 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
254 myTextFormat = GL_RGB8;
255 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
256 aDataType = GL_UNSIGNED_BYTE;
259 case Image_PixMap::ImgRGB:
261 myTextFormat = GL_RGB8;
262 aPixelFormat = GL_RGB;
263 aDataType = GL_UNSIGNED_BYTE;
266 case Image_PixMap::ImgBGR:
268 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
272 myTextFormat = GL_RGB8;
273 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
274 aDataType = GL_UNSIGNED_BYTE;
277 case Image_PixMap::ImgGray:
279 myTextFormat = GL_ALPHA8; // GL_R8
280 aPixelFormat = GL_ALPHA; // GL_RED
281 aDataType = GL_UNSIGNED_BYTE;
290 const GLsizei aMaxSize = theCtx->MaxTextureSize();
291 const GLsizei aWidth = (GLsizei )theImage.SizeX();
292 const GLsizei aHeight = (GLsizei )theImage.SizeY();
294 // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
295 // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
296 // Trying to create NPOT textures on such hardware will not fail
297 // but driver will fall back into software rendering,
298 const bool toForceP2 = !theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW;
299 const GLsizei aWidthOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aWidth, aMaxSize) : Min (aWidth, aMaxSize);
300 const GLsizei aHeightOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aHeight, aMaxSize) : Min (aHeight, aMaxSize);
302 GLint aTestWidth = 0;
303 GLint aTestHeight = 0;
305 // setup the alignment
306 OpenGl_UnpackAlignmentSentry anUnpackSentry;
307 const GLint anAligment = Min ((GLint )theImage.MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
308 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
310 // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
311 const GLint anExtraBytes = GLint(theImage.RowExtraBytes());
312 const GLint aPixelsWidth = GLint(theImage.SizeRowBytes() / theImage.SizePixelBytes());
313 glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
317 case Graphic3d_TOT_1D:
319 myTarget = GL_TEXTURE_1D;
321 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
322 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
325 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
326 if (aWidth != aWidthOut)
328 glPixelStorei (GL_PACK_ALIGNMENT, 1);
329 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
330 if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), 1)
331 || gluScaleImage (aPixelFormat,
332 aWidth, 1, aDataType, theImage.Data(),
333 aWidthOut, 1, aDataType, aCopy.ChangeData()) != 0)
339 aDataPtr = (GLvoid* )aCopy.Data();
340 anUnpackSentry.Reset();
343 // use proxy to check texture could be created or not
344 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, myTextFormat,
346 aPixelFormat, aDataType, NULL);
347 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
350 // no memory or broken input parameters
355 glTexImage1D (GL_TEXTURE_1D, 0, myTextFormat,
357 aPixelFormat, aDataType, aDataPtr);
358 if (glGetError() != GL_NO_ERROR)
370 case Graphic3d_TOT_2D:
372 myTarget = GL_TEXTURE_2D;
374 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
375 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
378 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
379 if (aWidth != aWidthOut || aHeight != aHeightOut)
382 glPixelStorei (GL_PACK_ALIGNMENT, 1);
383 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
384 if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), Standard_Size(aHeightOut))
385 || gluScaleImage (aPixelFormat,
386 aWidth, aHeight, aDataType, theImage.Data(),
387 aWidthOut, aHeightOut, aDataType, aCopy.ChangeData()) != 0)
393 aDataPtr = (GLvoid* )aCopy.Data();
394 anUnpackSentry.Reset();
397 // use proxy to check texture could be created or not
398 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
399 aWidthOut, aHeightOut, 0,
400 aPixelFormat, aDataType, NULL);
401 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
402 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
403 if (aTestWidth == 0 || aTestHeight == 0)
405 // no memory or broken input parameters
410 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
411 aWidthOut, aHeightOut, 0,
412 aPixelFormat, aDataType, aDataPtr);
413 if (glGetError() != GL_NO_ERROR)
420 mySizeY = aHeightOut;
425 case Graphic3d_TOT_2D_MIPMAP:
427 myTarget = GL_TEXTURE_2D;
428 myHasMipmaps = Standard_True;
430 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
431 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
433 if (theCtx->arbFBO != NULL
434 && aWidth == aWidthOut && aHeight == aHeightOut)
436 // use proxy to check texture could be created or not
437 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
438 aWidthOut, aHeightOut, 0,
439 aPixelFormat, aDataType, NULL);
440 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
441 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
442 if (aTestWidth == 0 || aTestHeight == 0)
444 // no memory or broken input parameters
449 // upload main picture
450 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
451 aWidthOut, aHeightOut, 0,
452 aPixelFormat, aDataType, theImage.Data());
453 if (glGetError() != GL_NO_ERROR)
460 mySizeY = aHeightOut;
463 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
464 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
471 bool isCreated = gluBuild2DMipmaps (GL_TEXTURE_2D, myTextFormat,
473 aPixelFormat, aDataType, theImage.Data()) == 0;
476 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &mySizeX);
477 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &mySizeY);
491 // =======================================================================
492 // function : InitRectangle
494 // =======================================================================
495 bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
496 const Standard_Integer theSizeX,
497 const Standard_Integer theSizeY,
498 const OpenGl_TextureFormat& theFormat)
500 if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
505 myTarget = GL_TEXTURE_RECTANGLE;
507 const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
508 const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
512 if (myParams->Filter() == Graphic3d_TOTF_NEAREST)
514 glTexParameteri (myTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
515 glTexParameteri (myTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
519 glTexParameteri (myTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
520 glTexParameteri (myTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
523 myTextFormat = theFormat.Internal();
525 glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE,
535 GLint aTestSizeX = 0;
536 GLint aTestSizeY = 0;
538 glGetTexLevelParameteriv (
539 GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
540 glGetTexLevelParameteriv (
541 GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
543 if (aTestSizeX == 0 || aTestSizeY == 0)
549 glTexImage2D (myTarget,
559 if (glGetError() != GL_NO_ERROR)