0024295: vclose behavior is inconsistent
[occt.git] / src / OpenGl / OpenGl_Texture.cxx
CommitLineData
bf75be98 1// Created by: Kirill GAVRILOV
2// Copyright (c) 2012 OPEN CASCADE SAS
3//
4// The content of this file is subject to the Open CASCADE Technology Public
5// License Version 6.5 (the "License"). You may not use the content of this file
6// except in compliance with the License. Please obtain a copy of the License
7// at http://www.opencascade.org and read it completely before using this file.
8//
9// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
10// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11//
12// The Original Code and all software distributed under the License is
13// distributed on an "AS IS" basis, without warranty of any kind, and the
14// Initial Developer hereby disclaims all such warranties, including without
15// limitation, any warranties of merchantability, fitness for a particular
16// purpose or non-infringement. Please see the License for the specific terms
17// and conditions governing the rights and limitations under the License.
18
19#include <OpenGl_Texture.hxx>
20
1a7dfdb7 21#include <OpenGl_ExtFBO.hxx>
bf75be98 22#include <OpenGl_Context.hxx>
23#include <Graphic3d_TextureParams.hxx>
24#include <Standard_Assert.hxx>
25#include <Image_PixMap.hxx>
26
27IMPLEMENT_STANDARD_HANDLE (OpenGl_Texture, OpenGl_Resource)
28IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Texture, OpenGl_Resource)
29
bf75be98 30// =======================================================================
31// function : OpenGl_Texture
32// purpose :
33// =======================================================================
34OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams)
35: OpenGl_Resource(),
36 myTextureId (NO_TEXTURE),
37 myTarget (GL_TEXTURE_2D),
38 mySizeX (0),
39 mySizeY (0),
40 myTextFormat (GL_FLOAT),
41 myHasMipmaps (Standard_False),
42 myParams (theParams)
43{
44 if (myParams.IsNull())
45 {
46 myParams = new Graphic3d_TextureParams();
47 }
48}
49
50// =======================================================================
51// function : ~OpenGl_Texture
52// purpose :
53// =======================================================================
54OpenGl_Texture::~OpenGl_Texture()
55{
56 Release (NULL);
57}
58
59// =======================================================================
60// function : HasMipmaps
61// purpose :
62// =======================================================================
63const Standard_Boolean OpenGl_Texture::HasMipmaps() const
64{
65 return myHasMipmaps;
66}
67
68// =======================================================================
69// function : GetParams
70// purpose :
71// =======================================================================
72const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const
73{
74 return myParams;
75}
76
77// =======================================================================
78// function : SetParams
79// purpose :
80// =======================================================================
81void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams)
82{
83 myParams = theParams;
84}
85
86// =======================================================================
87// function : Create
88// purpose :
89// =======================================================================
90bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& )
91{
92 if (myTextureId == NO_TEXTURE)
93 {
94 glGenTextures (1, &myTextureId);
95 }
96 return myTextureId != NO_TEXTURE;
97}
98
99// =======================================================================
100// function : Release
101// purpose :
102// =======================================================================
103void OpenGl_Texture::Release (const OpenGl_Context* theGlCtx)
104{
105 if (myTextureId == NO_TEXTURE)
106 {
107 return;
108 }
109
110 // application can not handle this case by exception - this is bug in code
111 Standard_ASSERT_RETURN (theGlCtx != NULL,
112 "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
113
114 glDeleteTextures (1, &myTextureId);
115 myTextureId = NO_TEXTURE;
116 mySizeX = mySizeY = 0;
117}
118
119// =======================================================================
120// function : Bind
121// purpose :
122// =======================================================================
123void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
124 const GLenum theTextureUnit) const
125{
126 if (theCtx->IsGlGreaterEqual (1, 3))
127 {
128 theCtx->core13->glActiveTexture (theTextureUnit);
129 }
130 glBindTexture (myTarget, myTextureId);
131}
132
133// =======================================================================
134// function : Unbind
135// purpose :
136// =======================================================================
137void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
138 const GLenum theTextureUnit) const
139{
140 if (theCtx->IsGlGreaterEqual (1, 3))
141 {
142 theCtx->core13->glActiveTexture (theTextureUnit);
143 }
144 glBindTexture (myTarget, NO_TEXTURE);
145}
146
147// =======================================================================
148// function : Init
149// purpose :
150// =======================================================================
151bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
152 const Image_PixMap& theImage,
153 const Graphic3d_TypeOfTexture theType)
154{
155 myHasMipmaps = Standard_False;
156 if (theImage.IsEmpty() || !Create (theCtx))
157 {
158 return false;
159 }
160
a577aaab 161 myTextFormat = GL_RGBA8;
162 GLenum aPixelFormat = 0;
163 GLenum aDataType = 0;
bf75be98 164 switch (theImage.Format())
165 {
166 case Image_PixMap::ImgGrayF:
167 {
a577aaab 168 myTextFormat = GL_ALPHA8; // GL_R8, GL_R32F
169 aPixelFormat = GL_ALPHA; // GL_RED
170 aDataType = GL_FLOAT;
bf75be98 171 break;
172 }
173 case Image_PixMap::ImgRGBAF:
174 {
a577aaab 175 myTextFormat = GL_RGBA8; // GL_RGBA32F
176 aPixelFormat = GL_RGBA;
177 aDataType = GL_FLOAT;
bf75be98 178 break;
179 }
180 case Image_PixMap::ImgBGRAF:
181 {
182 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
183 {
184 return false;
185 }
a577aaab 186 myTextFormat = GL_RGBA8; // GL_RGBA32F
187 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
188 aDataType = GL_FLOAT;
bf75be98 189 break;
190 }
191 case Image_PixMap::ImgRGBF:
192 {
a577aaab 193 myTextFormat = GL_RGB8; // GL_RGB32F
194 aPixelFormat = GL_RGB;
195 aDataType = GL_FLOAT;
bf75be98 196 break;
197 }
198 case Image_PixMap::ImgBGRF:
199 {
a577aaab 200 myTextFormat = GL_RGB8; // GL_RGB32F
201 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
202 aDataType = GL_FLOAT;
bf75be98 203 break;
204 }
205 case Image_PixMap::ImgRGBA:
206 {
a577aaab 207 myTextFormat = GL_RGBA8;
208 aPixelFormat = GL_RGBA;
209 aDataType = GL_UNSIGNED_BYTE;
bf75be98 210 break;
211 }
212 case Image_PixMap::ImgBGRA:
213 {
214 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
215 {
216 return false;
217 }
a577aaab 218 myTextFormat = GL_RGBA8;
219 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
220 aDataType = GL_UNSIGNED_BYTE;
bf75be98 221 break;
222 }
223 case Image_PixMap::ImgRGB32:
224 {
a577aaab 225 myTextFormat = GL_RGB8;
226 aPixelFormat = GL_RGBA;
227 aDataType = GL_UNSIGNED_BYTE;
bf75be98 228 break;
229 }
230 case Image_PixMap::ImgBGR32:
231 {
232 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
233 {
234 return false;
235 }
a577aaab 236 myTextFormat = GL_RGB8;
237 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
238 aDataType = GL_UNSIGNED_BYTE;
bf75be98 239 break;
240 }
241 case Image_PixMap::ImgRGB:
242 {
a577aaab 243 myTextFormat = GL_RGB8;
244 aPixelFormat = GL_RGB;
245 aDataType = GL_UNSIGNED_BYTE;
bf75be98 246 break;
247 }
248 case Image_PixMap::ImgBGR:
249 {
250 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
251 {
252 return false;
253 }
a577aaab 254 myTextFormat = GL_RGB8;
255 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
256 aDataType = GL_UNSIGNED_BYTE;
bf75be98 257 break;
258 }
259 case Image_PixMap::ImgGray:
260 {
a577aaab 261 myTextFormat = GL_ALPHA8; // GL_R8
262 aPixelFormat = GL_ALPHA; // GL_RED
263 aDataType = GL_UNSIGNED_BYTE;
bf75be98 264 break;
265 }
266 default:
267 {
268 return false;
269 }
270 }
271
272 const GLsizei aMaxSize = theCtx->MaxTextureSize();
273 const GLsizei aWidth = (GLsizei )theImage.SizeX();
274 const GLsizei aHeight = (GLsizei )theImage.SizeY();
275
276 // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
277 // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
278 // Trying to create NPOT rextures on such hardware will not fail
279 // but driver will fall back into software rendering,
280 const bool toForceP2 = !theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW;
a174a3c5 281 const GLsizei aWidthOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aWidth, aMaxSize) : Min (aWidth, aMaxSize);
282 const GLsizei aHeightOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aHeight, aMaxSize) : Min (aHeight, aMaxSize);
bf75be98 283
284 GLint aTestWidth = 0;
285 GLint aTestHeight = 0;
286
287 glPixelStorei (GL_UNPACK_ALIGNMENT, 1); // ensure alignment will not screw up the party
288 switch (theType)
289 {
290 case Graphic3d_TOT_1D:
291 {
292 myTarget = GL_TEXTURE_1D;
293 Bind (theCtx);
294 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
295 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
296
297 Image_PixMap aCopy;
298 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
299 if (aWidth != aWidthOut)
300 {
301 if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), 1)
302 || gluScaleImage (aPixelFormat,
303 aWidth, 1, aDataType, theImage.Data(),
304 aWidthOut, 1, aDataType, aCopy.ChangeData()) != 0)
305 {
306 Unbind (theCtx);
307 return false;
308 }
309
310 aDataPtr = (GLvoid* )aCopy.Data();
311 }
312
313 // use proxy to check texture could be created or not
a577aaab 314 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, myTextFormat,
bf75be98 315 aWidthOut, 0,
316 aPixelFormat, aDataType, NULL);
317 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
318 if (aTestWidth == 0)
319 {
320 // no memory or broken input parameters
321 Unbind (theCtx);
322 return false;
323 }
324
a577aaab 325 glTexImage1D (GL_TEXTURE_1D, 0, myTextFormat,
bf75be98 326 aWidthOut, 0,
327 aPixelFormat, aDataType, aDataPtr);
a174a3c5 328 if (glGetError() != GL_NO_ERROR)
329 {
330 Unbind (theCtx);
331 return false;
332 }
333
334 mySizeX = aWidthOut;
335 mySizeY = 1;
bf75be98 336
337 Unbind (theCtx);
338 return true;
339 }
340 case Graphic3d_TOT_2D:
341 {
342 myTarget = GL_TEXTURE_2D;
343 Bind (theCtx);
344 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
345 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
346
347 Image_PixMap aCopy;
348 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
349 if (aWidth != aWidthOut || aHeight != aHeightOut)
350 {
351 // scale texture
bf75be98 352 if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), Standard_Size(aHeightOut))
353 || gluScaleImage (aPixelFormat,
354 aWidth, aHeight, aDataType, theImage.Data(),
355 aWidthOut, aHeightOut, aDataType, aCopy.ChangeData()) != 0)
356 {
357 Unbind (theCtx);
358 return false;
359 }
360
361 aDataPtr = (GLvoid* )aCopy.Data();
362 }
363
364 // use proxy to check texture could be created or not
a577aaab 365 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
bf75be98 366 aWidthOut, aHeightOut, 0,
367 aPixelFormat, aDataType, NULL);
368 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
369 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
370 if (aTestWidth == 0 || aTestHeight == 0)
371 {
372 // no memory or broken input parameters
373 Unbind (theCtx);
374 return false;
375 }
376
a577aaab 377 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
bf75be98 378 aWidthOut, aHeightOut, 0,
379 aPixelFormat, aDataType, aDataPtr);
a174a3c5 380 if (glGetError() != GL_NO_ERROR)
381 {
382 Unbind (theCtx);
383 return false;
384 }
385
386 mySizeX = aWidthOut;
387 mySizeY = aHeightOut;
bf75be98 388
389 Unbind (theCtx);
390 return true;
391 }
392 case Graphic3d_TOT_2D_MIPMAP:
393 {
394 myTarget = GL_TEXTURE_2D;
395 myHasMipmaps = Standard_True;
396 Bind (theCtx);
397 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
398 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
399
1a7dfdb7 400 if (theCtx->extFBO != NULL
401 && aWidth == aWidthOut && aHeight == aHeightOut)
402 {
403 // use proxy to check texture could be created or not
a577aaab 404 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
1a7dfdb7 405 aWidthOut, aHeightOut, 0,
406 aPixelFormat, aDataType, NULL);
407 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
408 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
409 if (aTestWidth == 0 || aTestHeight == 0)
410 {
411 // no memory or broken input parameters
412 Unbind (theCtx);
413 return false;
414 }
415
416 // upload main picture
a577aaab 417 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
1a7dfdb7 418 aWidthOut, aHeightOut, 0,
419 aPixelFormat, aDataType, theImage.Data());
a174a3c5 420 if (glGetError() != GL_NO_ERROR)
421 {
422 Unbind (theCtx);
423 return false;
424 }
425
426 mySizeX = aWidthOut;
427 mySizeY = aHeightOut;
1a7dfdb7 428
429 // generate mipmaps
430 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
431 theCtx->extFBO->glGenerateMipmapEXT (GL_TEXTURE_2D);
432
433 Unbind (theCtx);
434 return true;
435 }
436 else
437 {
a577aaab 438 bool isCreated = gluBuild2DMipmaps (GL_TEXTURE_2D, myTextFormat,
1a7dfdb7 439 aWidth, aHeight,
440 aPixelFormat, aDataType, theImage.Data()) == 0;
a174a3c5 441 if (isCreated)
442 {
443 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &mySizeX);
444 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &mySizeY);
445 }
446
1a7dfdb7 447 Unbind (theCtx);
448 return isCreated;
449 }
bf75be98 450 }
451 default:
452 {
453 return false;
454 }
455 }
456}