0023722: stack overflow during reading IGES in Test Harness
[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
30//! Function for getting power of to number larger or equal to input number.
31//! @param theNumber number to 'power of two'
32//! @param theThreshold upper threshold
33//! @return power of two number
34inline GLsizei getPowerOfTwo (const GLsizei theNumber,
35 const GLsizei theThreshold)
36{
37 for (GLsizei p2 = 2; p2 <= theThreshold; p2 <<= 1)
38 {
39 if (theNumber <= p2)
40 {
41 return p2;
42 }
43 }
44 return theThreshold;
45}
46
47// =======================================================================
48// function : OpenGl_Texture
49// purpose :
50// =======================================================================
51OpenGl_Texture::OpenGl_Texture (const Handle(Graphic3d_TextureParams)& theParams)
52: OpenGl_Resource(),
53 myTextureId (NO_TEXTURE),
54 myTarget (GL_TEXTURE_2D),
55 mySizeX (0),
56 mySizeY (0),
57 myTextFormat (GL_FLOAT),
58 myHasMipmaps (Standard_False),
59 myParams (theParams)
60{
61 if (myParams.IsNull())
62 {
63 myParams = new Graphic3d_TextureParams();
64 }
65}
66
67// =======================================================================
68// function : ~OpenGl_Texture
69// purpose :
70// =======================================================================
71OpenGl_Texture::~OpenGl_Texture()
72{
73 Release (NULL);
74}
75
76// =======================================================================
77// function : HasMipmaps
78// purpose :
79// =======================================================================
80const Standard_Boolean OpenGl_Texture::HasMipmaps() const
81{
82 return myHasMipmaps;
83}
84
85// =======================================================================
86// function : GetParams
87// purpose :
88// =======================================================================
89const Handle(Graphic3d_TextureParams)& OpenGl_Texture::GetParams() const
90{
91 return myParams;
92}
93
94// =======================================================================
95// function : SetParams
96// purpose :
97// =======================================================================
98void OpenGl_Texture::SetParams (const Handle(Graphic3d_TextureParams)& theParams)
99{
100 myParams = theParams;
101}
102
103// =======================================================================
104// function : Create
105// purpose :
106// =======================================================================
107bool OpenGl_Texture::Create (const Handle(OpenGl_Context)& )
108{
109 if (myTextureId == NO_TEXTURE)
110 {
111 glGenTextures (1, &myTextureId);
112 }
113 return myTextureId != NO_TEXTURE;
114}
115
116// =======================================================================
117// function : Release
118// purpose :
119// =======================================================================
120void OpenGl_Texture::Release (const OpenGl_Context* theGlCtx)
121{
122 if (myTextureId == NO_TEXTURE)
123 {
124 return;
125 }
126
127 // application can not handle this case by exception - this is bug in code
128 Standard_ASSERT_RETURN (theGlCtx != NULL,
129 "OpenGl_Texture destroyed without GL context! Possible GPU memory leakage...",);
130
131 glDeleteTextures (1, &myTextureId);
132 myTextureId = NO_TEXTURE;
133 mySizeX = mySizeY = 0;
134}
135
136// =======================================================================
137// function : Bind
138// purpose :
139// =======================================================================
140void OpenGl_Texture::Bind (const Handle(OpenGl_Context)& theCtx,
141 const GLenum theTextureUnit) const
142{
143 if (theCtx->IsGlGreaterEqual (1, 3))
144 {
145 theCtx->core13->glActiveTexture (theTextureUnit);
146 }
147 glBindTexture (myTarget, myTextureId);
148}
149
150// =======================================================================
151// function : Unbind
152// purpose :
153// =======================================================================
154void OpenGl_Texture::Unbind (const Handle(OpenGl_Context)& theCtx,
155 const GLenum theTextureUnit) const
156{
157 if (theCtx->IsGlGreaterEqual (1, 3))
158 {
159 theCtx->core13->glActiveTexture (theTextureUnit);
160 }
161 glBindTexture (myTarget, NO_TEXTURE);
162}
163
164// =======================================================================
165// function : Init
166// purpose :
167// =======================================================================
168bool OpenGl_Texture::Init (const Handle(OpenGl_Context)& theCtx,
169 const Image_PixMap& theImage,
170 const Graphic3d_TypeOfTexture theType)
171{
172 myHasMipmaps = Standard_False;
173 if (theImage.IsEmpty() || !Create (theCtx))
174 {
175 return false;
176 }
177
178 GLenum aTextureFormat = GL_RGBA8;
179 GLenum aPixelFormat = 0;
180 GLenum aDataType = 0;
181 switch (theImage.Format())
182 {
183 case Image_PixMap::ImgGrayF:
184 {
185 aTextureFormat = GL_ALPHA8; // GL_R8, GL_R32F
186 aPixelFormat = GL_ALPHA; // GL_RED
187 aDataType = GL_FLOAT;
188 break;
189 }
190 case Image_PixMap::ImgRGBAF:
191 {
192 aTextureFormat = GL_RGBA8; // GL_RGBA32F
193 aPixelFormat = GL_RGBA;
194 aDataType = GL_FLOAT;
195 break;
196 }
197 case Image_PixMap::ImgBGRAF:
198 {
199 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
200 {
201 return false;
202 }
203 aTextureFormat = GL_RGBA8; // GL_RGBA32F
204 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
205 aDataType = GL_FLOAT;
206 break;
207 }
208 case Image_PixMap::ImgRGBF:
209 {
210 aTextureFormat = GL_RGB8; // GL_RGB32F
211 aPixelFormat = GL_RGB;
212 aDataType = GL_FLOAT;
213 break;
214 }
215 case Image_PixMap::ImgBGRF:
216 {
217 aTextureFormat = GL_RGB8; // GL_RGB32F
218 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
219 aDataType = GL_FLOAT;
220 break;
221 }
222 case Image_PixMap::ImgRGBA:
223 {
224 aTextureFormat = GL_RGBA8;
225 aPixelFormat = GL_RGBA;
226 aDataType = GL_UNSIGNED_BYTE;
227 break;
228 }
229 case Image_PixMap::ImgBGRA:
230 {
231 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
232 {
233 return false;
234 }
235 aTextureFormat = GL_RGBA8;
236 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
237 aDataType = GL_UNSIGNED_BYTE;
238 break;
239 }
240 case Image_PixMap::ImgRGB32:
241 {
242 aTextureFormat = GL_RGB8;
243 aPixelFormat = GL_RGBA;
244 aDataType = GL_UNSIGNED_BYTE;
245 break;
246 }
247 case Image_PixMap::ImgBGR32:
248 {
249 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
250 {
251 return false;
252 }
253 aTextureFormat = GL_RGB8;
254 aPixelFormat = GL_BGRA; // equals to GL_BGRA_EXT
255 aDataType = GL_UNSIGNED_BYTE;
256 break;
257 }
258 case Image_PixMap::ImgRGB:
259 {
260 aTextureFormat = GL_RGB8;
261 aPixelFormat = GL_RGB;
262 aDataType = GL_UNSIGNED_BYTE;
263 break;
264 }
265 case Image_PixMap::ImgBGR:
266 {
267 if (!theCtx->IsGlGreaterEqual (1, 2) && !theCtx->extBgra)
268 {
269 return false;
270 }
271 aTextureFormat = GL_RGB8;
272 aPixelFormat = GL_BGR; // equals to GL_BGR_EXT
273 aDataType = GL_UNSIGNED_BYTE;
274 break;
275 }
276 case Image_PixMap::ImgGray:
277 {
278 aTextureFormat = GL_ALPHA8; // GL_R8
279 aPixelFormat = GL_ALPHA; // GL_RED
280 aDataType = GL_UNSIGNED_BYTE;
281 break;
282 }
283 default:
284 {
285 return false;
286 }
287 }
288
289 const GLsizei aMaxSize = theCtx->MaxTextureSize();
290 const GLsizei aWidth = (GLsizei )theImage.SizeX();
291 const GLsizei aHeight = (GLsizei )theImage.SizeY();
292
293 // Notice that formally general NPOT textures are required by OpenGL 2.0 specifications
294 // however some hardware (NV30 - GeForce FX, RadeOn 9xxx and Xxxx) supports GLSL but not NPOT!
295 // Trying to create NPOT rextures on such hardware will not fail
296 // but driver will fall back into software rendering,
297 const bool toForceP2 = !theCtx->IsGlGreaterEqual (3, 0) && !theCtx->arbNPTW;
298 const GLsizei aWidthOut = toForceP2 ? getPowerOfTwo (aWidth, aMaxSize) : Min (aWidth, aMaxSize);
299 const GLsizei aHeightOut = toForceP2 ? getPowerOfTwo (aHeight, aMaxSize) : Min (aHeight, aMaxSize);
300
301 GLint aTestWidth = 0;
302 GLint aTestHeight = 0;
303
304 glPixelStorei (GL_UNPACK_ALIGNMENT, 1); // ensure alignment will not screw up the party
305 switch (theType)
306 {
307 case Graphic3d_TOT_1D:
308 {
309 myTarget = GL_TEXTURE_1D;
310 Bind (theCtx);
311 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
312 glTexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
313
314 Image_PixMap aCopy;
315 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
316 if (aWidth != aWidthOut)
317 {
318 if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), 1)
319 || gluScaleImage (aPixelFormat,
320 aWidth, 1, aDataType, theImage.Data(),
321 aWidthOut, 1, aDataType, aCopy.ChangeData()) != 0)
322 {
323 Unbind (theCtx);
324 return false;
325 }
326
327 aDataPtr = (GLvoid* )aCopy.Data();
328 }
329
330 // use proxy to check texture could be created or not
331 glTexImage1D (GL_PROXY_TEXTURE_1D, 0, aTextureFormat,
332 aWidthOut, 0,
333 aPixelFormat, aDataType, NULL);
334 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
335 if (aTestWidth == 0)
336 {
337 // no memory or broken input parameters
338 Unbind (theCtx);
339 return false;
340 }
341
342 glTexImage1D (GL_TEXTURE_1D, 0, aTextureFormat,
343 aWidthOut, 0,
344 aPixelFormat, aDataType, aDataPtr);
345
346 Unbind (theCtx);
347 return true;
348 }
349 case Graphic3d_TOT_2D:
350 {
351 myTarget = GL_TEXTURE_2D;
352 Bind (theCtx);
353 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
354 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
355
356 Image_PixMap aCopy;
357 GLvoid* aDataPtr = (GLvoid* )theImage.Data();
358 if (aWidth != aWidthOut || aHeight != aHeightOut)
359 {
360 // scale texture
bf75be98 361 if (!aCopy.InitTrash (theImage.Format(), Standard_Size(aWidthOut), Standard_Size(aHeightOut))
362 || gluScaleImage (aPixelFormat,
363 aWidth, aHeight, aDataType, theImage.Data(),
364 aWidthOut, aHeightOut, aDataType, aCopy.ChangeData()) != 0)
365 {
366 Unbind (theCtx);
367 return false;
368 }
369
370 aDataPtr = (GLvoid* )aCopy.Data();
371 }
372
373 // use proxy to check texture could be created or not
374 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, aTextureFormat,
375 aWidthOut, aHeightOut, 0,
376 aPixelFormat, aDataType, NULL);
377 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
378 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
379 if (aTestWidth == 0 || aTestHeight == 0)
380 {
381 // no memory or broken input parameters
382 Unbind (theCtx);
383 return false;
384 }
385
386 glTexImage2D (GL_TEXTURE_2D, 0, aTextureFormat,
387 aWidthOut, aHeightOut, 0,
388 aPixelFormat, aDataType, aDataPtr);
389
390 Unbind (theCtx);
391 return true;
392 }
393 case Graphic3d_TOT_2D_MIPMAP:
394 {
395 myTarget = GL_TEXTURE_2D;
396 myHasMipmaps = Standard_True;
397 Bind (theCtx);
398 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
399 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
400
1a7dfdb7 401 if (theCtx->extFBO != NULL
402 && aWidth == aWidthOut && aHeight == aHeightOut)
403 {
404 // use proxy to check texture could be created or not
405 glTexImage2D (GL_PROXY_TEXTURE_2D, 0, aTextureFormat,
406 aWidthOut, aHeightOut, 0,
407 aPixelFormat, aDataType, NULL);
408 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &aTestWidth);
409 glGetTexLevelParameteriv (GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &aTestHeight);
410 if (aTestWidth == 0 || aTestHeight == 0)
411 {
412 // no memory or broken input parameters
413 Unbind (theCtx);
414 return false;
415 }
416
417 // upload main picture
418 glTexImage2D (GL_TEXTURE_2D, 0, aTextureFormat,
419 aWidthOut, aHeightOut, 0,
420 aPixelFormat, aDataType, theImage.Data());
421
422 // generate mipmaps
423 //glHint (GL_GENERATE_MIPMAP_HINT, GL_NICEST);
424 theCtx->extFBO->glGenerateMipmapEXT (GL_TEXTURE_2D);
425
426 Unbind (theCtx);
427 return true;
428 }
429 else
430 {
431 bool isCreated = gluBuild2DMipmaps (GL_TEXTURE_2D, aTextureFormat,
432 aWidth, aHeight,
433 aPixelFormat, aDataType, theImage.Data()) == 0;
434 Unbind (theCtx);
435 return isCreated;
436 }
bf75be98 437 }
438 default:
439 {
440 return false;
441 }
442 }
443}