0024530: TKMesh - remove unused package IntPoly
[occt.git] / src / OpenGl / OpenGl_Texture.cxx
CommitLineData
bf75be98 1// Created by: Kirill GAVRILOV
973c2be1 2// Copyright (c) 2014 OPEN CASCADE SAS
bf75be98 3//
973c2be1 4// This file is part of Open CASCADE Technology software library.
bf75be98 5//
973c2be1 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.
bf75be98 11//
973c2be1 12// Alternatively, this file may be used under the terms of Open CASCADE
13// commercial license or contractual agreement.
bf75be98 14
15#include <OpenGl_Texture.hxx>
16
1a7dfdb7 17#include <OpenGl_ExtFBO.hxx>
bf75be98 18#include <OpenGl_Context.hxx>
19#include <Graphic3d_TextureParams.hxx>
20#include <Standard_Assert.hxx>
21#include <Image_PixMap.hxx>
22
23IMPLEMENT_STANDARD_HANDLE (OpenGl_Texture, OpenGl_Resource)
24IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_Resource)
25
74706083 26//! Simple class to reset unpack alignment settings
27struct OpenGl_UnpackAlignmentSentry
28{
29
30 //! Reset unpack alignment settings to safe values
31 void Reset()
32 {
33 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
34 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
35 }
36
37 ~OpenGl_UnpackAlignmentSentry()
38 {
39 Reset();
40 }
41
42};
43
bf75be98 44// =======================================================================
45// function : OpenGl_Texture
46// purpose :
47// =======================================================================
48OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams)
49: OpenGl_Resource(),
50 myTextureId (NO_TEXTURE),
51 myTarget (GL_TEXTURE_2D),
52 mySizeX (0),
53 mySizeY (0),
54 myTextFormat (GL_FLOAT),
55 myHasMipmaps (Standard_False),
56 myParams (theParams)
57{
58 if (myParams.IsNull())
59 {
60 myParams = new Graphic3d_TextureParams();
61 }
62}
63
64// =======================================================================
65// function : ~OpenGl_Texture
66// purpose :
67// =======================================================================
68OpenGl_Texture::~OpenGl_Texture()
69{
70 Release (NULL);
71}
72
73// =======================================================================
74// function : HasMipmaps
75// purpose :
76// =======================================================================
77const Standard_Boolean OpenGl_Texture::HasMipmaps() const
78{
79 return myHasMipmaps;
80}
81
82// =======================================================================
83// function : GetParams
84// purpose :
85// =======================================================================
86const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const
87{
88 return myParams;
89}
90
91// =======================================================================
92// function : SetParams
93// purpose :
94// =======================================================================
95void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams)
96{
97 myParams = theParams;
98}
99
100// =======================================================================
101// function : Create
102// purpose :
103// =======================================================================
104bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& )
105{
106 if (myTextureId == NO_TEXTURE)
107 {
108 glGenTextures (1, &myTextureId);
109 }
110 return myTextureId != NO_TEXTURE;
111}
112
113// =======================================================================
114// function : Release
115// purpose :
116// =======================================================================
117void OpenGl_Texture::Release (const OpenGl_Context* theGlCtx)
118{
119 if (myTextureId == NO_TEXTURE)
120 {
121 return;
122 }
123
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...",);
127
ec2eeb2d 128 if (theGlCtx->IsValid())
129 {
130 glDeleteTextures (1, &myTextureId);
131 }
bf75be98 132 myTextureId = NO_TEXTURE;
133 mySizeX = mySizeY = 0;
134}
135
136// =======================================================================
137// function : Bind
138// purpose :
139// =======================================================================
140void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
141 const GLenum theTextureUnit) const
142{
143 if (theCtx->IsGlGreaterEqual (1, 3))
144 {
145 theCtx->core13->glActiveTexture (theTextureUnit);
146 }
147 glBindTexture (myTarget, myTextureId);
148}
149
150// =======================================================================
151// function : Unbind
152// purpose :
153// =======================================================================
154void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
155 const GLenum theTextureUnit) const
156{
157 if (theCtx->IsGlGreaterEqual (1, 3))
158 {
159 theCtx->core13->glActiveTexture (theTextureUnit);
160 }
161 glBindTexture (myTarget, NO_TEXTURE);
162}
163
164// =======================================================================
165// function : Init
166// purpose :
167// =======================================================================
168bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
169 const Image_PixMap& theImage,
170 const Graphic3d_TypeOfTexture theType)
171{
172 myHasMipmaps = Standard_False;
173 if (theImage.IsEmpty() || !Create (theCtx))
174 {
175 return false;
176 }
177
a577aaab 178 myTextFormat = GL_RGBA8;
179 GLenum aPixelFormat = 0;
180 GLenum aDataType = 0;
bf75be98 181 switch (theImage.Format())
182 {
183 case Image_PixMap::ImgGrayF:
184 {
a577aaab 185 myTextFormat = GL_ALPHA8; // GL_R8, GL_R32F
186 aPixelFormat = GL_ALPHA; // GL_RED
187 aDataType = GL_FLOAT;
bf75be98 188 break;
189 }
190 case Image_PixMap::ImgRGBAF:
191 {
a577aaab 192 myTextFormat = GL_RGBA8; // GL_RGBA32F
193 aPixelFormat = GL_RGBA;
194 aDataType = GL_FLOAT;
bf75be98 195 break;
196 }
197 case Image_PixMap::ImgBGRAF:
198 {
199 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
200 {
201 return false;
202 }
a577aaab 203 myTextFormat = GL_RGBA8; // GL_RGBA32F
204 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
205 aDataType = GL_FLOAT;
bf75be98 206 break;
207 }
208 case Image_PixMap::ImgRGBF:
209 {
a577aaab 210 myTextFormat = GL_RGB8; // GL_RGB32F
211 aPixelFormat = GL_RGB;
212 aDataType = GL_FLOAT;
bf75be98 213 break;
214 }
215 case Image_PixMap::ImgBGRF:
216 {
a577aaab 217 myTextFormat = GL_RGB8; // GL_RGB32F
218 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
219 aDataType = GL_FLOAT;
bf75be98 220 break;
221 }
222 case Image_PixMap::ImgRGBA:
223 {
a577aaab 224 myTextFormat = GL_RGBA8;
225 aPixelFormat = GL_RGBA;
226 aDataType = GL_UNSIGNED_BYTE;
bf75be98 227 break;
228 }
229 case Image_PixMap::ImgBGRA:
230 {
231 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
232 {
233 return false;
234 }
a577aaab 235 myTextFormat = GL_RGBA8;
236 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
237 aDataType = GL_UNSIGNED_BYTE;
bf75be98 238 break;
239 }
240 case Image_PixMap::ImgRGB32:
241 {
a577aaab 242 myTextFormat = GL_RGB8;
243 aPixelFormat = GL_RGBA;
244 aDataType = GL_UNSIGNED_BYTE;
bf75be98 245 break;
246 }
247 case Image_PixMap::ImgBGR32:
248 {
249 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
250 {
251 return false;
252 }
a577aaab 253 myTextFormat = GL_RGB8;
254 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
255 aDataType = GL_UNSIGNED_BYTE;
bf75be98 256 break;
257 }
258 case Image_PixMap::ImgRGB:
259 {
a577aaab 260 myTextFormat = GL_RGB8;
261 aPixelFormat = GL_RGB;
262 aDataType = GL_UNSIGNED_BYTE;
bf75be98 263 break;
264 }
265 case Image_PixMap::ImgBGR:
266 {
267 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
268 {
269 return false;
270 }
a577aaab 271 myTextFormat = GL_RGB8;
272 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
273 aDataType = GL_UNSIGNED_BYTE;
bf75be98 274 break;
275 }
276 case Image_PixMap::ImgGray:
277 {
a577aaab 278 myTextFormat = GL_ALPHA8; // GL_R8
279 aPixelFormat = GL_ALPHA; // GL_RED
280 aDataType = GL_UNSIGNED_BYTE;
bf75be98 281 break;
282 }
283 default:
284 {
285 return false;
286 }
287 }
288
289 const GLsizei aMaxSize = theCtx->MaxTextureSize();
290 const GLsizei aWidth = (GLsizei )theImage.SizeX();
291 const GLsizei aHeight = (GLsizei )theImage.SizeY();
292
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!
68333c8f 295 // Trying to create NPOT textures on such hardware will not fail
bf75be98 296 // but driver will fall back into software rendering,
297 const bool toForceP2 = !theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW;
a174a3c5 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);
bf75be98 300
301 GLint aTestWidth = 0;
302 GLint aTestHeight = 0;
303
74706083 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);
308
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);
313
bf75be98 314 switch (theType)
315 {
316 case Graphic3d_TOT_1D:
317 {
318 myTarget = GL_TEXTURE_1D;
319 Bind (theCtx);
320 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
321 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
322
323 Image_PixMap aCopy;
324 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
325 if (aWidth != aWidthOut)
326 {
74706083 327 glPixelStorei (GL_PACK_ALIGNMENT, 1);
328 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
bf75be98 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)
333 {
334 Unbind (theCtx);
335 return false;
336 }
337
338 aDataPtr = (GLvoid* )aCopy.Data();
74706083 339 anUnpackSentry.Reset();
bf75be98 340 }
341
342 // use proxy to check texture could be created or not
a577aaab 343 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, myTextFormat,
bf75be98 344 aWidthOut, 0,
345 aPixelFormat, aDataType, NULL);
346 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
347 if (aTestWidth == 0)
348 {
349 // no memory or broken input parameters
350 Unbind (theCtx);
351 return false;
352 }
353
a577aaab 354 glTexImage1D (GL_TEXTURE_1D, 0, myTextFormat,
bf75be98 355 aWidthOut, 0,
356 aPixelFormat, aDataType, aDataPtr);
a174a3c5 357 if (glGetError() != GL_NO_ERROR)
358 {
359 Unbind (theCtx);
360 return false;
361 }
362
363 mySizeX = aWidthOut;
364 mySizeY = 1;
bf75be98 365
366 Unbind (theCtx);
367 return true;
368 }
369 case Graphic3d_TOT_2D:
370 {
371 myTarget = GL_TEXTURE_2D;
372 Bind (theCtx);
373 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
374 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
375
376 Image_PixMap aCopy;
377 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
378 if (aWidth != aWidthOut || aHeight != aHeightOut)
379 {
380 // scale texture
74706083 381 glPixelStorei (GL_PACK_ALIGNMENT, 1);
382 glPixelStorei (GL_PACK_ROW_LENGTH, 0);
bf75be98 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)
387 {
388 Unbind (theCtx);
389 return false;
390 }
391
392 aDataPtr = (GLvoid* )aCopy.Data();
74706083 393 anUnpackSentry.Reset();
bf75be98 394 }
395
396 // use proxy to check texture could be created or not
a577aaab 397 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
bf75be98 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)
403 {
404 // no memory or broken input parameters
405 Unbind (theCtx);
406 return false;
407 }
408
a577aaab 409 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
bf75be98 410 aWidthOut, aHeightOut, 0,
411 aPixelFormat, aDataType, aDataPtr);
a174a3c5 412 if (glGetError() != GL_NO_ERROR)
413 {
414 Unbind (theCtx);
415 return false;
416 }
417
418 mySizeX = aWidthOut;
419 mySizeY = aHeightOut;
bf75be98 420
421 Unbind (theCtx);
422 return true;
423 }
424 case Graphic3d_TOT_2D_MIPMAP:
425 {
426 myTarget = GL_TEXTURE_2D;
427 myHasMipmaps = Standard_True;
428 Bind (theCtx);
429 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
430 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
431
1a7dfdb7 432 if (theCtx->extFBO != NULL
433 && aWidth == aWidthOut && aHeight == aHeightOut)
434 {
435 // use proxy to check texture could be created or not
a577aaab 436 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
1a7dfdb7 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)
442 {
443 // no memory or broken input parameters
444 Unbind (theCtx);
445 return false;
446 }
447
448 // upload main picture
a577aaab 449 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
1a7dfdb7 450 aWidthOut, aHeightOut, 0,
451 aPixelFormat, aDataType, theImage.Data());
a174a3c5 452 if (glGetError() != GL_NO_ERROR)
453 {
454 Unbind (theCtx);
455 return false;
456 }
457
458 mySizeX = aWidthOut;
459 mySizeY = aHeightOut;
1a7dfdb7 460
461 // generate mipmaps
462 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
463 theCtx->extFBO->glGenerateMipmapEXT (GL_TEXTURE_2D);
464
465 Unbind (theCtx);
466 return true;
467 }
468 else
469 {
a577aaab 470 bool isCreated = gluBuild2DMipmaps (GL_TEXTURE_2D, myTextFormat,
1a7dfdb7 471 aWidth, aHeight,
472 aPixelFormat, aDataType, theImage.Data()) == 0;
a174a3c5 473 if (isCreated)
474 {
475 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &mySizeX);
476 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &mySizeY);
477 }
478
1a7dfdb7 479 Unbind (theCtx);
480 return isCreated;
481 }
bf75be98 482 }
483 default:
484 {
485 return false;
486 }
487 }
488}
68333c8f 489
490// =======================================================================
491// function : InitRectangle
492// purpose :
493// =======================================================================
494bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
495 const Standard_Integer theSizeX,
496 const Standard_Integer theSizeY,
497 const OpenGl_TextureFormat& theFormat)
498{
499 if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
500 {
501 return false;
502 }
503
504 myTarget = GL_TEXTURE_RECTANGLE;
505
506 const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
507 const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
508
509 Bind (theCtx);
510
511 if (myParams->Filter() == Graphic3d_TOTF_NEAREST)
512 {
513 glTexParameteri (myTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
514 glTexParameteri (myTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
515 }
516 else
517 {
518 glTexParameteri (myTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
519 glTexParameteri (myTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
520 }
521
522 myTextFormat = theFormat.Internal();
523
524 glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE,
525 0,
526 myTextFormat,
527 aSizeX,
528 aSizeY,
529 0,
530 theFormat.Format(),
531 GL_FLOAT,
532 NULL);
533
534 GLint aTestSizeX = 0;
535 GLint aTestSizeY = 0;
536
537 glGetTexLevelParameteriv (
538 GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
539 glGetTexLevelParameteriv (
540 GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
541
542 if (aTestSizeX == 0 || aTestSizeY == 0)
543 {
544 Unbind (theCtx);
545 return false;
546 }
547
548 glTexImage2D (myTarget,
549 0,
550 myTextFormat,
551 aSizeX,
552 aSizeY,
553 0,
554 theFormat.Format(),
555 GL_FLOAT,
556 NULL);
557
558 if (glGetError() != GL_NO_ERROR)
559 {
560 Unbind (theCtx);
561 return false;
562 }
563
564 mySizeX = aSizeX;
565 mySizeY = aSizeY;
566
567 Unbind (theCtx);
568 return true;
569}