1 // Created by: Kirill GAVRILOV
2 // Copyright (c) 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
7 // under the terms of the GNU Lesser General Public 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_ExtFBO.hxx>
18 #include <OpenGl_Context.hxx>
19 #include <Graphic3d_TextureParams.hxx>
20 #include <Standard_Assert.hxx>
21 #include <Image_PixMap.hxx>
23 IMPLEMENT_STANDARD_HANDLE (OpenGl_Texture, OpenGl_Resource)
24 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_Resource)
26 //! Simple class to reset unpack alignment settings
27 struct OpenGl_UnpackAlignmentSentry
30 //! Reset unpack alignment settings to safe values
33 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
34 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
37 ~OpenGl_UnpackAlignmentSentry()
44 // =======================================================================
45 // function : OpenGl_Texture
47 // =======================================================================
48 OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams)
50 myTextureId (NO_TEXTURE),
51 myTarget (GL_TEXTURE_2D),
54 myTextFormat (GL_FLOAT),
55 myHasMipmaps (Standard_False),
58 if (myParams.IsNull())
60 myParams = new Graphic3d_TextureParams();
64 // =======================================================================
65 // function : ~OpenGl_Texture
67 // =======================================================================
68 OpenGl_Texture::~OpenGl_Texture()
73 // =======================================================================
74 // function : HasMipmaps
76 // =======================================================================
77 const Standard_Boolean OpenGl_Texture::HasMipmaps() const
82 // =======================================================================
83 // function : GetParams
85 // =======================================================================
86 const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const
91 // =======================================================================
92 // function : SetParams
94 // =======================================================================
95 void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams)
100 // =======================================================================
103 // =======================================================================
104 bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& )
106 if (myTextureId == NO_TEXTURE)
108 glGenTextures (1, &myTextureId);
110 return myTextureId != NO_TEXTURE;
113 // =======================================================================
114 // function : Release
116 // =======================================================================
117 void OpenGl_Texture::Release (const OpenGl_Context* theGlCtx)
119 if (myTextureId == NO_TEXTURE)
124 // application can not handle this case by exception - this is bug in code
125 Standard_ASSERT_RETURN (theGlCtx != NULL,
126 "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
128 if (theGlCtx->IsValid())
130 glDeleteTextures (1, &myTextureId);
132 myTextureId = NO_TEXTURE;
133 mySizeX = mySizeY = 0;
136 // =======================================================================
139 // =======================================================================
140 void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
141 const GLenum theTextureUnit) const
143 if (theCtx->IsGlGreaterEqual (1, 3))
145 theCtx->core13->glActiveTexture (theTextureUnit);
147 glBindTexture (myTarget, myTextureId);
150 // =======================================================================
153 // =======================================================================
154 void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
155 const GLenum theTextureUnit) const
157 if (theCtx->IsGlGreaterEqual (1, 3))
159 theCtx->core13->glActiveTexture (theTextureUnit);
161 glBindTexture (myTarget, NO_TEXTURE);
164 // =======================================================================
167 // =======================================================================
168 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
169 const Image_PixMap& theImage,
170 const Graphic3d_TypeOfTexture theType)
172 myHasMipmaps = Standard_False;
173 if (theImage.IsEmpty() || !Create (theCtx))
178 myTextFormat = GL_RGBA8;
179 GLenum aPixelFormat = 0;
180 GLenum aDataType = 0;
181 switch (theImage.Format())
183 case Image_PixMap::ImgGrayF:
185 myTextFormat = GL_ALPHA8; // GL_R8, GL_R32F
186 aPixelFormat = GL_ALPHA; // GL_RED
187 aDataType = GL_FLOAT;
190 case Image_PixMap::ImgRGBAF:
192 myTextFormat = GL_RGBA8; // GL_RGBA32F
193 aPixelFormat = GL_RGBA;
194 aDataType = GL_FLOAT;
197 case Image_PixMap::ImgBGRAF:
199 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
203 myTextFormat = GL_RGBA8; // GL_RGBA32F
204 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
205 aDataType = GL_FLOAT;
208 case Image_PixMap::ImgRGBF:
210 myTextFormat = GL_RGB8; // GL_RGB32F
211 aPixelFormat = GL_RGB;
212 aDataType = GL_FLOAT;
215 case Image_PixMap::ImgBGRF:
217 myTextFormat = GL_RGB8; // GL_RGB32F
218 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
219 aDataType = GL_FLOAT;
222 case Image_PixMap::ImgRGBA:
224 myTextFormat = GL_RGBA8;
225 aPixelFormat = GL_RGBA;
226 aDataType = GL_UNSIGNED_BYTE;
229 case Image_PixMap::ImgBGRA:
231 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
235 myTextFormat = GL_RGBA8;
236 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
237 aDataType = GL_UNSIGNED_BYTE;
240 case Image_PixMap::ImgRGB32:
242 myTextFormat = GL_RGB8;
243 aPixelFormat = GL_RGBA;
244 aDataType = GL_UNSIGNED_BYTE;
247 case Image_PixMap::ImgBGR32:
249 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
253 myTextFormat = GL_RGB8;
254 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
255 aDataType = GL_UNSIGNED_BYTE;
258 case Image_PixMap::ImgRGB:
260 myTextFormat = GL_RGB8;
261 aPixelFormat = GL_RGB;
262 aDataType = GL_UNSIGNED_BYTE;
265 case Image_PixMap::ImgBGR:
267 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
271 myTextFormat = GL_RGB8;
272 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
273 aDataType = GL_UNSIGNED_BYTE;
276 case Image_PixMap::ImgGray:
278 myTextFormat = GL_ALPHA8; // GL_R8
279 aPixelFormat = GL_ALPHA; // GL_RED
280 aDataType = GL_UNSIGNED_BYTE;
289 const GLsizei aMaxSize = theCtx->MaxTextureSize();
290 const GLsizei aWidth = (GLsizei )theImage.SizeX();
291 const GLsizei aHeight = (GLsizei )theImage.SizeY();
293 // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
294 // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
295 // Trying to create NPOT rextures on such hardware will not fail
296 // but driver will fall back into software rendering,
297 const bool toForceP2 = !theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW;
298 const GLsizei aWidthOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aWidth, aMaxSize) : Min (aWidth, aMaxSize);
299 const GLsizei aHeightOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aHeight, aMaxSize) : Min (aHeight, aMaxSize);
301 GLint aTestWidth = 0;
302 GLint aTestHeight = 0;
304 // setup the alignment
305 OpenGl_UnpackAlignmentSentry anUnpackSentry;
306 const GLint anAligment = Min ((GLint )theImage.MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
307 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
309 // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
310 const GLint anExtraBytes = GLint(theImage.RowExtraBytes());
311 const GLint aPixelsWidth = GLint(theImage.SizeRowBytes() / theImage.SizePixelBytes());
312 glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
316 case Graphic3d_TOT_1D:
318 myTarget = GL_TEXTURE_1D;
320 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
321 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
324 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
325 if (aWidth != aWidthOut)
327 glPixelStorei (GL_PACK_ALIGNMENT, 1);
328 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
329 if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), 1)
330 || gluScaleImage (aPixelFormat,
331 aWidth, 1, aDataType, theImage.Data(),
332 aWidthOut, 1, aDataType, aCopy.ChangeData()) != 0)
338 aDataPtr = (GLvoid* )aCopy.Data();
339 anUnpackSentry.Reset();
342 // use proxy to check texture could be created or not
343 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, myTextFormat,
345 aPixelFormat, aDataType, NULL);
346 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
349 // no memory or broken input parameters
354 glTexImage1D (GL_TEXTURE_1D, 0, myTextFormat,
356 aPixelFormat, aDataType, aDataPtr);
357 if (glGetError() != GL_NO_ERROR)
369 case Graphic3d_TOT_2D:
371 myTarget = GL_TEXTURE_2D;
373 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
374 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
377 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
378 if (aWidth != aWidthOut || aHeight != aHeightOut)
381 glPixelStorei (GL_PACK_ALIGNMENT, 1);
382 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
383 if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), Standard_Size(aHeightOut))
384 || gluScaleImage (aPixelFormat,
385 aWidth, aHeight, aDataType, theImage.Data(),
386 aWidthOut, aHeightOut, aDataType, aCopy.ChangeData()) != 0)
392 aDataPtr = (GLvoid* )aCopy.Data();
393 anUnpackSentry.Reset();
396 // use proxy to check texture could be created or not
397 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
398 aWidthOut, aHeightOut, 0,
399 aPixelFormat, aDataType, NULL);
400 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
401 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
402 if (aTestWidth == 0 || aTestHeight == 0)
404 // no memory or broken input parameters
409 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
410 aWidthOut, aHeightOut, 0,
411 aPixelFormat, aDataType, aDataPtr);
412 if (glGetError() != GL_NO_ERROR)
419 mySizeY = aHeightOut;
424 case Graphic3d_TOT_2D_MIPMAP:
426 myTarget = GL_TEXTURE_2D;
427 myHasMipmaps = Standard_True;
429 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
430 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
432 if (theCtx->extFBO != NULL
433 && aWidth == aWidthOut && aHeight == aHeightOut)
435 // use proxy to check texture could be created or not
436 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
437 aWidthOut, aHeightOut, 0,
438 aPixelFormat, aDataType, NULL);
439 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
440 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
441 if (aTestWidth == 0 || aTestHeight == 0)
443 // no memory or broken input parameters
448 // upload main picture
449 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
450 aWidthOut, aHeightOut, 0,
451 aPixelFormat, aDataType, theImage.Data());
452 if (glGetError() != GL_NO_ERROR)
459 mySizeY = aHeightOut;
462 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
463 theCtx->extFBO->glGenerateMipmapEXT (GL_TEXTURE_2D);
470 bool isCreated = gluBuild2DMipmaps (GL_TEXTURE_2D, myTextFormat,
472 aPixelFormat, aDataType, theImage.Data()) == 0;
475 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &mySizeX);
476 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &mySizeY);