0030700: Visualization, TKOpenGl - support PBR Metallic-Roughness shading model
[occt.git] / src / OpenGl / OpenGl_Texture.cxx
CommitLineData
bf75be98 1// Created by: Kirill GAVRILOV
d5f74e42 2// Copyright (c) 2013-2014 OPEN CASCADE SAS
bf75be98 3//
973c2be1 4// This file is part of Open CASCADE Technology software library.
bf75be98 5//
d5f74e42 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
973c2be1 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
01ca42b2 17#include <OpenGl_ArbFBO.hxx>
bf75be98 18#include <OpenGl_Context.hxx>
3c4b62a4 19#include <OpenGl_GlCore32.hxx>
cc8cbabe 20#include <OpenGl_Sampler.hxx>
bf75be98 21#include <Graphic3d_TextureParams.hxx>
fa4dcbe0 22#include <TCollection_ExtendedString.hxx>
bf75be98 23#include <Standard_Assert.hxx>
24#include <Image_PixMap.hxx>
25
cc8cbabe 26IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_NamedResource)
92efcf78 27
74706083 28//! Simple class to reset unpack alignment settings
29struct OpenGl_UnpackAlignmentSentry
30{
31
32 //! Reset unpack alignment settings to safe values
90fd6145 33 static void Reset()
74706083 34 {
35 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
ca3c13d1 36 #if !defined(GL_ES_VERSION_2_0)
74706083 37 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
ca3c13d1 38 #endif
74706083 39 }
40
90fd6145 41 OpenGl_UnpackAlignmentSentry() {}
42
74706083 43 ~OpenGl_UnpackAlignmentSentry()
44 {
45 Reset();
46 }
47
48};
49
bf75be98 50// =======================================================================
51// function : OpenGl_Texture
52// purpose :
53// =======================================================================
cc8cbabe 54OpenGl_Texture::OpenGl_Texture (const TCollection_AsciiString& theResourceId,
55 const Handle(Graphic3d_TextureParams)& theParams)
56: OpenGl_NamedResource (theResourceId),
57 mySampler (new OpenGl_Sampler (theParams)),
d2edda76 58 myRevision (0),
bf75be98 59 myTextureId (NO_TEXTURE),
60 myTarget (GL_TEXTURE_2D),
61 mySizeX (0),
62 mySizeY (0),
74fb257d 63 mySizeZ (0),
8625ef7e 64 myTextFormat (GL_RGBA),
15669413 65 mySizedFormat(GL_RGBA8),
66 myNbSamples (1),
bf75be98 67 myHasMipmaps (Standard_False),
cc8cbabe 68 myIsAlpha (false)
bf75be98 69{
cc8cbabe 70 //
bf75be98 71}
72
73// =======================================================================
74// function : ~OpenGl_Texture
75// purpose :
76// =======================================================================
77OpenGl_Texture::~OpenGl_Texture()
78{
79 Release (NULL);
80}
81
bf75be98 82// =======================================================================
83// function : Create
84// purpose :
85// =======================================================================
cc8cbabe 86bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& theCtx)
bf75be98 87{
cc8cbabe 88 if (myTextureId != NO_TEXTURE)
89 {
90 return true;
91 }
92
93 theCtx->core11fwd->glGenTextures (1, &myTextureId);
bf75be98 94 if (myTextureId == NO_TEXTURE)
95 {
cc8cbabe 96 return false;
bf75be98 97 }
cc8cbabe 98
99 //mySampler->Create (theCtx); // do not create sampler object by default
100 return true;
bf75be98 101}
102
103// =======================================================================
104// function : Release
105// purpose :
106// =======================================================================
10b9c7df 107void OpenGl_Texture::Release (OpenGl_Context* theGlCtx)
bf75be98 108{
cc8cbabe 109 mySampler->Release (theGlCtx);
bf75be98 110 if (myTextureId == NO_TEXTURE)
111 {
112 return;
113 }
114
115 // application can not handle this case by exception - this is bug in code
116 Standard_ASSERT_RETURN (theGlCtx != NULL,
117 "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
118
ec2eeb2d 119 if (theGlCtx->IsValid())
120 {
121 glDeleteTextures (1, &myTextureId);
122 }
bf75be98 123 myTextureId = NO_TEXTURE;
d2edda76 124 mySizeX = mySizeY = mySizeZ = 0;
bf75be98 125}
126
cc8cbabe 127// =======================================================================
128// function : applyDefaultSamplerParams
129// purpose :
130// =======================================================================
131void OpenGl_Texture::applyDefaultSamplerParams (const Handle(OpenGl_Context)& theCtx)
132{
133 OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), NULL, myTarget, myHasMipmaps);
134 if (mySampler->IsValid() && !mySampler->IsImmutable())
135 {
136 OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), mySampler.get(), myTarget, myHasMipmaps);
137 }
138}
139
bf75be98 140// =======================================================================
141// function : Bind
142// purpose :
143// =======================================================================
144void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
cc8cbabe 145 const Graphic3d_TextureUnit theTextureUnit) const
bf75be98 146{
4e1523ef 147 if (theCtx->core15fwd != NULL)
bf75be98 148 {
cc8cbabe 149 theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
bf75be98 150 }
cc8cbabe 151 mySampler->Bind (theCtx, theTextureUnit);
bf75be98 152 glBindTexture (myTarget, myTextureId);
153}
154
155// =======================================================================
156// function : Unbind
157// purpose :
158// =======================================================================
159void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
cc8cbabe 160 const Graphic3d_TextureUnit theTextureUnit) const
bf75be98 161{
4e1523ef 162 if (theCtx->core15fwd != NULL)
bf75be98 163 {
cc8cbabe 164 theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit);
bf75be98 165 }
cc8cbabe 166 mySampler->Unbind (theCtx, theTextureUnit);
bf75be98 167 glBindTexture (myTarget, NO_TEXTURE);
168}
169
cc8cbabe 170//=======================================================================
171//function : InitSamplerObject
172//purpose :
173//=======================================================================
174bool OpenGl_Texture::InitSamplerObject (const Handle(OpenGl_Context)& theCtx)
175{
176 return myTextureId != NO_TEXTURE
177 && mySampler->Init (theCtx, *this);
178}
179
18f4e8e2 180// =======================================================================
181// function : Init
182// purpose :
183// =======================================================================
184bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
ba00aab7 185 const OpenGl_TextureFormat& theFormat,
186 const Graphic3d_Vec2i& theSizeXY,
18f4e8e2 187 const Graphic3d_TypeOfTexture theType,
188 const Image_PixMap* theImage)
189{
ba00aab7 190 if (theSizeXY.x() < 1
191 || theSizeXY.y() < 1)
66d1cdc6 192 {
193 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
194 "Error: texture of 0 size cannot be created.");
ba00aab7 195 Release (theCtx.get());
66d1cdc6 196 return false;
197 }
198
d2edda76 199#if !defined(GL_ES_VERSION_2_0)
200 const GLenum aTarget = theType == Graphic3d_TOT_1D
201 ? GL_TEXTURE_1D
202 : GL_TEXTURE_2D;
203#else
204 const GLenum aTarget = GL_TEXTURE_2D;
205#endif
206 const Standard_Boolean toCreateMipMaps = (theType == Graphic3d_TOT_2D_MIPMAP);
207 const bool toPatchExisting = IsValid()
ba00aab7 208 && myTextFormat == theFormat.PixelFormat()
d2edda76 209 && myTarget == aTarget
210 && myHasMipmaps == toCreateMipMaps
ba00aab7 211 && mySizeX == theSizeXY.x()
212 && (mySizeY == theSizeXY.y() || theType == Graphic3d_TOT_1D);
18f4e8e2 213 if (!Create (theCtx))
214 {
ba00aab7 215 Release (theCtx.get());
18f4e8e2 216 return false;
217 }
4e1523ef 218
219 if (theImage != NULL)
220 {
dc858f4c 221 myIsAlpha = theImage->Format() == Image_Format_Alpha
222 || theImage->Format() == Image_Format_AlphaF;
4e1523ef 223 }
224 else
225 {
ba00aab7 226 myIsAlpha = theFormat.PixelFormat() == GL_ALPHA;
4e1523ef 227 }
228
d2edda76 229 myHasMipmaps = toCreateMipMaps;
ba00aab7 230 myTextFormat = theFormat.PixelFormat();
231 mySizedFormat = theFormat.InternalFormat();
15669413 232 myNbSamples = 1;
8625ef7e 233#if !defined(GL_ES_VERSION_2_0)
ba00aab7 234 const GLint anIntFormat = theFormat.InternalFormat();
8625ef7e 235#else
a1073ae2 236 // ES 2.0 does not support sized formats and format conversions - them detected from data type
ba00aab7 237 const GLint anIntFormat = theCtx->IsGlGreaterEqual (3, 0) ? theFormat.InternalFormat() : theFormat.PixelFormat();
8625ef7e 238#endif
bf75be98 239
ba00aab7 240 if (theFormat.DataType() == GL_FLOAT
241 && !theCtx->arbTexFloat)
ff6665dc 242 {
243 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
244 "Error: floating-point textures are not supported by hardware.");
ba00aab7 245 Release (theCtx.get());
ff6665dc 246 return false;
247 }
248
d2edda76 249 const GLsizei aMaxSize = theCtx->MaxTextureSize();
ba00aab7 250 if (theSizeXY.x() > aMaxSize
251 || theSizeXY.y() > aMaxSize)
fa4dcbe0 252 {
ba00aab7 253 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
254 TCollection_AsciiString ("Error: Texture dimension - ") + theSizeXY.x() + "x" + theSizeXY.y()
255 + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")");
256 Release (theCtx.get());
fa4dcbe0 257 return false;
258 }
259#if !defined(GL_ES_VERSION_2_0)
260 else if (!theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW)
261 {
262 // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
263 // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
264 // Trying to create NPOT textures on such hardware will not fail
265 // but driver will fall back into software rendering,
ba00aab7 266 const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.x(), aMaxSize);
267 const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.y(), aMaxSize);
268 if (theSizeXY.x() != aWidthP2
269 || (theType != Graphic3d_TOT_1D && theSizeXY.y() != aHeightP2))
fa4dcbe0 270 {
ba00aab7 271 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
272 TCollection_AsciiString ("Error: NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")"
273 " are not supported by hardware.");
274 Release (theCtx.get());
fa4dcbe0 275 return false;
276 }
277 }
278#else
279 else if (!theCtx->IsGlGreaterEqual (3, 0) && theType == Graphic3d_TOT_2D_MIPMAP)
280 {
281 // Mipmap NPOT textures are not supported by OpenGL ES 2.0.
ba00aab7 282 const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.x(), aMaxSize);
283 const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.y(), aMaxSize);
284 if (theSizeXY.x() != aWidthP2
285 || theSizeXY.y() != aHeightP2)
fa4dcbe0 286 {
ba00aab7 287 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
288 TCollection_AsciiString ("Error: Mipmap NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")"
289 " are not supported by OpenGL ES 2.0");
290 Release (theCtx.get());
fa4dcbe0 291 return false;
292 }
293 }
294#endif
295
ca3c13d1 296#if !defined(GL_ES_VERSION_2_0)
bf75be98 297 GLint aTestWidth = 0;
298 GLint aTestHeight = 0;
ca3c13d1 299#endif
18f4e8e2 300 GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL;
bf75be98 301
74706083 302 // setup the alignment
303 OpenGl_UnpackAlignmentSentry anUnpackSentry;
fa4dcbe0 304 (void)anUnpackSentry; // avoid compiler warning
305
18f4e8e2 306 if (aDataPtr != NULL)
307 {
308 const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
309 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
74706083 310
ca3c13d1 311 #if !defined(GL_ES_VERSION_2_0)
18f4e8e2 312 // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
313 const GLint anExtraBytes = GLint(theImage->RowExtraBytes());
314 const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes());
315 glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
ca3c13d1 316 #endif
18f4e8e2 317 }
74706083 318
d2edda76 319 myTarget = aTarget;
bf75be98 320 switch (theType)
321 {
322 case Graphic3d_TOT_1D:
323 {
ca3c13d1 324 #if !defined(GL_ES_VERSION_2_0)
bf75be98 325 Bind (theCtx);
cc8cbabe 326 applyDefaultSamplerParams (theCtx);
d2edda76 327 if (toPatchExisting)
328 {
329 glTexSubImage1D (GL_TEXTURE_1D, 0, 0,
ba00aab7 330 theSizeXY.x(), theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
d2edda76 331 Unbind (theCtx);
332 return true;
333 }
bf75be98 334
bf75be98 335 // use proxy to check texture could be created or not
8625ef7e 336 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat,
ba00aab7 337 theSizeXY.x(), 0,
338 theFormat.PixelFormat(), theFormat.DataType(), NULL);
ff6665dc 339 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
15669413 340 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
bf75be98 341 if (aTestWidth == 0)
342 {
343 // no memory or broken input parameters
344 Unbind (theCtx);
18f4e8e2 345 Release (theCtx.operator->());
bf75be98 346 return false;
347 }
348
8625ef7e 349 glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat,
ba00aab7 350 theSizeXY.x(), 0,
351 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
a174a3c5 352 if (glGetError() != GL_NO_ERROR)
353 {
354 Unbind (theCtx);
ba00aab7 355 Release (theCtx.get());
a174a3c5 356 return false;
357 }
358
ba00aab7 359 mySizeX = theSizeXY.x();
a174a3c5 360 mySizeY = 1;
bf75be98 361
362 Unbind (theCtx);
363 return true;
ca3c13d1 364 #else
ff6665dc 365 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
366 "Error: 1D textures are not supported by hardware.");
ba00aab7 367 Release (theCtx.get());
ca3c13d1 368 return false;
369 #endif
bf75be98 370 }
371 case Graphic3d_TOT_2D:
372 {
bf75be98 373 Bind (theCtx);
cc8cbabe 374 applyDefaultSamplerParams (theCtx);
d2edda76 375 if (toPatchExisting)
376 {
377 glTexSubImage2D (GL_TEXTURE_2D, 0,
378 0, 0,
ba00aab7 379 theSizeXY.x(), theSizeXY.y(),
380 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
d2edda76 381 Unbind (theCtx);
382 return true;
383 }
bf75be98 384
ca3c13d1 385 #if !defined(GL_ES_VERSION_2_0)
bf75be98 386 // use proxy to check texture could be created or not
8625ef7e 387 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
ba00aab7 388 theSizeXY.x(), theSizeXY.y(), 0,
389 theFormat.PixelFormat(), theFormat.DataType(), NULL);
bf75be98 390 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
391 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
15669413 392 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
bf75be98 393 if (aTestWidth == 0 || aTestHeight == 0)
394 {
395 // no memory or broken input parameters
396 Unbind (theCtx);
ba00aab7 397 Release (theCtx.get());
bf75be98 398 return false;
399 }
ca3c13d1 400 #endif
bf75be98 401
8625ef7e 402 glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
ba00aab7 403 theSizeXY.x(), theSizeXY.y(), 0,
404 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
177781da 405 const GLenum anErr = glGetError();
406 if (anErr != GL_NO_ERROR)
a174a3c5 407 {
177781da 408 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
ba00aab7 409 TCollection_AsciiString ("Error: 2D texture ") + theSizeXY.x() + "x" + theSizeXY.y()
410 + " IF: " + int(anIntFormat) + " PF: " + int(theFormat.PixelFormat())
411 + " DT: " + int(theFormat.DataType())
177781da 412 + " can not be created with error " + int(anErr) + ".");
a174a3c5 413 Unbind (theCtx);
ba00aab7 414 Release (theCtx.get());
a174a3c5 415 return false;
416 }
417
ba00aab7 418 mySizeX = theSizeXY.x();
419 mySizeY = theSizeXY.y();
bf75be98 420
421 Unbind (theCtx);
422 return true;
423 }
424 case Graphic3d_TOT_2D_MIPMAP:
425 {
bf75be98 426 Bind (theCtx);
cc8cbabe 427 applyDefaultSamplerParams (theCtx);
d2edda76 428 if (toPatchExisting)
429 {
430 glTexSubImage2D (GL_TEXTURE_2D, 0,
431 0, 0,
ba00aab7 432 theSizeXY.x(), theSizeXY.y(),
433 theFormat.PixelFormat(), theFormat.DataType(), aDataPtr);
d2edda76 434 if (theCtx->arbFBO != NULL)
435 {
436 // generate mipmaps
437 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
438 if (glGetError() != GL_NO_ERROR)
439 {
440 Unbind (theCtx);
ba00aab7 441 Release (theCtx.get());
d2edda76 442 return false;
443 }
444 }
445
446 Unbind (theCtx);
447 return true;
448 }
bf75be98 449
fa4dcbe0 450 #if !defined(GL_ES_VERSION_2_0)
451 // use proxy to check texture could be created or not
452 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat,
ba00aab7 453 theSizeXY.x(), theSizeXY.y(), 0,
454 theFormat.PixelFormat(), theFormat.DataType(), NULL);
fa4dcbe0 455 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
456 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
15669413 457 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
fa4dcbe0 458 if (aTestWidth == 0 || aTestHeight == 0)
459 {
460 // no memory or broken input parameters
461 Unbind (theCtx);
ba00aab7 462 Release (theCtx.get());
fa4dcbe0 463 return false;
464 }
465 #endif
466
467 // upload main picture
468 glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat,
ba00aab7 469 theSizeXY.x(), theSizeXY.y(), 0,
470 theFormat.PixelFormat(), theFormat.DataType(), theImage->Data());
177781da 471 const GLenum aTexImgErr = glGetError();
472 if (aTexImgErr != GL_NO_ERROR)
1a7dfdb7 473 {
177781da 474 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
ba00aab7 475 TCollection_AsciiString ("Error: 2D texture ") + theSizeXY.x() + "x" + theSizeXY.y()
476 + " IF: " + int(anIntFormat) + " PF: " + int(theFormat.PixelFormat())
477 + " DT: " + int(theFormat.DataType())
177781da 478 + " can not be created with error " + int(aTexImgErr) + ".");
fa4dcbe0 479 Unbind (theCtx);
ba00aab7 480 Release (theCtx.get());
fa4dcbe0 481 return false;
482 }
483
ba00aab7 484 mySizeX = theSizeXY.x();
485 mySizeY = theSizeXY.y();
fa4dcbe0 486
487 if (theCtx->arbFBO != NULL)
488 {
489 // generate mipmaps
490 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
491 theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D);
1a7dfdb7 492
a174a3c5 493 if (glGetError() != GL_NO_ERROR)
494 {
495 Unbind (theCtx);
ba00aab7 496 Release (theCtx.get());
a174a3c5 497 return false;
498 }
1a7dfdb7 499 }
500 else
501 {
ba00aab7 502 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH,
503 "Warning: generating mipmaps requires GL_ARB_framebuffer_object extension which is missing.");
1a7dfdb7 504 Unbind (theCtx);
ba00aab7 505 Release (theCtx.get());
ca3c13d1 506 return false;
1a7dfdb7 507 }
fa4dcbe0 508
509 Unbind (theCtx);
510 return true;
bf75be98 511 }
077a220c 512 case Graphic3d_TOT_CUBEMAP:
513 {
514 Unbind (theCtx);
515 Release (theCtx.get());
516 return false;
517 }
bf75be98 518 }
d2edda76 519
ba00aab7 520 Release (theCtx.get());
d2edda76 521 return false;
bf75be98 522}
68333c8f 523
18f4e8e2 524// =======================================================================
525// function : Init
526// purpose :
527// =======================================================================
528bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
529 const Image_PixMap& theImage,
ba00aab7 530 const Graphic3d_TypeOfTexture theType,
531 const Standard_Boolean theIsColorMap)
18f4e8e2 532{
533 if (theImage.IsEmpty())
534 {
ba00aab7 535 Release (theCtx.get());
18f4e8e2 536 return false;
537 }
538
ba00aab7 539 const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theImage.Format(), theIsColorMap);
540 if (!aFormat.IsValid())
18f4e8e2 541 {
ba00aab7 542 Release (theCtx.get());
18f4e8e2 543 return false;
544 }
545
ba00aab7 546 return Init (theCtx, aFormat, Graphic3d_Vec2i ((Standard_Integer)theImage.SizeX(), (Standard_Integer)theImage.SizeY()),
18f4e8e2 547 theType, &theImage);
548}
549
077a220c 550// =======================================================================
551// function : Init
552// purpose :
553// =======================================================================
554bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
555 const Handle(Graphic3d_TextureMap)& theTextureMap)
556{
557 if (theTextureMap.IsNull())
558 {
559 return false;
560 }
561
562 switch (theTextureMap->Type())
563 {
564 case Graphic3d_TOT_CUBEMAP:
565 {
67312b79 566 return InitCubeMap (theCtx, Handle(Graphic3d_CubeMap)::DownCast(theTextureMap),
ba00aab7 567 0, Image_Format_RGB, false, theTextureMap->IsColorMap());
077a220c 568 }
569 default:
570 {
571 Handle(Image_PixMap) anImage = theTextureMap->GetImage();
572 if (anImage.IsNull())
573 {
574 return false;
575 }
ba00aab7 576 return Init (theCtx, *anImage, theTextureMap->Type(), theTextureMap->IsColorMap());
077a220c 577 }
578 }
579}
580
3c4b62a4 581// =======================================================================
582// function : Init2DMultisample
583// purpose :
584// =======================================================================
585bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx,
586 const GLsizei theNbSamples,
587 const GLint theTextFormat,
588 const GLsizei theSizeX,
589 const GLsizei theSizeY)
590{
591 if (!Create (theCtx)
592 || theNbSamples > theCtx->MaxMsaaSamples()
593 || theNbSamples < 1)
594 {
595 return false;
596 }
597
15669413 598 myNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples());
3c4b62a4 599 myTarget = GL_TEXTURE_2D_MULTISAMPLE;
15669413 600 myHasMipmaps = false;
3c4b62a4 601 if(theSizeX > theCtx->MaxTextureSize()
602 || theSizeY > theCtx->MaxTextureSize())
603 {
604 return false;
605 }
606
607 Bind (theCtx);
608 //myTextFormat = theTextFormat;
15669413 609 mySizedFormat = theTextFormat;
3c4b62a4 610#if !defined(GL_ES_VERSION_2_0)
611 if (theCtx->Functions()->glTexStorage2DMultisample != NULL)
612 {
15669413 613 theCtx->Functions()->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
3c4b62a4 614 }
615 else
616 {
15669413 617 theCtx->Functions()->glTexImage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
3c4b62a4 618 }
619#else
15669413 620 theCtx->Functions() ->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE);
3c4b62a4 621#endif
622 if (theCtx->core11fwd->glGetError() != GL_NO_ERROR)
623 {
624 Unbind (theCtx);
625 return false;
626 }
627
628 mySizeX = theSizeX;
629 mySizeY = theSizeY;
630
631 Unbind (theCtx);
632 return true;
633}
634
68333c8f 635// =======================================================================
636// function : InitRectangle
637// purpose :
638// =======================================================================
639bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx,
640 const Standard_Integer theSizeX,
641 const Standard_Integer theSizeY,
642 const OpenGl_TextureFormat& theFormat)
643{
644 if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0))
645 {
646 return false;
647 }
ca3c13d1 648
649#if !defined(GL_ES_VERSION_2_0)
68333c8f 650 myTarget = GL_TEXTURE_RECTANGLE;
15669413 651 myNbSamples = 1;
652 myHasMipmaps = false;
68333c8f 653
fe3a29bc 654 const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX);
655 const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY);
ca3c13d1 656
68333c8f 657 Bind (theCtx);
cc8cbabe 658 applyDefaultSamplerParams (theCtx);
68333c8f 659
15669413 660 myTextFormat = theFormat.Format();
661 mySizedFormat = theFormat.Internal();
68333c8f 662
90fd6145 663 // setup the alignment
664 OpenGl_UnpackAlignmentSentry::Reset();
665
15669413 666 glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE, 0, mySizedFormat,
667 aSizeX, aSizeY, 0,
668 myTextFormat, GL_FLOAT, NULL);
68333c8f 669
670 GLint aTestSizeX = 0;
671 GLint aTestSizeY = 0;
672
15669413 673 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX);
674 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY);
675 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
68333c8f 676
677 if (aTestSizeX == 0 || aTestSizeY == 0)
678 {
679 Unbind (theCtx);
680 return false;
681 }
682
15669413 683 glTexImage2D (myTarget, 0, mySizedFormat,
684 aSizeX, aSizeY, 0,
685 myTextFormat, GL_FLOAT, NULL);
68333c8f 686
687 if (glGetError() != GL_NO_ERROR)
688 {
689 Unbind (theCtx);
690 return false;
691 }
692
693 mySizeX = aSizeX;
694 mySizeY = aSizeY;
695
696 Unbind (theCtx);
697 return true;
ca3c13d1 698#else
20aeeb7b 699 (void )theSizeX;
700 (void )theSizeY;
701 (void )theFormat;
ca3c13d1 702 return false;
703#endif
68333c8f 704}
74fb257d 705
706// =======================================================================
707// function : Init3D
708// purpose :
709// =======================================================================
710bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx,
ba00aab7 711 const OpenGl_TextureFormat& theFormat,
712 const Graphic3d_Vec3i& theSizeXYZ,
74fb257d 713 const void* thePixels)
714{
715 if (theCtx->Functions()->glTexImage3D == NULL)
716 {
ba00aab7 717 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
718 "Error: three-dimensional textures are not supported by hardware.");
74fb257d 719 return false;
720 }
721
722 if (!Create(theCtx))
723 {
724 return false;
725 }
726
727 myTarget = GL_TEXTURE_3D;
15669413 728 myNbSamples = 1;
729 myHasMipmaps = false;
74fb257d 730
ba00aab7 731 const Graphic3d_Vec3i aSizeXYZ = theSizeXYZ.cwiseMin (Graphic3d_Vec3i (theCtx->MaxTextureSize()));
732 if (aSizeXYZ != theSizeXYZ)
733 {
734 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
735 "Error: 3D texture dimensions exceed hardware limits.");
736 Release (theCtx.get());
737 Unbind (theCtx);
738 return false;
739 }
74fb257d 740 Bind (theCtx);
741
ba00aab7 742 if (theFormat.DataType() == GL_FLOAT
743 && !theCtx->arbTexFloat)
74fb257d 744 {
ba00aab7 745 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
746 "Error: floating-point textures are not supported by hardware.");
747 Release (theCtx.get());
74fb257d 748 Unbind (theCtx);
749 return false;
750 }
751
ba00aab7 752 mySizedFormat = theFormat.InternalFormat();
74fb257d 753
90fd6145 754 // setup the alignment
755 OpenGl_UnpackAlignmentSentry::Reset();
756
74fb257d 757#if !defined (GL_ES_VERSION_2_0)
15669413 758 theCtx->core15fwd->glTexImage3D (GL_PROXY_TEXTURE_3D, 0, mySizedFormat,
ba00aab7 759 aSizeXYZ.x(), aSizeXYZ.y(), aSizeXYZ.z(), 0,
760 theFormat.PixelFormat(), theFormat.DataType(), NULL);
74fb257d 761
ba00aab7 762 NCollection_Vec3<GLint> aTestSizeXYZ;
763 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &aTestSizeXYZ.x());
764 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &aTestSizeXYZ.y());
765 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &aTestSizeXYZ.z());
15669413 766 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat);
ba00aab7 767 if (aTestSizeXYZ.x() == 0 || aTestSizeXYZ.y() == 0 || aTestSizeXYZ.z() == 0)
74fb257d 768 {
769 Unbind (theCtx);
ba00aab7 770 Release (theCtx.get());
74fb257d 771 return false;
772 }
773#endif
774
cc8cbabe 775 applyDefaultSamplerParams (theCtx);
15669413 776 theCtx->Functions()->glTexImage3D (myTarget, 0, mySizedFormat,
ba00aab7 777 aSizeXYZ.x(), aSizeXYZ.y(), aSizeXYZ.z(), 0,
778 theFormat.PixelFormat(), theFormat.DataType(), thePixels);
74fb257d 779
780 if (glGetError() != GL_NO_ERROR)
781 {
782 Unbind (theCtx);
ba00aab7 783 Release (theCtx.get());
74fb257d 784 return false;
785 }
786
ba00aab7 787 mySizeX = aSizeXYZ.x();
788 mySizeY = aSizeXYZ.y();
789 mySizeZ = aSizeXYZ.z();
74fb257d 790
791 Unbind (theCtx);
792 return true;
793}
15669413 794
077a220c 795// =======================================================================
67312b79 796// function : InitCubeMap
077a220c 797// purpose :
798// =======================================================================
67312b79 799bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)& theCtx,
077a220c 800 const Handle(Graphic3d_CubeMap)& theCubeMap,
ba00aab7 801 Standard_Size theSize,
802 Image_Format theFormat,
803 Standard_Boolean theToGenMipmap,
804 Standard_Boolean theIsColorMap)
077a220c 805{
806 if (!Create (theCtx))
807 {
808 Release (theCtx.get());
809 return false;
810 }
811
812 if (!theCubeMap.IsNull())
813 {
67312b79 814 theToGenMipmap = theCubeMap->HasMipmaps();
ba00aab7 815 if (Handle(Image_PixMap) anImage = theCubeMap->Reset().Value())
077a220c 816 {
817 theSize = anImage->SizeX();
818 theFormat = anImage->Format();
819 }
820 else
821 {
822 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
ba00aab7 823 "Unable to get the first side of cubemap");
077a220c 824 Release(theCtx.get());
825 return false;
826 }
827 }
828
ba00aab7 829 OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theFormat, theIsColorMap);
830 if (!aFormat.IsValid())
077a220c 831 {
832 Unbind(theCtx);
833 Release(theCtx.get());
834 return false;
835 }
836
837 myTarget = GL_TEXTURE_CUBE_MAP;
838 myHasMipmaps = theToGenMipmap;
839 myNbSamples = 1;
67312b79 840 mySizeX = (GLsizei )theSize;
841 mySizeY = (GLsizei )theSize;
077a220c 842 Bind (theCtx);
843 applyDefaultSamplerParams (theCtx);
844
845 for (Standard_Integer i = 0; i < 6; ++i)
846 {
847 const void* aData = NULL;
848 Handle(Image_PixMap) anImage;
849
850 if (!theCubeMap.IsNull())
851 {
852 anImage = theCubeMap->Value();
853 if (!anImage.IsNull())
854 {
855#if !defined(GL_ES_VERSION_2_0)
856 const GLint anAligment = Min ((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
857 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
858
859 // notice that GL_UNPACK_ROW_LENGTH is not available on OpenGL ES 2.0 without GL_EXT_unpack_subimage extension
860 const GLint anExtraBytes = GLint(anImage->RowExtraBytes());
861 const GLint aPixelsWidth = GLint(anImage->SizeRowBytes() / anImage->SizePixelBytes());
862 const GLint aRowLength = (anExtraBytes >= anAligment) ? aPixelsWidth : 0;
863 glPixelStorei (GL_UNPACK_ROW_LENGTH, aRowLength);
864#else
865 Handle(Image_PixMap) aCopyImage = new Image_PixMap();
866 aCopyImage->InitTrash (theFormat, theSize, theSize);
867 for (unsigned int y = 0; y < theSize; ++y)
868 {
869 for (unsigned int x = 0; x < theSize; ++x)
870 {
871 for (unsigned int aByte = 0; aByte < anImage->SizePixelBytes(); ++aByte)
872 {
873 aCopyImage->ChangeRawValue (y, x)[aByte] = anImage->RawValue (y, x)[aByte];
874 }
875 }
876 }
877 anImage = aCopyImage;
878 const GLint anAligment = Min((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes
879 glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment);
880#endif
881 aData = anImage->Data();
882 }
883 else
884 {
ba00aab7 885 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
886 TCollection_AsciiString() + "Unable to get [" + i + "] side of cubemap");
077a220c 887 Unbind (theCtx);
888 Release (theCtx.get());
889 return false;
890 }
891 theCubeMap->Next();
892 }
893
894 glTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0,
ba00aab7 895 aFormat.InternalFormat(),
077a220c 896 GLsizei(theSize), GLsizei(theSize),
ba00aab7 897 0, aFormat.PixelFormat(), aFormat.DataType(),
077a220c 898 aData);
899
900 OpenGl_UnpackAlignmentSentry::Reset();
901
ba00aab7 902 const GLenum anErr = glGetError();
903 if (anErr != GL_NO_ERROR)
077a220c 904 {
905 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
ba00aab7 906 TCollection_AsciiString ("Unable to initialize side of cubemap. Error #") + int(anErr));
077a220c 907 Unbind (theCtx);
908 Release (theCtx.get());
909 return false;
910 }
911 }
912
913 if (theToGenMipmap && theCtx->arbFBO != NULL)
914 {
ba00aab7 915 theCtx->arbFBO->glGenerateMipmap (myTarget);
916 const GLenum anErr = glGetError();
917 if (anErr != GL_NO_ERROR)
918 {
919 theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
920 TCollection_AsciiString ("Unable to generate mipmap of cubemap. Error #") + int(anErr));
921 Unbind (theCtx);
922 Release (theCtx.get());
923 return false;
924 }
077a220c 925 }
926
927 Unbind (theCtx.get());
928 return true;
929}
930
15669413 931// =======================================================================
932// function : PixelSizeOfPixelFormat
933// purpose :
934// =======================================================================
935Standard_Size OpenGl_Texture::PixelSizeOfPixelFormat (Standard_Integer theInternalFormat)
936{
937 switch(theInternalFormat)
938 {
939 // RED variations (GL_RED, OpenGL 3.0+)
940 case GL_RED:
941 case GL_R8: return 1;
942 case GL_R16: return 2;
943 case GL_R16F: return 2;
944 case GL_R32F: return 4;
945 // RGB variations
946 case GL_RGB: return 3;
947 case GL_RGB8: return 3;
948 case GL_RGB16: return 6;
949 case GL_RGB16F: return 6;
950 case GL_RGB32F: return 12;
951 // RGBA variations
952 case GL_RGBA: return 4;
953 case GL_RGBA8: return 4;
954 case GL_RGB10_A2: return 4;
955 case GL_RGBA12: return 6;
956 case GL_RGBA16: return 8;
957 case GL_RGBA16F: return 8;
958 case GL_RGBA32F: return 16;
959 //
960 case GL_BGRA_EXT: return 4;
961 // ALPHA variations (deprecated)
962 case GL_ALPHA:
963 case GL_ALPHA8: return 1;
964 case GL_ALPHA16: return 2;
965 case GL_LUMINANCE: return 1;
966 case GL_LUMINANCE_ALPHA: return 2;
967 // depth-stencil
968 case GL_DEPTH24_STENCIL8: return 4;
969 case GL_DEPTH32F_STENCIL8: return 8;
970 case GL_DEPTH_COMPONENT16: return 2;
971 case GL_DEPTH_COMPONENT24: return 3;
972 case GL_DEPTH_COMPONENT32F: return 4;
973 }
974 return 0;
975}
976
977// =======================================================================
978// function : EstimatedDataSize
979// purpose :
980// =======================================================================
981Standard_Size OpenGl_Texture::EstimatedDataSize() const
982{
983 if (!IsValid())
984 {
985 return 0;
986 }
987
988 Standard_Size aSize = PixelSizeOfPixelFormat (mySizedFormat) * mySizeX * myNbSamples;
989 if (mySizeY != 0)
990 {
991 aSize *= Standard_Size(mySizeY);
992 }
993 if (mySizeZ != 0)
994 {
995 aSize *= Standard_Size(mySizeZ);
996 }
67312b79 997 if (myTarget == GL_TEXTURE_CUBE_MAP)
998 {
999 aSize *= 6; // cube sides
1000 }
15669413 1001 if (myHasMipmaps)
1002 {
1003 aSize = aSize + aSize / 3;
1004 }
1005 return aSize;
1006}