0024166: Unable to create file with "Save" menu of voxeldemo Qt sample
[occt.git] / src / OpenGl / OpenGl_Texture.cxx
CommitLineData
bf75be98 1// Created by: Kirill GAVRILOV
2// Copyright (c) 2012 OPEN CASCADE SAS
3//
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.
8//
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.
11//
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.
18
19#include <OpenGl_Texture.hxx>
20
1a7dfdb7 21#include <OpenGl_ExtFBO.hxx>
bf75be98 22#include <OpenGl_Context.hxx>
23#include <Graphic3d_TextureParams.hxx>
24#include <Standard_Assert.hxx>
25#include <Image_PixMap.hxx>
26
27IMPLEMENT_STANDARD_HANDLE (OpenGl_Texture, OpenGl_Resource)
28IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_Resource)
29
74706083 30//! Simple class to reset unpack alignment settings
31struct OpenGl_UnpackAlignmentSentry
32{
33
34 //! Reset unpack alignment settings to safe values
35 void Reset()
36 {
37 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
38 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
39 }
40
41 ~OpenGl_UnpackAlignmentSentry()
42 {
43 Reset();
44 }
45
46};
47
bf75be98 48// =======================================================================
49// function : OpenGl_Texture
50// purpose :
51// =======================================================================
52OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams)
53: OpenGl_Resource(),
54 myTextureId (NO_TEXTURE),
55 myTarget (GL_TEXTURE_2D),
56 mySizeX (0),
57 mySizeY (0),
58 myTextFormat (GL_FLOAT),
59 myHasMipmaps (Standard_False),
60 myParams (theParams)
61{
62 if (myParams.IsNull())
63 {
64 myParams = new Graphic3d_TextureParams();
65 }
66}
67
68// =======================================================================
69// function : ~OpenGl_Texture
70// purpose :
71// =======================================================================
72OpenGl_Texture::~OpenGl_Texture()
73{
74 Release (NULL);
75}
76
77// =======================================================================
78// function : HasMipmaps
79// purpose :
80// =======================================================================
81const Standard_Boolean OpenGl_Texture::HasMipmaps() const
82{
83 return myHasMipmaps;
84}
85
86// =======================================================================
87// function : GetParams
88// purpose :
89// =======================================================================
90const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const
91{
92 return myParams;
93}
94
95// =======================================================================
96// function : SetParams
97// purpose :
98// =======================================================================
99void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams)
100{
101 myParams = theParams;
102}
103
104// =======================================================================
105// function : Create
106// purpose :
107// =======================================================================
108bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& )
109{
110 if (myTextureId == NO_TEXTURE)
111 {
112 glGenTextures (1, &myTextureId);
113 }
114 return myTextureId != NO_TEXTURE;
115}
116
117// =======================================================================
118// function : Release
119// purpose :
120// =======================================================================
121void OpenGl_Texture::Release (const OpenGl_Context* theGlCtx)
122{
123 if (myTextureId == NO_TEXTURE)
124 {
125 return;
126 }
127
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...",);
131
ec2eeb2d 132 if (theGlCtx->IsValid())
133 {
134 glDeleteTextures (1, &myTextureId);
135 }
bf75be98 136 myTextureId = NO_TEXTURE;
137 mySizeX = mySizeY = 0;
138}
139
140// =======================================================================
141// function : Bind
142// purpose :
143// =======================================================================
144void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
145 const GLenum theTextureUnit) const
146{
147 if (theCtx->IsGlGreaterEqual (1, 3))
148 {
149 theCtx->core13->glActiveTexture (theTextureUnit);
150 }
151 glBindTexture (myTarget, myTextureId);
152}
153
154// =======================================================================
155// function : Unbind
156// purpose :
157// =======================================================================
158void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
159 const GLenum theTextureUnit) const
160{
161 if (theCtx->IsGlGreaterEqual (1, 3))
162 {
163 theCtx->core13->glActiveTexture (theTextureUnit);
164 }
165 glBindTexture (myTarget, NO_TEXTURE);
166}
167
168// =======================================================================
169// function : Init
170// purpose :
171// =======================================================================
172bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
173 const Image_PixMap& theImage,
174 const Graphic3d_TypeOfTexture theType)
175{
176 myHasMipmaps = Standard_False;
177 if (theImage.IsEmpty() || !Create (theCtx))
178 {
179 return false;
180 }
181
a577aaab 182 myTextFormat = GL_RGBA8;
183 GLenum aPixelFormat = 0;
184 GLenum aDataType = 0;
bf75be98 185 switch (theImage.Format())
186 {
187 case Image_PixMap::ImgGrayF:
188 {
a577aaab 189 myTextFormat = GL_ALPHA8; // GL_R8, GL_R32F
190 aPixelFormat = GL_ALPHA; // GL_RED
191 aDataType = GL_FLOAT;
bf75be98 192 break;
193 }
194 case Image_PixMap::ImgRGBAF:
195 {
a577aaab 196 myTextFormat = GL_RGBA8; // GL_RGBA32F
197 aPixelFormat = GL_RGBA;
198 aDataType = GL_FLOAT;
bf75be98 199 break;
200 }
201 case Image_PixMap::ImgBGRAF:
202 {
203 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
204 {
205 return false;
206 }
a577aaab 207 myTextFormat = GL_RGBA8; // GL_RGBA32F
208 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
209 aDataType = GL_FLOAT;
bf75be98 210 break;
211 }
212 case Image_PixMap::ImgRGBF:
213 {
a577aaab 214 myTextFormat = GL_RGB8; // GL_RGB32F
215 aPixelFormat = GL_RGB;
216 aDataType = GL_FLOAT;
bf75be98 217 break;
218 }
219 case Image_PixMap::ImgBGRF:
220 {
a577aaab 221 myTextFormat = GL_RGB8; // GL_RGB32F
222 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
223 aDataType = GL_FLOAT;
bf75be98 224 break;
225 }
226 case Image_PixMap::ImgRGBA:
227 {
a577aaab 228 myTextFormat = GL_RGBA8;
229 aPixelFormat = GL_RGBA;
230 aDataType = GL_UNSIGNED_BYTE;
bf75be98 231 break;
232 }
233 case Image_PixMap::ImgBGRA:
234 {
235 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
236 {
237 return false;
238 }
a577aaab 239 myTextFormat = GL_RGBA8;
240 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
241 aDataType = GL_UNSIGNED_BYTE;
bf75be98 242 break;
243 }
244 case Image_PixMap::ImgRGB32:
245 {
a577aaab 246 myTextFormat = GL_RGB8;
247 aPixelFormat = GL_RGBA;
248 aDataType = GL_UNSIGNED_BYTE;
bf75be98 249 break;
250 }
251 case Image_PixMap::ImgBGR32:
252 {
253 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
254 {
255 return false;
256 }
a577aaab 257 myTextFormat = GL_RGB8;
258 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
259 aDataType = GL_UNSIGNED_BYTE;
bf75be98 260 break;
261 }
262 case Image_PixMap::ImgRGB:
263 {
a577aaab 264 myTextFormat = GL_RGB8;
265 aPixelFormat = GL_RGB;
266 aDataType = GL_UNSIGNED_BYTE;
bf75be98 267 break;
268 }
269 case Image_PixMap::ImgBGR:
270 {
271 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
272 {
273 return false;
274 }
a577aaab 275 myTextFormat = GL_RGB8;
276 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
277 aDataType = GL_UNSIGNED_BYTE;
bf75be98 278 break;
279 }
280 case Image_PixMap::ImgGray:
281 {
a577aaab 282 myTextFormat = GL_ALPHA8; // GL_R8
283 aPixelFormat = GL_ALPHA; // GL_RED
284 aDataType = GL_UNSIGNED_BYTE;
bf75be98 285 break;
286 }
287 default:
288 {
289 return false;
290 }
291 }
292
293 const GLsizei aMaxSize = theCtx->MaxTextureSize();
294 const GLsizei aWidth = (GLsizei )theImage.SizeX();
295 const GLsizei aHeight = (GLsizei )theImage.SizeY();
296
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;
a174a3c5 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);
bf75be98 304
305 GLint aTestWidth = 0;
306 GLint aTestHeight = 0;
307
74706083 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);
312
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);
317
bf75be98 318 switch (theType)
319 {
320 case Graphic3d_TOT_1D:
321 {
322 myTarget = GL_TEXTURE_1D;
323 Bind (theCtx);
324 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
325 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
326
327 Image_PixMap aCopy;
328 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
329 if (aWidth != aWidthOut)
330 {
74706083 331 glPixelStorei (GL_PACK_ALIGNMENT, 1);
332 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
bf75be98 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)
337 {
338 Unbind (theCtx);
339 return false;
340 }
341
342 aDataPtr = (GLvoid* )aCopy.Data();
74706083 343 anUnpackSentry.Reset();
bf75be98 344 }
345
346 // use proxy to check texture could be created or not
a577aaab 347 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, myTextFormat,
bf75be98 348 aWidthOut, 0,
349 aPixelFormat, aDataType, NULL);
350 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
351 if (aTestWidth == 0)
352 {
353 // no memory or broken input parameters
354 Unbind (theCtx);
355 return false;
356 }
357
a577aaab 358 glTexImage1D (GL_TEXTURE_1D, 0, myTextFormat,
bf75be98 359 aWidthOut, 0,
360 aPixelFormat, aDataType, aDataPtr);
a174a3c5 361 if (glGetError() != GL_NO_ERROR)
362 {
363 Unbind (theCtx);
364 return false;
365 }
366
367 mySizeX = aWidthOut;
368 mySizeY = 1;
bf75be98 369
370 Unbind (theCtx);
371 return true;
372 }
373 case Graphic3d_TOT_2D:
374 {
375 myTarget = GL_TEXTURE_2D;
376 Bind (theCtx);
377 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
378 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
379
380 Image_PixMap aCopy;
381 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
382 if (aWidth != aWidthOut || aHeight != aHeightOut)
383 {
384 // scale texture
74706083 385 glPixelStorei (GL_PACK_ALIGNMENT, 1);
386 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
bf75be98 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)
391 {
392 Unbind (theCtx);
393 return false;
394 }
395
396 aDataPtr = (GLvoid* )aCopy.Data();
74706083 397 anUnpackSentry.Reset();
bf75be98 398 }
399
400 // use proxy to check texture could be created or not
a577aaab 401 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
bf75be98 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)
407 {
408 // no memory or broken input parameters
409 Unbind (theCtx);
410 return false;
411 }
412
a577aaab 413 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
bf75be98 414 aWidthOut, aHeightOut, 0,
415 aPixelFormat, aDataType, aDataPtr);
a174a3c5 416 if (glGetError() != GL_NO_ERROR)
417 {
418 Unbind (theCtx);
419 return false;
420 }
421
422 mySizeX = aWidthOut;
423 mySizeY = aHeightOut;
bf75be98 424
425 Unbind (theCtx);
426 return true;
427 }
428 case Graphic3d_TOT_2D_MIPMAP:
429 {
430 myTarget = GL_TEXTURE_2D;
431 myHasMipmaps = Standard_True;
432 Bind (theCtx);
433 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
434 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
435
1a7dfdb7 436 if (theCtx->extFBO != NULL
437 && aWidth == aWidthOut && aHeight == aHeightOut)
438 {
439 // use proxy to check texture could be created or not
a577aaab 440 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
1a7dfdb7 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)
446 {
447 // no memory or broken input parameters
448 Unbind (theCtx);
449 return false;
450 }
451
452 // upload main picture
a577aaab 453 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
1a7dfdb7 454 aWidthOut, aHeightOut, 0,
455 aPixelFormat, aDataType, theImage.Data());
a174a3c5 456 if (glGetError() != GL_NO_ERROR)
457 {
458 Unbind (theCtx);
459 return false;
460 }
461
462 mySizeX = aWidthOut;
463 mySizeY = aHeightOut;
1a7dfdb7 464
465 // generate mipmaps
466 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
467 theCtx->extFBO->glGenerateMipmapEXT (GL_TEXTURE_2D);
468
469 Unbind (theCtx);
470 return true;
471 }
472 else
473 {
a577aaab 474 bool isCreated = gluBuild2DMipmaps (GL_TEXTURE_2D, myTextFormat,
1a7dfdb7 475 aWidth, aHeight,
476 aPixelFormat, aDataType, theImage.Data()) == 0;
a174a3c5 477 if (isCreated)
478 {
479 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &mySizeX);
480 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &mySizeY);
481 }
482
1a7dfdb7 483 Unbind (theCtx);
484 return isCreated;
485 }
bf75be98 486 }
487 default:
488 {
489 return false;
490 }
491 }
492}