0024336: Content of OCCT documentation should be updated. Iter 2
[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
ec2eeb2d 114 if (theGlCtx->IsValid())
115 {
116 glDeleteTextures (1, &myTextureId);
117 }
bf75be98 118 myTextureId = NO_TEXTURE;
119 mySizeX = mySizeY = 0;
120}
121
122// =======================================================================
123// function : Bind
124// purpose :
125// =======================================================================
126void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
127 const GLenum theTextureUnit) const
128{
129 if (theCtx->IsGlGreaterEqual (1, 3))
130 {
131 theCtx->core13->glActiveTexture (theTextureUnit);
132 }
133 glBindTexture (myTarget, myTextureId);
134}
135
136// =======================================================================
137// function : Unbind
138// purpose :
139// =======================================================================
140void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
141 const GLenum theTextureUnit) const
142{
143 if (theCtx->IsGlGreaterEqual (1, 3))
144 {
145 theCtx->core13->glActiveTexture (theTextureUnit);
146 }
147 glBindTexture (myTarget, NO_TEXTURE);
148}
149
150// =======================================================================
151// function : Init
152// purpose :
153// =======================================================================
154bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
155 const Image_PixMap& theImage,
156 const Graphic3d_TypeOfTexture theType)
157{
158 myHasMipmaps = Standard_False;
159 if (theImage.IsEmpty() || !Create (theCtx))
160 {
161 return false;
162 }
163
a577aaab 164 myTextFormat = GL_RGBA8;
165 GLenum aPixelFormat = 0;
166 GLenum aDataType = 0;
bf75be98 167 switch (theImage.Format())
168 {
169 case Image_PixMap::ImgGrayF:
170 {
a577aaab 171 myTextFormat = GL_ALPHA8; // GL_R8, GL_R32F
172 aPixelFormat = GL_ALPHA; // GL_RED
173 aDataType = GL_FLOAT;
bf75be98 174 break;
175 }
176 case Image_PixMap::ImgRGBAF:
177 {
a577aaab 178 myTextFormat = GL_RGBA8; // GL_RGBA32F
179 aPixelFormat = GL_RGBA;
180 aDataType = GL_FLOAT;
bf75be98 181 break;
182 }
183 case Image_PixMap::ImgBGRAF:
184 {
185 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
186 {
187 return false;
188 }
a577aaab 189 myTextFormat = GL_RGBA8; // GL_RGBA32F
190 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
191 aDataType = GL_FLOAT;
bf75be98 192 break;
193 }
194 case Image_PixMap::ImgRGBF:
195 {
a577aaab 196 myTextFormat = GL_RGB8; // GL_RGB32F
197 aPixelFormat = GL_RGB;
198 aDataType = GL_FLOAT;
bf75be98 199 break;
200 }
201 case Image_PixMap::ImgBGRF:
202 {
a577aaab 203 myTextFormat = GL_RGB8; // GL_RGB32F
204 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
205 aDataType = GL_FLOAT;
bf75be98 206 break;
207 }
208 case Image_PixMap::ImgRGBA:
209 {
a577aaab 210 myTextFormat = GL_RGBA8;
211 aPixelFormat = GL_RGBA;
212 aDataType = GL_UNSIGNED_BYTE;
bf75be98 213 break;
214 }
215 case Image_PixMap::ImgBGRA:
216 {
217 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
218 {
219 return false;
220 }
a577aaab 221 myTextFormat = GL_RGBA8;
222 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
223 aDataType = GL_UNSIGNED_BYTE;
bf75be98 224 break;
225 }
226 case Image_PixMap::ImgRGB32:
227 {
a577aaab 228 myTextFormat = GL_RGB8;
229 aPixelFormat = GL_RGBA;
230 aDataType = GL_UNSIGNED_BYTE;
bf75be98 231 break;
232 }
233 case Image_PixMap::ImgBGR32:
234 {
235 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
236 {
237 return false;
238 }
a577aaab 239 myTextFormat = GL_RGB8;
240 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
241 aDataType = GL_UNSIGNED_BYTE;
bf75be98 242 break;
243 }
244 case Image_PixMap::ImgRGB:
245 {
a577aaab 246 myTextFormat = GL_RGB8;
247 aPixelFormat = GL_RGB;
248 aDataType = GL_UNSIGNED_BYTE;
bf75be98 249 break;
250 }
251 case Image_PixMap::ImgBGR:
252 {
253 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
254 {
255 return false;
256 }
a577aaab 257 myTextFormat = GL_RGB8;
258 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
259 aDataType = GL_UNSIGNED_BYTE;
bf75be98 260 break;
261 }
262 case Image_PixMap::ImgGray:
263 {
a577aaab 264 myTextFormat = GL_ALPHA8; // GL_R8
265 aPixelFormat = GL_ALPHA; // GL_RED
266 aDataType = GL_UNSIGNED_BYTE;
bf75be98 267 break;
268 }
269 default:
270 {
271 return false;
272 }
273 }
274
275 const GLsizei aMaxSize = theCtx->MaxTextureSize();
276 const GLsizei aWidth = (GLsizei )theImage.SizeX();
277 const GLsizei aHeight = (GLsizei )theImage.SizeY();
278
279 // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
280 // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
281 // Trying to create NPOT rextures on such hardware will not fail
282 // but driver will fall back into software rendering,
283 const bool toForceP2 = !theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW;
a174a3c5 284 const GLsizei aWidthOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aWidth, aMaxSize) : Min (aWidth, aMaxSize);
285 const GLsizei aHeightOut = toForceP2 ? OpenGl_Context::GetPowerOfTwo (aHeight, aMaxSize) : Min (aHeight, aMaxSize);
bf75be98 286
287 GLint aTestWidth = 0;
288 GLint aTestHeight = 0;
289
290 glPixelStorei (GL_UNPACK_ALIGNMENT, 1); // ensure alignment will not screw up the party
291 switch (theType)
292 {
293 case Graphic3d_TOT_1D:
294 {
295 myTarget = GL_TEXTURE_1D;
296 Bind (theCtx);
297 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
298 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
299
300 Image_PixMap aCopy;
301 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
302 if (aWidth != aWidthOut)
303 {
304 if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), 1)
305 || gluScaleImage (aPixelFormat,
306 aWidth, 1, aDataType, theImage.Data(),
307 aWidthOut, 1, aDataType, aCopy.ChangeData()) != 0)
308 {
309 Unbind (theCtx);
310 return false;
311 }
312
313 aDataPtr = (GLvoid* )aCopy.Data();
314 }
315
316 // use proxy to check texture could be created or not
a577aaab 317 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, myTextFormat,
bf75be98 318 aWidthOut, 0,
319 aPixelFormat, aDataType, NULL);
320 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
321 if (aTestWidth == 0)
322 {
323 // no memory or broken input parameters
324 Unbind (theCtx);
325 return false;
326 }
327
a577aaab 328 glTexImage1D (GL_TEXTURE_1D, 0, myTextFormat,
bf75be98 329 aWidthOut, 0,
330 aPixelFormat, aDataType, aDataPtr);
a174a3c5 331 if (glGetError() != GL_NO_ERROR)
332 {
333 Unbind (theCtx);
334 return false;
335 }
336
337 mySizeX = aWidthOut;
338 mySizeY = 1;
bf75be98 339
340 Unbind (theCtx);
341 return true;
342 }
343 case Graphic3d_TOT_2D:
344 {
345 myTarget = GL_TEXTURE_2D;
346 Bind (theCtx);
347 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
348 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
349
350 Image_PixMap aCopy;
351 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
352 if (aWidth != aWidthOut || aHeight != aHeightOut)
353 {
354 // scale texture
bf75be98 355 if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), Standard_Size(aHeightOut))
356 || gluScaleImage (aPixelFormat,
357 aWidth, aHeight, aDataType, theImage.Data(),
358 aWidthOut, aHeightOut, aDataType, aCopy.ChangeData()) != 0)
359 {
360 Unbind (theCtx);
361 return false;
362 }
363
364 aDataPtr = (GLvoid* )aCopy.Data();
365 }
366
367 // use proxy to check texture could be created or not
a577aaab 368 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
bf75be98 369 aWidthOut, aHeightOut, 0,
370 aPixelFormat, aDataType, NULL);
371 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
372 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
373 if (aTestWidth == 0 || aTestHeight == 0)
374 {
375 // no memory or broken input parameters
376 Unbind (theCtx);
377 return false;
378 }
379
a577aaab 380 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
bf75be98 381 aWidthOut, aHeightOut, 0,
382 aPixelFormat, aDataType, aDataPtr);
a174a3c5 383 if (glGetError() != GL_NO_ERROR)
384 {
385 Unbind (theCtx);
386 return false;
387 }
388
389 mySizeX = aWidthOut;
390 mySizeY = aHeightOut;
bf75be98 391
392 Unbind (theCtx);
393 return true;
394 }
395 case Graphic3d_TOT_2D_MIPMAP:
396 {
397 myTarget = GL_TEXTURE_2D;
398 myHasMipmaps = Standard_True;
399 Bind (theCtx);
400 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
401 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
402
1a7dfdb7 403 if (theCtx->extFBO != NULL
404 && aWidth == aWidthOut && aHeight == aHeightOut)
405 {
406 // use proxy to check texture could be created or not
a577aaab 407 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, myTextFormat,
1a7dfdb7 408 aWidthOut, aHeightOut, 0,
409 aPixelFormat, aDataType, NULL);
410 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
411 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
412 if (aTestWidth == 0 || aTestHeight == 0)
413 {
414 // no memory or broken input parameters
415 Unbind (theCtx);
416 return false;
417 }
418
419 // upload main picture
a577aaab 420 glTexImage2D (GL_TEXTURE_2D, 0, myTextFormat,
1a7dfdb7 421 aWidthOut, aHeightOut, 0,
422 aPixelFormat, aDataType, theImage.Data());
a174a3c5 423 if (glGetError() != GL_NO_ERROR)
424 {
425 Unbind (theCtx);
426 return false;
427 }
428
429 mySizeX = aWidthOut;
430 mySizeY = aHeightOut;
1a7dfdb7 431
432 // generate mipmaps
433 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
434 theCtx->extFBO->glGenerateMipmapEXT (GL_TEXTURE_2D);
435
436 Unbind (theCtx);
437 return true;
438 }
439 else
440 {
a577aaab 441 bool isCreated = gluBuild2DMipmaps (GL_TEXTURE_2D, myTextFormat,
1a7dfdb7 442 aWidth, aHeight,
443 aPixelFormat, aDataType, theImage.Data()) == 0;
a174a3c5 444 if (isCreated)
445 {
446 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &mySizeX);
447 glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &mySizeY);
448 }
449
1a7dfdb7 450 Unbind (theCtx);
451 return isCreated;
452 }
bf75be98 453 }
454 default:
455 {
456 return false;
457 }
458 }
459}