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> |
8f8fe4a9 |
19 | #include <OpenGl_GlCore45.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> |
faff3767 |
24 | #include <Image_CompressedPixMap.hxx> |
bf75be98 |
25 | #include <Image_PixMap.hxx> |
faff3767 |
26 | #include <Image_SupportedFormats.hxx> |
bf75be98 |
27 | |
e1d17ceb |
28 | #include <algorithm> |
29 | |
cc8cbabe |
30 | IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_NamedResource) |
92efcf78 |
31 | |
faff3767 |
32 | namespace |
33 | { |
34 | |
74706083 |
35 | //! Simple class to reset unpack alignment settings |
36 | struct OpenGl_UnpackAlignmentSentry |
37 | { |
74706083 |
38 | //! Reset unpack alignment settings to safe values |
e1d17ceb |
39 | static void Reset (const OpenGl_Context& theCtx) |
74706083 |
40 | { |
e1d17ceb |
41 | theCtx.core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, 1); |
42 | if (theCtx.hasUnpackRowLength) |
43 | { |
44 | theCtx.core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); |
45 | } |
74706083 |
46 | } |
47 | |
e1d17ceb |
48 | OpenGl_UnpackAlignmentSentry (const Handle(OpenGl_Context)& theCtx) |
49 | : myCtx (theCtx.get()) {} |
90fd6145 |
50 | |
74706083 |
51 | ~OpenGl_UnpackAlignmentSentry() |
52 | { |
e1d17ceb |
53 | Reset (*myCtx); |
74706083 |
54 | } |
55 | |
e1d17ceb |
56 | private: |
57 | OpenGl_Context* myCtx; |
74706083 |
58 | }; |
59 | |
faff3767 |
60 | //! Compute the upper mipmap level for complete mipmap set (e.g. till the 1x1 level). |
61 | static Standard_Integer computeUpperMipMapLevel (Standard_Integer theSize) |
62 | { |
63 | for (Standard_Integer aMipIter = 0;; ++aMipIter, theSize /= 2) |
64 | { |
65 | if (theSize <= 1) |
66 | { |
67 | return aMipIter; |
68 | } |
69 | } |
70 | } |
71 | |
72 | //! Compute the upper mipmap level for complete mipmap set (e.g. till the 1x1 level). |
73 | static Standard_Integer computeUpperMipMapLevel (Standard_Integer theSizeX, Standard_Integer theSizeY) |
74 | { |
75 | return computeUpperMipMapLevel (Max (theSizeX, theSizeY)); |
76 | } |
77 | |
78 | //! Compute size of the smallest defined mipmap level (for verbose messages). |
79 | static Graphic3d_Vec2i computeSmallestMipMapSize (const Graphic3d_Vec2i& theBaseSize, Standard_Integer theMaxLevel) |
80 | { |
81 | Graphic3d_Vec2i aMipSizeXY = theBaseSize; |
82 | for (Standard_Integer aMipIter = 0;; ++aMipIter) |
83 | { |
84 | if (aMipIter > theMaxLevel) |
85 | { |
86 | return aMipSizeXY; |
87 | } |
88 | |
89 | aMipSizeXY /= 2; |
90 | if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; } |
91 | if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; } |
92 | } |
93 | } |
94 | |
95 | } |
96 | |
bf75be98 |
97 | // ======================================================================= |
98 | // function : OpenGl_Texture |
99 | // purpose : |
100 | // ======================================================================= |
cc8cbabe |
101 | OpenGl_Texture::OpenGl_Texture (const TCollection_AsciiString& theResourceId, |
102 | const Handle(Graphic3d_TextureParams)& theParams) |
103 | : OpenGl_NamedResource (theResourceId), |
104 | mySampler (new OpenGl_Sampler (theParams)), |
d2edda76 |
105 | myRevision (0), |
bf75be98 |
106 | myTextureId (NO_TEXTURE), |
107 | myTarget (GL_TEXTURE_2D), |
108 | mySizeX (0), |
109 | mySizeY (0), |
74fb257d |
110 | mySizeZ (0), |
8625ef7e |
111 | myTextFormat (GL_RGBA), |
15669413 |
112 | mySizedFormat(GL_RGBA8), |
113 | myNbSamples (1), |
faff3767 |
114 | myMaxMipLevel(0), |
115 | myIsAlpha (false), |
116 | myIsTopDown (true) |
bf75be98 |
117 | { |
cc8cbabe |
118 | // |
bf75be98 |
119 | } |
120 | |
121 | // ======================================================================= |
122 | // function : ~OpenGl_Texture |
123 | // purpose : |
124 | // ======================================================================= |
125 | OpenGl_Texture::~OpenGl_Texture() |
126 | { |
127 | Release (NULL); |
128 | } |
129 | |
bf75be98 |
130 | // ======================================================================= |
131 | // function : Create |
132 | // purpose : |
133 | // ======================================================================= |
cc8cbabe |
134 | bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& theCtx) |
bf75be98 |
135 | { |
cc8cbabe |
136 | if (myTextureId != NO_TEXTURE) |
137 | { |
138 | return true; |
139 | } |
140 | |
141 | theCtx->core11fwd->glGenTextures (1, &myTextureId); |
bf75be98 |
142 | if (myTextureId == NO_TEXTURE) |
143 | { |
cc8cbabe |
144 | return false; |
bf75be98 |
145 | } |
cc8cbabe |
146 | |
147 | //mySampler->Create (theCtx); // do not create sampler object by default |
148 | return true; |
bf75be98 |
149 | } |
150 | |
151 | // ======================================================================= |
152 | // function : Release |
153 | // purpose : |
154 | // ======================================================================= |
10b9c7df |
155 | void OpenGl_Texture::Release (OpenGl_Context* theGlCtx) |
bf75be98 |
156 | { |
cc8cbabe |
157 | mySampler->Release (theGlCtx); |
bf75be98 |
158 | if (myTextureId == NO_TEXTURE) |
159 | { |
160 | return; |
161 | } |
162 | |
163 | // application can not handle this case by exception - this is bug in code |
164 | Standard_ASSERT_RETURN (theGlCtx != NULL, |
165 | "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",); |
166 | |
ec2eeb2d |
167 | if (theGlCtx->IsValid()) |
168 | { |
e1d17ceb |
169 | theGlCtx->core11fwd->glDeleteTextures (1, &myTextureId); |
ec2eeb2d |
170 | } |
bf75be98 |
171 | myTextureId = NO_TEXTURE; |
d2edda76 |
172 | mySizeX = mySizeY = mySizeZ = 0; |
bf75be98 |
173 | } |
174 | |
cc8cbabe |
175 | // ======================================================================= |
176 | // function : applyDefaultSamplerParams |
177 | // purpose : |
178 | // ======================================================================= |
179 | void OpenGl_Texture::applyDefaultSamplerParams (const Handle(OpenGl_Context)& theCtx) |
180 | { |
faff3767 |
181 | OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), NULL, myTarget, myMaxMipLevel); |
cc8cbabe |
182 | if (mySampler->IsValid() && !mySampler->IsImmutable()) |
183 | { |
faff3767 |
184 | OpenGl_Sampler::applySamplerParams (theCtx, mySampler->Parameters(), mySampler.get(), myTarget, myMaxMipLevel); |
cc8cbabe |
185 | } |
186 | } |
187 | |
bf75be98 |
188 | // ======================================================================= |
189 | // function : Bind |
190 | // purpose : |
191 | // ======================================================================= |
192 | void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx, |
cc8cbabe |
193 | const Graphic3d_TextureUnit theTextureUnit) const |
bf75be98 |
194 | { |
4e1523ef |
195 | if (theCtx->core15fwd != NULL) |
bf75be98 |
196 | { |
cc8cbabe |
197 | theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit); |
bf75be98 |
198 | } |
cc8cbabe |
199 | mySampler->Bind (theCtx, theTextureUnit); |
e1d17ceb |
200 | theCtx->core11fwd->glBindTexture (myTarget, myTextureId); |
bf75be98 |
201 | } |
202 | |
203 | // ======================================================================= |
204 | // function : Unbind |
205 | // purpose : |
206 | // ======================================================================= |
207 | void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx, |
cc8cbabe |
208 | const Graphic3d_TextureUnit theTextureUnit) const |
bf75be98 |
209 | { |
4e1523ef |
210 | if (theCtx->core15fwd != NULL) |
bf75be98 |
211 | { |
cc8cbabe |
212 | theCtx->core15fwd->glActiveTexture (GL_TEXTURE0 + theTextureUnit); |
bf75be98 |
213 | } |
cc8cbabe |
214 | mySampler->Unbind (theCtx, theTextureUnit); |
e1d17ceb |
215 | theCtx->core11fwd->glBindTexture (myTarget, NO_TEXTURE); |
bf75be98 |
216 | } |
217 | |
cc8cbabe |
218 | //======================================================================= |
219 | //function : InitSamplerObject |
220 | //purpose : |
221 | //======================================================================= |
222 | bool OpenGl_Texture::InitSamplerObject (const Handle(OpenGl_Context)& theCtx) |
223 | { |
224 | return myTextureId != NO_TEXTURE |
225 | && mySampler->Init (theCtx, *this); |
226 | } |
227 | |
18f4e8e2 |
228 | // ======================================================================= |
229 | // function : Init |
230 | // purpose : |
231 | // ======================================================================= |
232 | bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, |
ba00aab7 |
233 | const OpenGl_TextureFormat& theFormat, |
234 | const Graphic3d_Vec2i& theSizeXY, |
18f4e8e2 |
235 | const Graphic3d_TypeOfTexture theType, |
236 | const Image_PixMap* theImage) |
237 | { |
ba00aab7 |
238 | if (theSizeXY.x() < 1 |
239 | || theSizeXY.y() < 1) |
66d1cdc6 |
240 | { |
241 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
776302d4 |
242 | TCollection_AsciiString ("Error: texture of 0 size cannot be created [") + myResourceId +"]"); |
ba00aab7 |
243 | Release (theCtx.get()); |
66d1cdc6 |
244 | return false; |
245 | } |
246 | |
d2edda76 |
247 | #if !defined(GL_ES_VERSION_2_0) |
248 | const GLenum aTarget = theType == Graphic3d_TOT_1D |
249 | ? GL_TEXTURE_1D |
250 | : GL_TEXTURE_2D; |
251 | #else |
252 | const GLenum aTarget = GL_TEXTURE_2D; |
253 | #endif |
d2edda76 |
254 | const bool toPatchExisting = IsValid() |
ba00aab7 |
255 | && myTextFormat == theFormat.PixelFormat() |
d2edda76 |
256 | && myTarget == aTarget |
faff3767 |
257 | && HasMipmaps() == (theType == Graphic3d_TOT_2D_MIPMAP) |
ba00aab7 |
258 | && mySizeX == theSizeXY.x() |
259 | && (mySizeY == theSizeXY.y() || theType == Graphic3d_TOT_1D); |
18f4e8e2 |
260 | if (!Create (theCtx)) |
261 | { |
ba00aab7 |
262 | Release (theCtx.get()); |
18f4e8e2 |
263 | return false; |
264 | } |
4e1523ef |
265 | |
266 | if (theImage != NULL) |
267 | { |
dc858f4c |
268 | myIsAlpha = theImage->Format() == Image_Format_Alpha |
269 | || theImage->Format() == Image_Format_AlphaF; |
faff3767 |
270 | myIsTopDown = theImage->IsTopDown(); |
4e1523ef |
271 | } |
272 | else |
273 | { |
ba00aab7 |
274 | myIsAlpha = theFormat.PixelFormat() == GL_ALPHA; |
4e1523ef |
275 | } |
276 | |
faff3767 |
277 | myMaxMipLevel = theType == Graphic3d_TOT_2D_MIPMAP && theCtx->arbFBO != NULL |
278 | ? computeUpperMipMapLevel (theSizeXY.x(), theSizeXY.y()) |
279 | : 0; |
280 | myTextFormat = theFormat.PixelFormat(); |
281 | mySizedFormat = theFormat.InternalFormat(); |
282 | myNbSamples = 1; |
8625ef7e |
283 | #if !defined(GL_ES_VERSION_2_0) |
ba00aab7 |
284 | const GLint anIntFormat = theFormat.InternalFormat(); |
8625ef7e |
285 | #else |
a1073ae2 |
286 | // ES 2.0 does not support sized formats and format conversions - them detected from data type |
ba00aab7 |
287 | const GLint anIntFormat = theCtx->IsGlGreaterEqual (3, 0) ? theFormat.InternalFormat() : theFormat.PixelFormat(); |
8625ef7e |
288 | #endif |
bf75be98 |
289 | |
ba00aab7 |
290 | if (theFormat.DataType() == GL_FLOAT |
291 | && !theCtx->arbTexFloat) |
ff6665dc |
292 | { |
293 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
776302d4 |
294 | TCollection_AsciiString ("Error: floating-point textures are not supported by hardware [") + myResourceId +"]"); |
ba00aab7 |
295 | Release (theCtx.get()); |
ff6665dc |
296 | return false; |
297 | } |
298 | |
d2edda76 |
299 | const GLsizei aMaxSize = theCtx->MaxTextureSize(); |
ba00aab7 |
300 | if (theSizeXY.x() > aMaxSize |
301 | || theSizeXY.y() > aMaxSize) |
fa4dcbe0 |
302 | { |
ba00aab7 |
303 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
304 | TCollection_AsciiString ("Error: Texture dimension - ") + theSizeXY.x() + "x" + theSizeXY.y() |
776302d4 |
305 | + " exceeds hardware limits (" + aMaxSize + "x" + aMaxSize + ")" |
306 | + " [" + myResourceId +"]"); |
ba00aab7 |
307 | Release (theCtx.get()); |
fa4dcbe0 |
308 | return false; |
309 | } |
310 | #if !defined(GL_ES_VERSION_2_0) |
311 | else if (!theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW) |
312 | { |
313 | // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications |
314 | // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT! |
315 | // Trying to create NPOT textures on such hardware will not fail |
316 | // but driver will fall back into software rendering, |
ba00aab7 |
317 | const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.x(), aMaxSize); |
318 | const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.y(), aMaxSize); |
319 | if (theSizeXY.x() != aWidthP2 |
320 | || (theType != Graphic3d_TOT_1D && theSizeXY.y() != aHeightP2)) |
fa4dcbe0 |
321 | { |
ba00aab7 |
322 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, |
323 | TCollection_AsciiString ("Error: NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")" |
776302d4 |
324 | " are not supported by hardware [" + myResourceId +"]"); |
ba00aab7 |
325 | Release (theCtx.get()); |
fa4dcbe0 |
326 | return false; |
327 | } |
328 | } |
329 | #else |
330 | else if (!theCtx->IsGlGreaterEqual (3, 0) && theType == Graphic3d_TOT_2D_MIPMAP) |
331 | { |
332 | // Mipmap NPOT textures are not supported by OpenGL ES 2.0. |
ba00aab7 |
333 | const GLsizei aWidthP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.x(), aMaxSize); |
334 | const GLsizei aHeightP2 = OpenGl_Context::GetPowerOfTwo (theSizeXY.y(), aMaxSize); |
335 | if (theSizeXY.x() != aWidthP2 |
336 | || theSizeXY.y() != aHeightP2) |
fa4dcbe0 |
337 | { |
ba00aab7 |
338 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, |
339 | TCollection_AsciiString ("Error: Mipmap NPOT Textures (") + theSizeXY.x() + "x" + theSizeXY.y() + ")" |
776302d4 |
340 | " are not supported by OpenGL ES 2.0 [" + myResourceId +"]"); |
ba00aab7 |
341 | Release (theCtx.get()); |
fa4dcbe0 |
342 | return false; |
343 | } |
344 | } |
345 | #endif |
346 | |
ca3c13d1 |
347 | #if !defined(GL_ES_VERSION_2_0) |
e1d17ceb |
348 | GLint aTestWidth = 0, aTestHeight = 0; |
ca3c13d1 |
349 | #endif |
18f4e8e2 |
350 | GLvoid* aDataPtr = (theImage != NULL) ? (GLvoid* )theImage->Data() : NULL; |
bf75be98 |
351 | |
74706083 |
352 | // setup the alignment |
e1d17ceb |
353 | OpenGl_UnpackAlignmentSentry anUnpackSentry (theCtx); |
fa4dcbe0 |
354 | (void)anUnpackSentry; // avoid compiler warning |
355 | |
18f4e8e2 |
356 | if (aDataPtr != NULL) |
357 | { |
358 | const GLint anAligment = Min ((GLint )theImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes |
a46ab511 |
359 | theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment); |
18f4e8e2 |
360 | const GLint anExtraBytes = GLint(theImage->RowExtraBytes()); |
361 | const GLint aPixelsWidth = GLint(theImage->SizeRowBytes() / theImage->SizePixelBytes()); |
e1d17ceb |
362 | if (theCtx->hasUnpackRowLength) |
363 | { |
364 | theCtx->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0); |
365 | } |
366 | else if (anExtraBytes >= anAligment) |
367 | { |
368 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, |
369 | TCollection_AsciiString ("Error: unsupported image stride within OpenGL ES 2.0 [") + myResourceId +"]"); |
370 | Release (theCtx.get()); |
371 | return false; |
372 | } |
18f4e8e2 |
373 | } |
74706083 |
374 | |
d2edda76 |
375 | myTarget = aTarget; |
bf75be98 |
376 | switch (theType) |
377 | { |
378 | case Graphic3d_TOT_1D: |
379 | { |
ca3c13d1 |
380 | #if !defined(GL_ES_VERSION_2_0) |
bf75be98 |
381 | Bind (theCtx); |
cc8cbabe |
382 | applyDefaultSamplerParams (theCtx); |
d2edda76 |
383 | if (toPatchExisting) |
384 | { |
a46ab511 |
385 | theCtx->core11fwd->glTexSubImage1D (GL_TEXTURE_1D, 0, 0, |
386 | theSizeXY.x(), theFormat.PixelFormat(), theFormat.DataType(), aDataPtr); |
d2edda76 |
387 | Unbind (theCtx); |
388 | return true; |
389 | } |
bf75be98 |
390 | |
bf75be98 |
391 | // use proxy to check texture could be created or not |
a46ab511 |
392 | theCtx->core11fwd->glTexImage1D (GL_PROXY_TEXTURE_1D, 0, anIntFormat, |
393 | theSizeXY.x(), 0, |
394 | theFormat.PixelFormat(), theFormat.DataType(), NULL); |
ff6665dc |
395 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_WIDTH, &aTestWidth); |
15669413 |
396 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_1D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat); |
bf75be98 |
397 | if (aTestWidth == 0) |
398 | { |
399 | // no memory or broken input parameters |
400 | Unbind (theCtx); |
18f4e8e2 |
401 | Release (theCtx.operator->()); |
bf75be98 |
402 | return false; |
403 | } |
404 | |
a46ab511 |
405 | theCtx->core11fwd->glTexImage1D (GL_TEXTURE_1D, 0, anIntFormat, |
406 | theSizeXY.x(), 0, |
407 | theFormat.PixelFormat(), theFormat.DataType(), aDataPtr); |
408 | if (theCtx->core11fwd->glGetError() != GL_NO_ERROR) |
a174a3c5 |
409 | { |
410 | Unbind (theCtx); |
ba00aab7 |
411 | Release (theCtx.get()); |
a174a3c5 |
412 | return false; |
413 | } |
414 | |
ba00aab7 |
415 | mySizeX = theSizeXY.x(); |
a174a3c5 |
416 | mySizeY = 1; |
bf75be98 |
417 | |
418 | Unbind (theCtx); |
419 | return true; |
ca3c13d1 |
420 | #else |
ff6665dc |
421 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
776302d4 |
422 | TCollection_AsciiString ( "Error: 1D textures are not supported by hardware [") + myResourceId +"]"); |
ba00aab7 |
423 | Release (theCtx.get()); |
ca3c13d1 |
424 | return false; |
425 | #endif |
bf75be98 |
426 | } |
427 | case Graphic3d_TOT_2D: |
bf75be98 |
428 | case Graphic3d_TOT_2D_MIPMAP: |
429 | { |
bf75be98 |
430 | Bind (theCtx); |
cc8cbabe |
431 | applyDefaultSamplerParams (theCtx); |
d2edda76 |
432 | if (toPatchExisting) |
433 | { |
a46ab511 |
434 | theCtx->core11fwd->glTexSubImage2D (GL_TEXTURE_2D, 0, |
435 | 0, 0, |
436 | theSizeXY.x(), theSizeXY.y(), |
437 | theFormat.PixelFormat(), theFormat.DataType(), aDataPtr); |
faff3767 |
438 | |
439 | if (myMaxMipLevel > 0) |
d2edda76 |
440 | { |
441 | // generate mipmaps |
442 | theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D); |
a46ab511 |
443 | if (theCtx->core11fwd->glGetError() != GL_NO_ERROR) |
d2edda76 |
444 | { |
faff3767 |
445 | myMaxMipLevel = 0; |
d2edda76 |
446 | } |
447 | } |
448 | |
449 | Unbind (theCtx); |
450 | return true; |
451 | } |
bf75be98 |
452 | |
fa4dcbe0 |
453 | #if !defined(GL_ES_VERSION_2_0) |
454 | // use proxy to check texture could be created or not |
a46ab511 |
455 | theCtx->core11fwd->glTexImage2D (GL_PROXY_TEXTURE_2D, 0, anIntFormat, |
456 | theSizeXY.x(), theSizeXY.y(), 0, |
457 | theFormat.PixelFormat(), theFormat.DataType(), NULL); |
fa4dcbe0 |
458 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth); |
459 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight); |
15669413 |
460 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat); |
fa4dcbe0 |
461 | if (aTestWidth == 0 || aTestHeight == 0) |
462 | { |
463 | // no memory or broken input parameters |
464 | Unbind (theCtx); |
ba00aab7 |
465 | Release (theCtx.get()); |
fa4dcbe0 |
466 | return false; |
467 | } |
468 | #endif |
469 | |
a46ab511 |
470 | theCtx->core11fwd->glTexImage2D (GL_TEXTURE_2D, 0, anIntFormat, |
471 | theSizeXY.x(), theSizeXY.y(), 0, |
472 | theFormat.PixelFormat(), theFormat.DataType(), aDataPtr); |
473 | GLenum anErr = theCtx->core11fwd->glGetError(); |
faff3767 |
474 | if (anErr != GL_NO_ERROR) |
1a7dfdb7 |
475 | { |
177781da |
476 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
ba00aab7 |
477 | TCollection_AsciiString ("Error: 2D texture ") + theSizeXY.x() + "x" + theSizeXY.y() |
a46ab511 |
478 | + " IF: " + OpenGl_TextureFormat::FormatFormat (anIntFormat) |
479 | + " PF: " + OpenGl_TextureFormat::FormatFormat (theFormat.PixelFormat()) |
480 | + " DT: " + OpenGl_TextureFormat::FormatDataType (theFormat.DataType()) |
776302d4 |
481 | + " can not be created with error " + OpenGl_Context::FormatGlError (anErr) |
482 | + " [" + myResourceId +"]"); |
fa4dcbe0 |
483 | Unbind (theCtx); |
ba00aab7 |
484 | Release (theCtx.get()); |
fa4dcbe0 |
485 | return false; |
486 | } |
487 | |
ba00aab7 |
488 | mySizeX = theSizeXY.x(); |
489 | mySizeY = theSizeXY.y(); |
fa4dcbe0 |
490 | |
faff3767 |
491 | if (myMaxMipLevel > 0) |
fa4dcbe0 |
492 | { |
493 | // generate mipmaps |
494 | //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST); |
495 | theCtx->arbFBO->glGenerateMipmap (GL_TEXTURE_2D); |
a46ab511 |
496 | anErr = theCtx->core11fwd->glGetError(); |
faff3767 |
497 | if (anErr != GL_NO_ERROR) |
a174a3c5 |
498 | { |
faff3767 |
499 | myMaxMipLevel = 0; |
776302d4 |
500 | #if defined(GL_ES_VERSION_2_0) |
501 | if (theFormat.InternalFormat() == GL_RGB8 |
502 | || theFormat.InternalFormat() == GL_SRGB8) |
503 | { |
504 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, |
505 | TCollection_AsciiString ("Warning: generating mipmaps requires color-renderable format, while giving ") |
506 | + OpenGl_TextureFormat::FormatFormat (anIntFormat) + " [" + myResourceId +"]"); |
507 | } |
508 | else |
509 | #endif |
510 | { |
511 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_HIGH, |
512 | TCollection_AsciiString ("Warning: generating mipmaps has failed [") + myResourceId +"]"); |
513 | } |
a174a3c5 |
514 | } |
1a7dfdb7 |
515 | } |
fa4dcbe0 |
516 | |
517 | Unbind (theCtx); |
518 | return true; |
bf75be98 |
519 | } |
077a220c |
520 | case Graphic3d_TOT_CUBEMAP: |
521 | { |
522 | Unbind (theCtx); |
523 | Release (theCtx.get()); |
524 | return false; |
525 | } |
bf75be98 |
526 | } |
d2edda76 |
527 | |
ba00aab7 |
528 | Release (theCtx.get()); |
d2edda76 |
529 | return false; |
bf75be98 |
530 | } |
68333c8f |
531 | |
18f4e8e2 |
532 | // ======================================================================= |
533 | // function : Init |
534 | // purpose : |
535 | // ======================================================================= |
536 | bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, |
537 | const Image_PixMap& theImage, |
ba00aab7 |
538 | const Graphic3d_TypeOfTexture theType, |
539 | const Standard_Boolean theIsColorMap) |
18f4e8e2 |
540 | { |
541 | if (theImage.IsEmpty()) |
542 | { |
ba00aab7 |
543 | Release (theCtx.get()); |
18f4e8e2 |
544 | return false; |
545 | } |
546 | |
ba00aab7 |
547 | const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theImage.Format(), theIsColorMap); |
548 | if (!aFormat.IsValid()) |
18f4e8e2 |
549 | { |
776302d4 |
550 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
551 | TCollection_AsciiString ("Error: No suitable texture format for ") + Image_PixMap::ImageFormatToString (theImage.Format()) + " image format" |
552 | + " [" + myResourceId +"]"); |
ba00aab7 |
553 | Release (theCtx.get()); |
18f4e8e2 |
554 | return false; |
555 | } |
556 | |
ba00aab7 |
557 | return Init (theCtx, aFormat, Graphic3d_Vec2i ((Standard_Integer)theImage.SizeX(), (Standard_Integer)theImage.SizeY()), |
18f4e8e2 |
558 | theType, &theImage); |
559 | } |
560 | |
077a220c |
561 | // ======================================================================= |
562 | // function : Init |
563 | // purpose : |
564 | // ======================================================================= |
565 | bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx, |
566 | const Handle(Graphic3d_TextureMap)& theTextureMap) |
567 | { |
568 | if (theTextureMap.IsNull()) |
569 | { |
570 | return false; |
571 | } |
572 | |
573 | switch (theTextureMap->Type()) |
574 | { |
575 | case Graphic3d_TOT_CUBEMAP: |
576 | { |
67312b79 |
577 | return InitCubeMap (theCtx, Handle(Graphic3d_CubeMap)::DownCast(theTextureMap), |
ba00aab7 |
578 | 0, Image_Format_RGB, false, theTextureMap->IsColorMap()); |
077a220c |
579 | } |
580 | default: |
581 | { |
faff3767 |
582 | if (theCtx->SupportedTextureFormats()->HasCompressed() |
583 | && !theCtx->caps->compressedTexturesDisable) |
584 | { |
585 | if (Handle(Image_CompressedPixMap) aCompressed = theTextureMap->GetCompressedImage (theCtx->SupportedTextureFormats())) |
586 | { |
587 | return InitCompressed (theCtx, *aCompressed, theTextureMap->IsColorMap()); |
588 | } |
589 | } |
590 | |
591 | Handle(Image_PixMap) anImage = theTextureMap->GetImage (theCtx->SupportedTextureFormats()); |
077a220c |
592 | if (anImage.IsNull()) |
593 | { |
594 | return false; |
595 | } |
ba00aab7 |
596 | return Init (theCtx, *anImage, theTextureMap->Type(), theTextureMap->IsColorMap()); |
077a220c |
597 | } |
598 | } |
599 | } |
600 | |
faff3767 |
601 | // ======================================================================= |
602 | // function : InitCompressed |
603 | // purpose : |
604 | // ======================================================================= |
605 | bool OpenGl_Texture::InitCompressed (const Handle(OpenGl_Context)& theCtx, |
606 | const Image_CompressedPixMap& theImage, |
607 | const Standard_Boolean theIsColorMap) |
608 | { |
609 | if (theImage.SizeX() < 1 |
610 | || theImage.SizeY() < 1 |
611 | || theImage.FaceData().IsNull()) |
612 | { |
613 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
614 | "Error: texture of 0 size cannot be created."); |
615 | Release (theCtx.get()); |
616 | return false; |
617 | } |
618 | if (theImage.SizeX() > theCtx->MaxTextureSize() |
619 | || theImage.SizeY() > theCtx->MaxTextureSize()) |
620 | { |
621 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
622 | TCollection_AsciiString ("Error: Texture dimension - ") + theImage.SizeX() + "x" + theImage.SizeY() |
623 | + " exceeds hardware limits (" + theCtx->MaxTextureSize() + "x" + theCtx->MaxTextureSize() + ")"); |
624 | Release (theCtx.get()); |
625 | return false; |
626 | } |
627 | |
628 | const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindCompressedFormat (theCtx, theImage.CompressedFormat(), theIsColorMap); |
629 | if (!aFormat.IsValid()) |
630 | { |
776302d4 |
631 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
632 | TCollection_AsciiString ("Error: No suitable texture format for ") + Image_PixMap::ImageFormatToString (theImage.CompressedFormat()) + " image format " |
633 | + " [" + myResourceId +"]"); |
faff3767 |
634 | Release (theCtx.get()); |
635 | return false; |
636 | } |
637 | |
638 | if (!Create (theCtx)) |
639 | { |
640 | return false; |
641 | } |
642 | |
643 | myTarget = GL_TEXTURE_2D; |
644 | myNbSamples = 1; |
645 | myTextFormat = aFormat.Format(); |
646 | mySizedFormat = aFormat.Internal(); |
647 | myIsTopDown = theImage.IsTopDown(); |
648 | mySizeX = theImage.SizeX(); |
649 | mySizeY = theImage.SizeY(); |
650 | myMaxMipLevel = Max (theImage.MipMaps().Size() - 1, 0); |
651 | if (myMaxMipLevel > 0 |
652 | && !theImage.IsCompleteMipMapSet()) |
653 | { |
654 | const Graphic3d_Vec2i aMipSize = computeSmallestMipMapSize (Graphic3d_Vec2i (mySizeX, mySizeY), myMaxMipLevel); |
655 | if (!theCtx->HasTextureBaseLevel()) |
656 | { |
657 | myMaxMipLevel = 0; |
658 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_MEDIUM, |
659 | TCollection_AsciiString ("Warning: compressed 2D texture ") + myResourceId + " " + mySizeX + "x" + mySizeY |
660 | + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y() + "; mipmaps will be ignored"); |
661 | } |
662 | else |
663 | { |
664 | Message::SendTrace (TCollection_AsciiString ("Warning: compressed 2D texture ") + myResourceId + " " + mySizeX + "x" + mySizeY |
665 | + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y()); |
666 | } |
667 | } |
668 | |
669 | Bind (theCtx); |
670 | applyDefaultSamplerParams (theCtx); |
671 | |
672 | // setup the alignment |
e1d17ceb |
673 | OpenGl_UnpackAlignmentSentry::Reset (*theCtx); |
faff3767 |
674 | |
675 | Graphic3d_Vec2i aMipSizeXY (theImage.SizeX(), theImage.SizeY()); |
676 | const Standard_Byte* aData = theImage.FaceData()->Data(); |
677 | for (Standard_Integer aMipIter = 0; aMipIter <= myMaxMipLevel; ++aMipIter) |
678 | { |
679 | const Standard_Integer aMipLength = theImage.MipMaps().Value (aMipIter); |
680 | theCtx->Functions()->glCompressedTexImage2D (GL_TEXTURE_2D, aMipIter, mySizedFormat, aMipSizeXY.x(), aMipSizeXY.y(), 0, aMipLength, aData); |
e1d17ceb |
681 | const GLenum aTexImgErr = theCtx->core11fwd->glGetError(); |
faff3767 |
682 | if (aTexImgErr != GL_NO_ERROR) |
683 | { |
684 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
685 | TCollection_AsciiString ("Error: 2D compressed texture ") + aMipSizeXY.x() + "x" + aMipSizeXY.y() |
a46ab511 |
686 | + " IF: " + OpenGl_TextureFormat::FormatFormat (aFormat.Internal()) |
687 | + " PF: " + OpenGl_TextureFormat::FormatFormat (aFormat.PixelFormat()) |
688 | + " DT: " + OpenGl_TextureFormat::FormatDataType (aFormat.DataType()) |
689 | + " can not be created with error " + OpenGl_Context::FormatGlError (aTexImgErr) + "."); |
faff3767 |
690 | Unbind (theCtx); |
691 | Release (theCtx.get()); |
692 | return false; |
693 | } |
694 | |
695 | aData += aMipLength; |
696 | aMipSizeXY /= 2; |
697 | if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; } |
698 | if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; } |
699 | } |
700 | |
701 | Unbind (theCtx); |
702 | return true; |
703 | } |
704 | |
3c4b62a4 |
705 | // ======================================================================= |
706 | // function : Init2DMultisample |
707 | // purpose : |
708 | // ======================================================================= |
709 | bool OpenGl_Texture::Init2DMultisample (const Handle(OpenGl_Context)& theCtx, |
1220d98e |
710 | const Standard_Integer theNbSamples, |
711 | const Standard_Integer theTextFormat, |
712 | const Standard_Integer theSizeX, |
713 | const Standard_Integer theSizeY) |
3c4b62a4 |
714 | { |
715 | if (!Create (theCtx) |
716 | || theNbSamples > theCtx->MaxMsaaSamples() |
717 | || theNbSamples < 1) |
718 | { |
719 | return false; |
720 | } |
721 | |
15669413 |
722 | myNbSamples = OpenGl_Context::GetPowerOfTwo (theNbSamples, theCtx->MaxMsaaSamples()); |
3c4b62a4 |
723 | myTarget = GL_TEXTURE_2D_MULTISAMPLE; |
faff3767 |
724 | myMaxMipLevel = 0; |
3c4b62a4 |
725 | if(theSizeX > theCtx->MaxTextureSize() |
726 | || theSizeY > theCtx->MaxTextureSize()) |
727 | { |
728 | return false; |
729 | } |
730 | |
731 | Bind (theCtx); |
732 | //myTextFormat = theTextFormat; |
15669413 |
733 | mySizedFormat = theTextFormat; |
3c4b62a4 |
734 | #if !defined(GL_ES_VERSION_2_0) |
735 | if (theCtx->Functions()->glTexStorage2DMultisample != NULL) |
736 | { |
15669413 |
737 | theCtx->Functions()->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE); |
3c4b62a4 |
738 | } |
739 | else |
740 | { |
15669413 |
741 | theCtx->Functions()->glTexImage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE); |
3c4b62a4 |
742 | } |
743 | #else |
15669413 |
744 | theCtx->Functions() ->glTexStorage2DMultisample (myTarget, myNbSamples, theTextFormat, theSizeX, theSizeY, GL_FALSE); |
3c4b62a4 |
745 | #endif |
746 | if (theCtx->core11fwd->glGetError() != GL_NO_ERROR) |
747 | { |
748 | Unbind (theCtx); |
749 | return false; |
750 | } |
751 | |
752 | mySizeX = theSizeX; |
753 | mySizeY = theSizeY; |
754 | |
755 | Unbind (theCtx); |
756 | return true; |
757 | } |
758 | |
68333c8f |
759 | // ======================================================================= |
760 | // function : InitRectangle |
761 | // purpose : |
762 | // ======================================================================= |
763 | bool OpenGl_Texture::InitRectangle (const Handle(OpenGl_Context)& theCtx, |
764 | const Standard_Integer theSizeX, |
765 | const Standard_Integer theSizeY, |
766 | const OpenGl_TextureFormat& theFormat) |
767 | { |
768 | if (!Create (theCtx) || !theCtx->IsGlGreaterEqual (3, 0)) |
769 | { |
770 | return false; |
771 | } |
ca3c13d1 |
772 | |
773 | #if !defined(GL_ES_VERSION_2_0) |
68333c8f |
774 | myTarget = GL_TEXTURE_RECTANGLE; |
15669413 |
775 | myNbSamples = 1; |
faff3767 |
776 | myMaxMipLevel = 0; |
68333c8f |
777 | |
e1d17ceb |
778 | const GLsizei aSizeX = Min (theCtx->MaxTextureSize(), theSizeX); |
779 | const GLsizei aSizeY = Min (theCtx->MaxTextureSize(), theSizeY); |
ca3c13d1 |
780 | |
68333c8f |
781 | Bind (theCtx); |
cc8cbabe |
782 | applyDefaultSamplerParams (theCtx); |
68333c8f |
783 | |
15669413 |
784 | myTextFormat = theFormat.Format(); |
785 | mySizedFormat = theFormat.Internal(); |
68333c8f |
786 | |
90fd6145 |
787 | // setup the alignment |
e1d17ceb |
788 | OpenGl_UnpackAlignmentSentry::Reset (*theCtx); |
90fd6145 |
789 | |
a46ab511 |
790 | theCtx->core11fwd->glTexImage2D (GL_PROXY_TEXTURE_RECTANGLE, 0, mySizedFormat, |
791 | aSizeX, aSizeY, 0, |
792 | myTextFormat, GL_FLOAT, NULL); |
68333c8f |
793 | |
e1d17ceb |
794 | GLint aTestSizeX = 0, aTestSizeY = 0; |
15669413 |
795 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_WIDTH, &aTestSizeX); |
796 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_HEIGHT, &aTestSizeY); |
797 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_RECTANGLE, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat); |
68333c8f |
798 | if (aTestSizeX == 0 || aTestSizeY == 0) |
799 | { |
800 | Unbind (theCtx); |
801 | return false; |
802 | } |
803 | |
a46ab511 |
804 | theCtx->core11fwd->glTexImage2D (myTarget, 0, mySizedFormat, |
805 | aSizeX, aSizeY, 0, |
806 | myTextFormat, GL_FLOAT, NULL); |
a46ab511 |
807 | if (theCtx->core11fwd->glGetError() != GL_NO_ERROR) |
68333c8f |
808 | { |
809 | Unbind (theCtx); |
810 | return false; |
811 | } |
812 | |
813 | mySizeX = aSizeX; |
814 | mySizeY = aSizeY; |
68333c8f |
815 | Unbind (theCtx); |
816 | return true; |
ca3c13d1 |
817 | #else |
20aeeb7b |
818 | (void )theSizeX; |
819 | (void )theSizeY; |
820 | (void )theFormat; |
ca3c13d1 |
821 | return false; |
822 | #endif |
68333c8f |
823 | } |
74fb257d |
824 | |
825 | // ======================================================================= |
826 | // function : Init3D |
827 | // purpose : |
828 | // ======================================================================= |
829 | bool OpenGl_Texture::Init3D (const Handle(OpenGl_Context)& theCtx, |
ba00aab7 |
830 | const OpenGl_TextureFormat& theFormat, |
831 | const Graphic3d_Vec3i& theSizeXYZ, |
74fb257d |
832 | const void* thePixels) |
833 | { |
834 | if (theCtx->Functions()->glTexImage3D == NULL) |
835 | { |
ba00aab7 |
836 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
837 | "Error: three-dimensional textures are not supported by hardware."); |
74fb257d |
838 | return false; |
839 | } |
840 | |
841 | if (!Create(theCtx)) |
842 | { |
843 | return false; |
844 | } |
845 | |
846 | myTarget = GL_TEXTURE_3D; |
15669413 |
847 | myNbSamples = 1; |
faff3767 |
848 | myMaxMipLevel = 0; |
74fb257d |
849 | |
ba00aab7 |
850 | const Graphic3d_Vec3i aSizeXYZ = theSizeXYZ.cwiseMin (Graphic3d_Vec3i (theCtx->MaxTextureSize())); |
851 | if (aSizeXYZ != theSizeXYZ) |
852 | { |
853 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
854 | "Error: 3D texture dimensions exceed hardware limits."); |
855 | Release (theCtx.get()); |
856 | Unbind (theCtx); |
857 | return false; |
858 | } |
74fb257d |
859 | Bind (theCtx); |
860 | |
ba00aab7 |
861 | if (theFormat.DataType() == GL_FLOAT |
862 | && !theCtx->arbTexFloat) |
74fb257d |
863 | { |
ba00aab7 |
864 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
865 | "Error: floating-point textures are not supported by hardware."); |
866 | Release (theCtx.get()); |
74fb257d |
867 | Unbind (theCtx); |
868 | return false; |
869 | } |
870 | |
ba00aab7 |
871 | mySizedFormat = theFormat.InternalFormat(); |
74fb257d |
872 | |
90fd6145 |
873 | // setup the alignment |
e1d17ceb |
874 | OpenGl_UnpackAlignmentSentry::Reset (*theCtx); |
90fd6145 |
875 | |
74fb257d |
876 | #if !defined (GL_ES_VERSION_2_0) |
15669413 |
877 | theCtx->core15fwd->glTexImage3D (GL_PROXY_TEXTURE_3D, 0, mySizedFormat, |
ba00aab7 |
878 | aSizeXYZ.x(), aSizeXYZ.y(), aSizeXYZ.z(), 0, |
879 | theFormat.PixelFormat(), theFormat.DataType(), NULL); |
74fb257d |
880 | |
ba00aab7 |
881 | NCollection_Vec3<GLint> aTestSizeXYZ; |
882 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &aTestSizeXYZ.x()); |
883 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_HEIGHT, &aTestSizeXYZ.y()); |
884 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_DEPTH, &aTestSizeXYZ.z()); |
15669413 |
885 | glGetTexLevelParameteriv (GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_INTERNAL_FORMAT, &mySizedFormat); |
ba00aab7 |
886 | if (aTestSizeXYZ.x() == 0 || aTestSizeXYZ.y() == 0 || aTestSizeXYZ.z() == 0) |
74fb257d |
887 | { |
888 | Unbind (theCtx); |
ba00aab7 |
889 | Release (theCtx.get()); |
74fb257d |
890 | return false; |
891 | } |
892 | #endif |
893 | |
cc8cbabe |
894 | applyDefaultSamplerParams (theCtx); |
15669413 |
895 | theCtx->Functions()->glTexImage3D (myTarget, 0, mySizedFormat, |
ba00aab7 |
896 | aSizeXYZ.x(), aSizeXYZ.y(), aSizeXYZ.z(), 0, |
897 | theFormat.PixelFormat(), theFormat.DataType(), thePixels); |
74fb257d |
898 | |
a46ab511 |
899 | if (theCtx->core11fwd->glGetError() != GL_NO_ERROR) |
74fb257d |
900 | { |
901 | Unbind (theCtx); |
ba00aab7 |
902 | Release (theCtx.get()); |
74fb257d |
903 | return false; |
904 | } |
905 | |
ba00aab7 |
906 | mySizeX = aSizeXYZ.x(); |
907 | mySizeY = aSizeXYZ.y(); |
908 | mySizeZ = aSizeXYZ.z(); |
74fb257d |
909 | |
910 | Unbind (theCtx); |
911 | return true; |
912 | } |
15669413 |
913 | |
077a220c |
914 | // ======================================================================= |
67312b79 |
915 | // function : InitCubeMap |
077a220c |
916 | // purpose : |
917 | // ======================================================================= |
67312b79 |
918 | bool OpenGl_Texture::InitCubeMap (const Handle(OpenGl_Context)& theCtx, |
077a220c |
919 | const Handle(Graphic3d_CubeMap)& theCubeMap, |
ba00aab7 |
920 | Standard_Size theSize, |
921 | Image_Format theFormat, |
922 | Standard_Boolean theToGenMipmap, |
923 | Standard_Boolean theIsColorMap) |
077a220c |
924 | { |
925 | if (!Create (theCtx)) |
926 | { |
927 | Release (theCtx.get()); |
928 | return false; |
929 | } |
930 | |
faff3767 |
931 | Handle(Image_PixMap) anImage; |
932 | Handle(Image_CompressedPixMap) aCompImage; |
933 | OpenGl_TextureFormat aFormat; |
077a220c |
934 | if (!theCubeMap.IsNull()) |
935 | { |
faff3767 |
936 | theCubeMap->Reset(); |
937 | if (theCtx->SupportedTextureFormats()->HasCompressed() |
938 | && !theCtx->caps->compressedTexturesDisable) |
077a220c |
939 | { |
faff3767 |
940 | aCompImage = theCubeMap->CompressedValue (theCtx->SupportedTextureFormats()); |
077a220c |
941 | } |
faff3767 |
942 | if (!aCompImage.IsNull()) |
077a220c |
943 | { |
faff3767 |
944 | aFormat = OpenGl_TextureFormat::FindCompressedFormat (theCtx, aCompImage->CompressedFormat(), theIsColorMap); |
945 | if (aFormat.IsValid()) |
946 | { |
947 | theToGenMipmap = false; |
948 | theSize = aCompImage->SizeX(); |
949 | theFormat = aCompImage->BaseFormat(); |
950 | myMaxMipLevel = Max (aCompImage->MipMaps().Size() - 1, 0); |
951 | if (myMaxMipLevel > 0 |
952 | && !aCompImage->IsCompleteMipMapSet()) |
953 | { |
954 | const Graphic3d_Vec2i aMipSize = computeSmallestMipMapSize (Graphic3d_Vec2i (aCompImage->SizeX(), aCompImage->SizeY()), myMaxMipLevel); |
955 | if (!theCtx->HasTextureBaseLevel()) |
956 | { |
957 | myMaxMipLevel = 0; |
958 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PERFORMANCE, 0, GL_DEBUG_SEVERITY_MEDIUM, |
959 | TCollection_AsciiString ("Warning: Cubemap compressed texture ") + theCubeMap->GetId() + " " + aCompImage->SizeX() + "x" + aCompImage->SizeX() |
960 | + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y() + "; mipmaps will be ignored"); |
961 | } |
962 | else |
963 | { |
964 | Message::SendTrace (TCollection_AsciiString ("Warning: Cubemap compressed texture ") + theCubeMap->GetId() + " " + aCompImage->SizeX() + "x" + aCompImage->SizeX() |
965 | + " has smallest mipmap " + aMipSize.x() + "x" + aMipSize.y()); |
966 | } |
967 | } |
968 | |
e1d17ceb |
969 | OpenGl_UnpackAlignmentSentry::Reset (*theCtx); |
faff3767 |
970 | } |
971 | else |
972 | { |
973 | aCompImage.Nullify(); |
974 | } |
975 | } |
976 | |
977 | if (!aFormat.IsValid()) |
978 | { |
979 | anImage = theCubeMap->Reset().Value (theCtx->SupportedTextureFormats()); |
980 | if (anImage.IsNull()) |
981 | { |
982 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
983 | "Unable to get the first side of cubemap"); |
984 | Release(theCtx.get()); |
985 | return false; |
986 | } |
987 | |
988 | theSize = anImage->SizeX(); |
989 | theFormat = anImage->Format(); |
990 | theToGenMipmap = theCubeMap->HasMipmaps(); |
991 | myMaxMipLevel = theToGenMipmap ? computeUpperMipMapLevel ((Standard_Integer )theSize) : 0; |
077a220c |
992 | } |
faff3767 |
993 | |
994 | myIsTopDown = theCubeMap->IsTopDown(); |
995 | } |
996 | else |
997 | { |
998 | myMaxMipLevel = theToGenMipmap ? computeUpperMipMapLevel ((Standard_Integer )theSize) : 0; |
077a220c |
999 | } |
1000 | |
faff3767 |
1001 | if (!aFormat.IsValid()) |
1002 | { |
1003 | aFormat = OpenGl_TextureFormat::FindFormat (theCtx, theFormat, theIsColorMap); |
1004 | } |
ba00aab7 |
1005 | if (!aFormat.IsValid()) |
077a220c |
1006 | { |
776302d4 |
1007 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
1008 | TCollection_AsciiString ("Error: No suitable texture format for ") + Image_PixMap::ImageFormatToString (theFormat) + " image format" |
1009 | + " [" + myResourceId +"]"); |
077a220c |
1010 | Unbind(theCtx); |
1011 | Release(theCtx.get()); |
1012 | return false; |
1013 | } |
1014 | |
1015 | myTarget = GL_TEXTURE_CUBE_MAP; |
077a220c |
1016 | myNbSamples = 1; |
67312b79 |
1017 | mySizeX = (GLsizei )theSize; |
1018 | mySizeY = (GLsizei )theSize; |
faff3767 |
1019 | myTextFormat = aFormat.Format(); |
1020 | mySizedFormat = aFormat.Internal(); |
e4e3254a |
1021 | #if !defined(GL_ES_VERSION_2_0) |
1022 | const GLint anIntFormat = aFormat.InternalFormat(); |
1023 | #else |
1024 | // ES 2.0 does not support sized formats and format conversions - them detected from data type |
1025 | const GLint anIntFormat = theCtx->IsGlGreaterEqual (3, 0) ? aFormat.InternalFormat() : aFormat.PixelFormat(); |
1026 | #endif |
1027 | |
077a220c |
1028 | Bind (theCtx); |
1029 | applyDefaultSamplerParams (theCtx); |
1030 | |
1031 | for (Standard_Integer i = 0; i < 6; ++i) |
1032 | { |
faff3767 |
1033 | const Standard_Byte* aData = NULL; |
077a220c |
1034 | |
1035 | if (!theCubeMap.IsNull()) |
1036 | { |
faff3767 |
1037 | if (i != 0) |
1038 | { |
1039 | if (!aCompImage.IsNull()) |
1040 | { |
1041 | aCompImage = theCubeMap->CompressedValue (theCtx->SupportedTextureFormats()); |
1042 | } |
1043 | else |
1044 | { |
1045 | anImage = theCubeMap->Value (theCtx->SupportedTextureFormats()); |
1046 | } |
1047 | } |
1048 | if (!aCompImage.IsNull()) |
1049 | { |
1050 | Graphic3d_Vec2i aMipSizeXY (mySizeX, mySizeY); |
1051 | aData = aCompImage->FaceData()->Data(); |
1052 | for (Standard_Integer aMipIter = 0; aMipIter <= myMaxMipLevel; ++aMipIter) |
1053 | { |
1054 | const Standard_Integer aMipLength = aCompImage->MipMaps().Value (aMipIter); |
1055 | theCtx->Functions()->glCompressedTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, aMipIter, mySizedFormat, aMipSizeXY.x(), aMipSizeXY.y(), 0, aMipLength, aData); |
e1d17ceb |
1056 | const GLenum aTexImgErr = theCtx->core11fwd->glGetError(); |
faff3767 |
1057 | if (aTexImgErr != GL_NO_ERROR) |
1058 | { |
1059 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
1060 | TCollection_AsciiString ("Error: cubemap compressed texture ") + aMipSizeXY.x() + "x" + aMipSizeXY.y() |
a46ab511 |
1061 | + " IF: " + OpenGl_TextureFormat::FormatFormat (aFormat.Internal()) |
1062 | + " PF: " + OpenGl_TextureFormat::FormatFormat (aFormat.PixelFormat()) |
1063 | + " DT: " + OpenGl_TextureFormat::FormatDataType (aFormat.DataType()) |
1064 | + " can not be created with error " + OpenGl_Context::FormatGlError (aTexImgErr) + "."); |
faff3767 |
1065 | Unbind (theCtx); |
1066 | Release (theCtx.get()); |
1067 | return false; |
1068 | } |
1069 | |
1070 | aData += aMipLength; |
1071 | aMipSizeXY /= 2; |
1072 | if (aMipSizeXY.x() == 0) { aMipSizeXY.x() = 1; } |
1073 | if (aMipSizeXY.y() == 0) { aMipSizeXY.y() = 1; } |
1074 | } |
1075 | |
1076 | theCubeMap->Next(); |
1077 | continue; |
1078 | } |
1079 | |
077a220c |
1080 | if (!anImage.IsNull()) |
1081 | { |
077a220c |
1082 | const GLint anAligment = Min ((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes |
077a220c |
1083 | const GLint anExtraBytes = GLint(anImage->RowExtraBytes()); |
1084 | const GLint aPixelsWidth = GLint(anImage->SizeRowBytes() / anImage->SizePixelBytes()); |
1085 | const GLint aRowLength = (anExtraBytes >= anAligment) ? aPixelsWidth : 0; |
e1d17ceb |
1086 | if (theCtx->hasUnpackRowLength) |
1087 | { |
1088 | theCtx->core11fwd->glPixelStorei (GL_UNPACK_ROW_LENGTH, aRowLength); |
1089 | } |
1090 | |
1091 | if (aRowLength > 0 |
1092 | && !theCtx->hasUnpackRowLength) |
077a220c |
1093 | { |
e1d17ceb |
1094 | Handle(Image_PixMap) aCopyImage = new Image_PixMap(); |
1095 | aCopyImage->InitTrash (theFormat, theSize, theSize); |
1096 | const Standard_Size aRowBytesPacked = std::min (aCopyImage->SizeRowBytes(), anImage->SizeRowBytes()); |
1097 | for (unsigned int y = 0; y < theSize; ++y) |
077a220c |
1098 | { |
e1d17ceb |
1099 | memcpy (aCopyImage->ChangeRow (y), anImage->ChangeRow (y), aRowBytesPacked); |
077a220c |
1100 | } |
e1d17ceb |
1101 | anImage = aCopyImage; |
1102 | const GLint anAligment2 = Min((GLint)anImage->MaxRowAligmentBytes(), 8); // OpenGL supports alignment upto 8 bytes |
1103 | theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment2); |
077a220c |
1104 | } |
e1d17ceb |
1105 | else |
1106 | { |
1107 | theCtx->core11fwd->glPixelStorei (GL_UNPACK_ALIGNMENT, anAligment); |
1108 | } |
1109 | |
077a220c |
1110 | aData = anImage->Data(); |
1111 | } |
1112 | else |
1113 | { |
ba00aab7 |
1114 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
1115 | TCollection_AsciiString() + "Unable to get [" + i + "] side of cubemap"); |
077a220c |
1116 | Unbind (theCtx); |
1117 | Release (theCtx.get()); |
1118 | return false; |
1119 | } |
1120 | theCubeMap->Next(); |
1121 | } |
1122 | |
a46ab511 |
1123 | theCtx->core11fwd->glTexImage2D (GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, |
1124 | anIntFormat, |
1125 | GLsizei(theSize), GLsizei(theSize), |
1126 | 0, aFormat.PixelFormat(), aFormat.DataType(), |
1127 | aData); |
077a220c |
1128 | |
e1d17ceb |
1129 | OpenGl_UnpackAlignmentSentry::Reset (*theCtx); |
077a220c |
1130 | |
a46ab511 |
1131 | const GLenum anErr = theCtx->core11fwd->glGetError(); |
ba00aab7 |
1132 | if (anErr != GL_NO_ERROR) |
077a220c |
1133 | { |
1134 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
a46ab511 |
1135 | TCollection_AsciiString ("Unable to initialize side of cubemap. Error ") + OpenGl_Context::FormatGlError (anErr)); |
077a220c |
1136 | Unbind (theCtx); |
1137 | Release (theCtx.get()); |
1138 | return false; |
1139 | } |
1140 | } |
1141 | |
1142 | if (theToGenMipmap && theCtx->arbFBO != NULL) |
1143 | { |
ba00aab7 |
1144 | theCtx->arbFBO->glGenerateMipmap (myTarget); |
a46ab511 |
1145 | const GLenum anErr = theCtx->core11fwd->glGetError(); |
ba00aab7 |
1146 | if (anErr != GL_NO_ERROR) |
1147 | { |
1148 | theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, |
776302d4 |
1149 | TCollection_AsciiString ("Unable to generate mipmap of cubemap with format ") |
1150 | + OpenGl_TextureFormat::FormatFormat (anIntFormat) |
1151 | + ", error " + OpenGl_Context::FormatGlError (anErr)); |
1152 | myMaxMipLevel = 0; |
ba00aab7 |
1153 | } |
077a220c |
1154 | } |
1155 | |
1156 | Unbind (theCtx.get()); |
1157 | return true; |
1158 | } |
1159 | |
15669413 |
1160 | // ======================================================================= |
1161 | // function : PixelSizeOfPixelFormat |
1162 | // purpose : |
1163 | // ======================================================================= |
1164 | Standard_Size OpenGl_Texture::PixelSizeOfPixelFormat (Standard_Integer theInternalFormat) |
1165 | { |
1166 | switch(theInternalFormat) |
1167 | { |
1168 | // RED variations (GL_RED, OpenGL 3.0+) |
1169 | case GL_RED: |
1170 | case GL_R8: return 1; |
1171 | case GL_R16: return 2; |
1172 | case GL_R16F: return 2; |
1173 | case GL_R32F: return 4; |
1174 | // RGB variations |
1175 | case GL_RGB: return 3; |
1176 | case GL_RGB8: return 3; |
1177 | case GL_RGB16: return 6; |
1178 | case GL_RGB16F: return 6; |
1179 | case GL_RGB32F: return 12; |
1180 | // RGBA variations |
1181 | case GL_RGBA: return 4; |
1182 | case GL_RGBA8: return 4; |
1183 | case GL_RGB10_A2: return 4; |
1184 | case GL_RGBA12: return 6; |
1185 | case GL_RGBA16: return 8; |
1186 | case GL_RGBA16F: return 8; |
1187 | case GL_RGBA32F: return 16; |
1188 | // |
1189 | case GL_BGRA_EXT: return 4; |
1190 | // ALPHA variations (deprecated) |
1191 | case GL_ALPHA: |
1192 | case GL_ALPHA8: return 1; |
1193 | case GL_ALPHA16: return 2; |
1194 | case GL_LUMINANCE: return 1; |
1195 | case GL_LUMINANCE_ALPHA: return 2; |
1196 | // depth-stencil |
1197 | case GL_DEPTH24_STENCIL8: return 4; |
1198 | case GL_DEPTH32F_STENCIL8: return 8; |
1199 | case GL_DEPTH_COMPONENT16: return 2; |
1200 | case GL_DEPTH_COMPONENT24: return 3; |
1201 | case GL_DEPTH_COMPONENT32F: return 4; |
faff3767 |
1202 | // compressed |
1203 | case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: // DXT1 uses circa half a byte per pixel (64 bits per 4x4 block) |
1204 | case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: |
1205 | case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: |
1206 | case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: |
1207 | case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: // DXT3/5 uses circa 1 byte per pixel (128 bits per 4x4 block) |
1208 | case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: |
1209 | case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: |
1210 | case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: |
1211 | return 1; |
15669413 |
1212 | } |
faff3767 |
1213 | return 1; |
15669413 |
1214 | } |
1215 | |
1216 | // ======================================================================= |
1217 | // function : EstimatedDataSize |
1218 | // purpose : |
1219 | // ======================================================================= |
1220 | Standard_Size OpenGl_Texture::EstimatedDataSize() const |
1221 | { |
1222 | if (!IsValid()) |
1223 | { |
1224 | return 0; |
1225 | } |
1226 | |
1227 | Standard_Size aSize = PixelSizeOfPixelFormat (mySizedFormat) * mySizeX * myNbSamples; |
1228 | if (mySizeY != 0) |
1229 | { |
1230 | aSize *= Standard_Size(mySizeY); |
1231 | } |
1232 | if (mySizeZ != 0) |
1233 | { |
1234 | aSize *= Standard_Size(mySizeZ); |
1235 | } |
67312b79 |
1236 | if (myTarget == GL_TEXTURE_CUBE_MAP) |
1237 | { |
1238 | aSize *= 6; // cube sides |
1239 | } |
faff3767 |
1240 | if (myMaxMipLevel > 0) |
15669413 |
1241 | { |
1242 | aSize = aSize + aSize / 3; |
1243 | } |
1244 | return aSize; |
1245 | } |
8f8fe4a9 |
1246 | |
1247 | // ======================================================================= |
1248 | // function : ImageDump |
1249 | // purpose : |
1250 | // ======================================================================= |
1251 | bool OpenGl_Texture::ImageDump (Image_PixMap& theImage, |
1252 | const Handle(OpenGl_Context)& theCtx, |
1253 | Graphic3d_TextureUnit theTexUnit, |
1254 | Standard_Integer theLevel, |
1255 | Standard_Integer theCubeSide) const |
1256 | { |
1257 | #if !defined(GL_ES_VERSION_2_0) |
1258 | const OpenGl_TextureFormat aFormat = OpenGl_TextureFormat::FindSizedFormat (theCtx, mySizedFormat); |
1259 | if (theCtx.IsNull() |
1260 | || !IsValid() |
1261 | || theLevel < 0 |
1262 | || !aFormat.IsValid() |
1263 | || aFormat.ImageFormat() == Image_Format_UNKNOWN |
1264 | || (myTarget == GL_TEXTURE_CUBE_MAP |
1265 | && (theCubeSide < 0 || theCubeSide > 5))) |
1266 | { |
1267 | return false; |
1268 | } |
1269 | |
1270 | GLenum aTarget = myTarget; |
1271 | Graphic3d_Vec2i aSize (mySizeX, mySizeY); |
1272 | if (myTarget == GL_TEXTURE_CUBE_MAP) |
1273 | { |
1274 | aTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + theCubeSide; |
1275 | } |
1276 | for (Standard_Integer aMipIter = 0; aMipIter < theLevel; ++aMipIter) |
1277 | { |
1278 | aSize /= 2; |
1279 | if (aSize.x() == 0) { aSize.x() = 1; } |
1280 | if (aSize.y() == 0) { aSize.y() = 1; } |
1281 | } |
1282 | if (!theImage.InitTrash (aFormat.ImageFormat(), aSize.x(), aSize.y())) |
1283 | { |
1284 | return false; |
1285 | } |
1286 | |
1287 | const GLint anAligment = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL |
1288 | theCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, anAligment); |
e1d17ceb |
1289 | if (theCtx->hasPackRowLength) |
1290 | { |
1291 | theCtx->core11fwd->glPixelStorei (GL_PACK_ROW_LENGTH, 0); |
1292 | } |
8f8fe4a9 |
1293 | // glGetTextureImage() allows avoiding to binding texture id, but apparently requires clean FBO binding state... |
1294 | //if (theCtx->core45 != NULL) { theCtx->core45->glGetTextureImage (myTextureId, theLevel, aFormat.PixelFormat(), aFormat.DataType(), (GLsizei )theImage.SizeBytes(), theImage.ChangeData()); } else |
1295 | { |
1296 | Bind (theCtx, theTexUnit); |
1297 | theCtx->core11fwd->glGetTexImage (aTarget, theLevel, aFormat.PixelFormat(), aFormat.DataType(), theImage.ChangeData()); |
1298 | Unbind (theCtx, theTexUnit); |
1299 | } |
1300 | if (theImage.Format() != aFormat.ImageFormat()) |
1301 | { |
1302 | Image_PixMap::SwapRgbaBgra (theImage); |
1303 | } |
1304 | |
1305 | const bool hasErrors = theCtx->ResetErrors (true); |
1306 | theCtx->core11fwd->glPixelStorei (GL_PACK_ALIGNMENT, 1); |
1307 | return !hasErrors; |
1308 | #else |
1309 | // glGetTexImage() is unavailable in OpenGL ES |
1310 | (void )theImage; |
1311 | (void )theCtx; |
1312 | (void )theTexUnit; |
1313 | (void )theLevel; |
1314 | (void )theCubeSide; |
1315 | return false; |
1316 | #endif |
1317 | } |