1 // Created by: Kirill GAVRILOV
2 // Copyright (c) 2012 OPEN CASCADE SAS
4 // The content of this file is subject to the Open CASCADE Technology Public
5 // License Version 6.5 (the "License"). You may not use the content of this file
6 // except in compliance with the License. Please obtain a copy of the License
7 // at http://www.opencascade.org and read it completely before using this file.
9 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
10 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12 // The Original Code and all software distributed under the License is
13 // distributed on an "AS IS" basis, without warranty of any kind, and the
14 // Initial Developer hereby disclaims all such warranties, including without
15 // limitation, any warranties of merchantability, fitness for a particular
16 // purpose or non-infringement. Please see the License for the specific terms
17 // and conditions governing the rights and limitations under the License.
19 #include <OpenGl_Texture.hxx>
21 #include <OpenGl_ExtFBO.hxx>
22 #include <OpenGl_Context.hxx>
23 #include <Graphic3d_TextureParams.hxx>
24 #include <Standard_Assert.hxx>
25 #include <Image_PixMap.hxx>
27 IMPLEMENT_STANDARD_HANDLE (OpenGl_Texture, OpenGl_Resource)
28 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_Resource)
30 //! Simple class to reset unpack alignment settings
31 struct OpenGl_UnpackAlignmentSentry
34 //! Reset unpack alignment settings to safe values
37 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
38 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
41 ~OpenGl_UnpackAlignmentSentry()
48 // =======================================================================
49 // function : OpenGl_Texture
51 // =======================================================================
52 OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams)
54 myTextureId (NO_TEXTURE),
55 myTarget (GL_TEXTURE_2D),
58 myTextFormat (GL_FLOAT),
59 myHasMipmaps (Standard_False),
62 if (myParams.IsNull())
64 myParams = new Graphic3d_TextureParams();
68 // =======================================================================
69 // function : ~OpenGl_Texture
71 // =======================================================================
72 OpenGl_Texture::~OpenGl_Texture()
77 // =======================================================================
78 // function : HasMipmaps
80 // =======================================================================
81 const Standard_Boolean OpenGl_Texture::HasMipmaps() const
86 // =======================================================================
87 // function : GetParams
89 // =======================================================================
90 const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const
95 // =======================================================================
96 // function : SetParams
98 // =======================================================================
99 void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams)
101 myParams = theParams;
104 // =======================================================================
107 // =======================================================================
108 bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& )
110 if (myTextureId == NO_TEXTURE)
112 glGenTextures (1, &myTextureId);
114 return myTextureId != NO_TEXTURE;
117 // =======================================================================
118 // function : Release
120 // =======================================================================
121 void OpenGl_Texture::Release (const OpenGl_Context* theGlCtx)
123 if (myTextureId == NO_TEXTURE)
128 // application can not handle this case by exception - this is bug in code
129 Standard_ASSERT_RETURN (theGlCtx != NULL,
130 "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
132 if (theGlCtx->IsValid())
134 glDeleteTextures (1, &myTextureId);
136 myTextureId = NO_TEXTURE;
137 mySizeX = mySizeY = 0;
140 // =======================================================================
143 // =======================================================================
144 void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
145 const GLenum theTextureUnit) const
147 if (theCtx->IsGlGreaterEqual (1, 3))
149 theCtx->core13->glActiveTexture (theTextureUnit);
151 glBindTexture (myTarget, myTextureId);
154 // =======================================================================
157 // =======================================================================
158 void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
159 const GLenum theTextureUnit) const
161 if (theCtx->IsGlGreaterEqual (1, 3))
163 theCtx->core13->glActiveTexture (theTextureUnit);
165 glBindTexture (myTarget, NO_TEXTURE);
168 // =======================================================================
171 // =======================================================================
172 bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
173 const Image_PixMap& theImage,
174 const Graphic3d_TypeOfTexture theType)
176 myHasMipmaps = Standard_False;
177 if (theImage.IsEmpty() || !Create (theCtx))
182 myTextFormat = GL_RGBA8;
183 GLenum aPixelFormat = 0;
184 GLenum aDataType = 0;
185 switch (theImage.Format())
187 case Image_PixMap::ImgGrayF:
189 myTextFormat = GL_ALPHA8; // GL_R8, GL_R32F
190 aPixelFormat = GL_ALPHA; // GL_RED
191 aDataType = GL_FLOAT;
194 case Image_PixMap::ImgRGBAF:
196 myTextFormat = GL_RGBA8; // GL_RGBA32F
197 aPixelFormat = GL_RGBA;
198 aDataType = GL_FLOAT;
201 case Image_PixMap::ImgBGRAF:
203 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
207 myTextFormat = GL_RGBA8; // GL_RGBA32F
208 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
209 aDataType = GL_FLOAT;
212 case Image_PixMap::ImgRGBF:
214 myTextFormat = GL_RGB8; // GL_RGB32F
215 aPixelFormat = GL_RGB;
216 aDataType = GL_FLOAT;
219 case Image_PixMap::ImgBGRF:
221 myTextFormat = GL_RGB8; // GL_RGB32F
222 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
223 aDataType = GL_FLOAT;
226 case Image_PixMap::ImgRGBA:
228 myTextFormat = GL_RGBA8;
229 aPixelFormat = GL_RGBA;
230 aDataType = GL_UNSIGNED_BYTE;
233 case Image_PixMap::ImgBGRA:
235 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
239 myTextFormat = GL_RGBA8;
240 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
241 aDataType = GL_UNSIGNED_BYTE;
244 case Image_PixMap::ImgRGB32:
246 myTextFormat = GL_RGB8;
247 aPixelFormat = GL_RGBA;
248 aDataType = GL_UNSIGNED_BYTE;
251 case Image_PixMap::ImgBGR32:
253 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
257 myTextFormat = GL_RGB8;
258 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
259 aDataType = GL_UNSIGNED_BYTE;
262 case Image_PixMap::ImgRGB:
264 myTextFormat = GL_RGB8;
265 aPixelFormat = GL_RGB;
266 aDataType = GL_UNSIGNED_BYTE;
269 case Image_PixMap::ImgBGR:
271 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
275 myTextFormat = GL_RGB8;
276 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
277 aDataType = GL_UNSIGNED_BYTE;
280 case Image_PixMap::ImgGray:
282 myTextFormat = GL_ALPHA8; // GL_R8
283 aPixelFormat = GL_ALPHA; // GL_RED
284 aDataType = GL_UNSIGNED_BYTE;
293 const GLsizei aMaxSize = theCtx->MaxTextureSize();
294 const GLsizei aWidth = (GLsizei )theImage.SizeX();
295 const GLsizei aHeight = (GLsizei )theImage.SizeY();
297 // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
298 // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
299 // Trying to create NPOT rextures on such hardware will not fail
300 // but driver will fall back into software rendering,
301 const bool toForceP2 = !theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW;
302 const GLsizei aWidthOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aWidth, aMaxSize) : Min (aWidth, aMaxSize);
303 const GLsizei aHeightOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aHeight, aMaxSize) : Min (aHeight, aMaxSize);
305 GLint aTestWidth = 0;
306 GLint aTestHeight = 0;
308 // setup the alignment
309 OpenGl_UnpackAlignmentSentry anUnpackSentry;
310 const GLint anAligment = Min ((GLint )theImage.MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
311 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
313 // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
314 const GLint anExtraBytes = GLint(theImage.RowExtraBytes());
315 const GLint aPixelsWidth = GLint(theImage.SizeRowBytes() / theImage.SizePixelBytes());
316 glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
320 case Graphic3d_TOT_1D:
322 myTarget = GL_TEXTURE_1D;
324 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
325 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
328 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
329 if (aWidth != aWidthOut)
331 glPixelStorei (GL_PACK_ALIGNMENT, 1);
332 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
333 if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), 1)
334 || gluScaleImage (aPixelFormat,
335 aWidth, 1, aDataType, theImage.Data(),
336 aWidthOut, 1, aDataType, aCopy.ChangeData()) != 0)
342 aDataPtr = (GLvoid* )aCopy.Data();
343 anUnpackSentry.Reset();
346 // use proxy to check texture could be created or not
347 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, myTextFormat,
349 aPixelFormat, aDataType, NULL);
350 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
353 // no memory or broken input parameters
358 glTexImage1D (GL_TEXTURE_1D, 0, myTextFormat,
360 aPixelFormat, aDataType, aDataPtr);
361 if (glGetError() != GL_NO_ERROR)
373 case Graphic3d_TOT_2D:
375 myTarget = GL_TEXTURE_2D;
377 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
378 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
381 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
382 if (aWidth != aWidthOut || aHeight != aHeightOut)
385 glPixelStorei (GL_PACK_ALIGNMENT, 1);
386 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
387 if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), Standard_Size(aHeightOut))
388 || gluScaleImage (aPixelFormat,
389 aWidth, aHeight, aDataType, theImage.Data(),
390 aWidthOut, aHeightOut, aDataType, aCopy.ChangeData()) != 0)
396 aDataPtr = (GLvoid* )aCopy.Data();
397 anUnpackSentry.Reset();
400 // use proxy to check texture could be created or not
401 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
402 aWidthOut, aHeightOut, 0,
403 aPixelFormat, aDataType, NULL);
404 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
405 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
406 if (aTestWidth == 0 || aTestHeight == 0)
408 // no memory or broken input parameters
413 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
414 aWidthOut, aHeightOut, 0,
415 aPixelFormat, aDataType, aDataPtr);
416 if (glGetError() != GL_NO_ERROR)
423 mySizeY = aHeightOut;
428 case Graphic3d_TOT_2D_MIPMAP:
430 myTarget = GL_TEXTURE_2D;
431 myHasMipmaps = Standard_True;
433 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
434 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
436 if (theCtx->extFBO != NULL
437 && aWidth == aWidthOut && aHeight == aHeightOut)
439 // use proxy to check texture could be created or not
440 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
441 aWidthOut, aHeightOut, 0,
442 aPixelFormat, aDataType, NULL);
443 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
444 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
445 if (aTestWidth == 0 || aTestHeight == 0)
447 // no memory or broken input parameters
452 // upload main picture
453 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
454 aWidthOut, aHeightOut, 0,
455 aPixelFormat, aDataType, theImage.Data());
456 if (glGetError() != GL_NO_ERROR)
463 mySizeY = aHeightOut;
466 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
467 theCtx->extFBO->glGenerateMipmapEXT (GL_TEXTURE_2D);
474 bool isCreated = gluBuild2DMipmaps (GL_TEXTURE_2D, myTextFormat,
476 aPixelFormat, aDataType, theImage.Data()) == 0;
479 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &mySizeX);
480 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &mySizeY);