aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/COpenGLTexture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/COpenGLTexture.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/source/Irrlicht/COpenGLTexture.cpp963
1 files changed, 963 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/COpenGLTexture.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/COpenGLTexture.cpp
new file mode 100644
index 0000000..3cc41c0
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/source/Irrlicht/COpenGLTexture.cpp
@@ -0,0 +1,963 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#include "IrrCompileConfig.h"
6
7#ifdef _IRR_COMPILE_WITH_OPENGL_
8
9#include "irrTypes.h"
10#include "COpenGLTexture.h"
11#include "COpenGLDriver.h"
12#include "os.h"
13#include "CColorConverter.h"
14
15#include "irrString.h"
16
17namespace irr
18{
19namespace video
20{
21
22//! constructor for usual textures
23COpenGLTexture::COpenGLTexture(IImage* origImage, const io::path& name, void* mipmapData, COpenGLDriver* driver)
24 : ITexture(name), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0), MipImage(0),
25 TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT),
26 PixelType(GL_UNSIGNED_BYTE), MipLevelStored(0), MipmapLegacyMode(true),
27 IsRenderTarget(false), AutomaticMipmapUpdate(false),
28 ReadOnlyLock(false), KeepImage(true)
29{
30 #ifdef _DEBUG
31 setDebugName("COpenGLTexture");
32 #endif
33
34 HasMipMaps = Driver->getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);
35 getImageValues(origImage);
36
37 glGenTextures(1, &TextureName);
38
39 if (ImageSize==TextureSize)
40 {
41 Image = Driver->createImage(ColorFormat, ImageSize);
42 origImage->copyTo(Image);
43 }
44 else
45 {
46 Image = Driver->createImage(ColorFormat, TextureSize);
47 // scale texture
48 origImage->copyToScaling(Image);
49 }
50 uploadTexture(true, mipmapData);
51 if (!KeepImage)
52 {
53 Image->drop();
54 Image=0;
55 }
56}
57
58
59//! constructor for basic setup (only for derived classes)
60COpenGLTexture::COpenGLTexture(const io::path& name, COpenGLDriver* driver)
61 : ITexture(name), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0), MipImage(0),
62 TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT),
63 PixelType(GL_UNSIGNED_BYTE), MipLevelStored(0), HasMipMaps(true),
64 MipmapLegacyMode(true), IsRenderTarget(false), AutomaticMipmapUpdate(false),
65 ReadOnlyLock(false), KeepImage(true)
66{
67 #ifdef _DEBUG
68 setDebugName("COpenGLTexture");
69 #endif
70}
71
72
73//! destructor
74COpenGLTexture::~COpenGLTexture()
75{
76 if (TextureName)
77 glDeleteTextures(1, &TextureName);
78 if (Image)
79 Image->drop();
80}
81
82
83//! Choose best matching color format, based on texture creation flags
84ECOLOR_FORMAT COpenGLTexture::getBestColorFormat(ECOLOR_FORMAT format)
85{
86 ECOLOR_FORMAT destFormat = ECF_A8R8G8B8;
87 switch (format)
88 {
89 case ECF_A1R5G5B5:
90 if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT))
91 destFormat = ECF_A1R5G5B5;
92 break;
93 case ECF_R5G6B5:
94 if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT))
95 destFormat = ECF_A1R5G5B5;
96 break;
97 case ECF_A8R8G8B8:
98 if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) ||
99 Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))
100 destFormat = ECF_A1R5G5B5;
101 break;
102 case ECF_R8G8B8:
103 if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) ||
104 Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))
105 destFormat = ECF_A1R5G5B5;
106 default:
107 break;
108 }
109 if (Driver->getTextureCreationFlag(ETCF_NO_ALPHA_CHANNEL))
110 {
111 switch (destFormat)
112 {
113 case ECF_A1R5G5B5:
114 destFormat = ECF_R5G6B5;
115 break;
116 case ECF_A8R8G8B8:
117 destFormat = ECF_R8G8B8;
118 break;
119 default:
120 break;
121 }
122 }
123 return destFormat;
124}
125
126
127//! Get opengl values for the GPU texture storage
128GLint COpenGLTexture::getOpenGLFormatAndParametersFromColorFormat(ECOLOR_FORMAT format,
129 GLint& filtering,
130 GLenum& colorformat,
131 GLenum& type)
132{
133 // default
134 filtering = GL_LINEAR;
135 colorformat = GL_RGBA;
136 type = GL_UNSIGNED_BYTE;
137 GLenum internalformat = GL_RGBA;
138
139 switch(format)
140 {
141 case ECF_A1R5G5B5:
142 colorformat=GL_BGRA_EXT;
143 type=GL_UNSIGNED_SHORT_1_5_5_5_REV;
144 internalformat = GL_RGBA;
145 break;
146 case ECF_R5G6B5:
147 colorformat=GL_RGB;
148 type=GL_UNSIGNED_SHORT_5_6_5;
149 internalformat = GL_RGB;
150 break;
151 case ECF_R8G8B8:
152 colorformat=GL_BGR;
153 type=GL_UNSIGNED_BYTE;
154 internalformat = GL_RGB;
155 break;
156 case ECF_A8R8G8B8:
157 colorformat=GL_BGRA_EXT;
158 if (Driver->Version > 101)
159 type=GL_UNSIGNED_INT_8_8_8_8_REV;
160 internalformat = GL_RGBA;
161 break;
162 // Floating Point texture formats. Thanks to Patryk "Nadro" Nadrowski.
163 case ECF_R16F:
164 {
165#ifdef GL_ARB_texture_rg
166 filtering = GL_NEAREST;
167 colorformat = GL_RED;
168 type = GL_FLOAT;
169
170 internalformat = GL_R16F;
171#else
172 ColorFormat = ECF_A8R8G8B8;
173 internalformat = GL_RGB8;
174#endif
175 }
176 break;
177 case ECF_G16R16F:
178 {
179#ifdef GL_ARB_texture_rg
180 filtering = GL_NEAREST;
181 colorformat = GL_RG;
182 type = GL_FLOAT;
183
184 internalformat = GL_RG16F;
185#else
186 ColorFormat = ECF_A8R8G8B8;
187 internalformat = GL_RGB8;
188#endif
189 }
190 break;
191 case ECF_A16B16G16R16F:
192 {
193#ifdef GL_ARB_texture_rg
194 filtering = GL_NEAREST;
195 colorformat = GL_RGBA;
196 type = GL_FLOAT;
197
198 internalformat = GL_RGBA16F_ARB;
199#else
200 ColorFormat = ECF_A8R8G8B8;
201 internalformat = GL_RGBA8;
202#endif
203 }
204 break;
205 case ECF_R32F:
206 {
207#ifdef GL_ARB_texture_rg
208 filtering = GL_NEAREST;
209 colorformat = GL_RED;
210 type = GL_FLOAT;
211
212 internalformat = GL_R32F;
213#else
214 ColorFormat = ECF_A8R8G8B8;
215 internalformat = GL_RGB8;
216#endif
217 }
218 break;
219 case ECF_G32R32F:
220 {
221#ifdef GL_ARB_texture_rg
222 filtering = GL_NEAREST;
223 colorformat = GL_RG;
224 type = GL_FLOAT;
225
226 internalformat = GL_RG32F;
227#else
228 ColorFormat = ECF_A8R8G8B8;
229 internalformat = GL_RGB8;
230#endif
231 }
232 break;
233 case ECF_A32B32G32R32F:
234 {
235#ifdef GL_ARB_texture_float
236 filtering = GL_NEAREST;
237 colorformat = GL_RGBA;
238 type = GL_FLOAT;
239
240 internalformat = GL_RGBA32F_ARB;
241#else
242 ColorFormat = ECF_A8R8G8B8;
243 internalformat = GL_RGBA8;
244#endif
245 }
246 break;
247 default:
248 {
249 os::Printer::log("Unsupported texture format", ELL_ERROR);
250 internalformat = GL_RGBA8;
251 }
252 }
253#if defined(GL_ARB_framebuffer_sRGB) || defined(GL_EXT_framebuffer_sRGB)
254 if (Driver->Params.HandleSRGB)
255 {
256 if (internalformat==GL_RGBA)
257 internalformat=GL_SRGB_ALPHA_EXT;
258 else if (internalformat==GL_RGB)
259 internalformat=GL_SRGB_EXT;
260 }
261#endif
262 return internalformat;
263}
264
265
266// prepare values ImageSize, TextureSize, and ColorFormat based on image
267void COpenGLTexture::getImageValues(IImage* image)
268{
269 if (!image)
270 {
271 os::Printer::log("No image for OpenGL texture.", ELL_ERROR);
272 return;
273 }
274
275 ImageSize = image->getDimension();
276
277 if ( !ImageSize.Width || !ImageSize.Height)
278 {
279 os::Printer::log("Invalid size of image for OpenGL Texture.", ELL_ERROR);
280 return;
281 }
282
283 const f32 ratio = (f32)ImageSize.Width/(f32)ImageSize.Height;
284 if ((ImageSize.Width>Driver->MaxTextureSize) && (ratio >= 1.0f))
285 {
286 ImageSize.Width = Driver->MaxTextureSize;
287 ImageSize.Height = (u32)(Driver->MaxTextureSize/ratio);
288 }
289 else if (ImageSize.Height>Driver->MaxTextureSize)
290 {
291 ImageSize.Height = Driver->MaxTextureSize;
292 ImageSize.Width = (u32)(Driver->MaxTextureSize*ratio);
293 }
294 TextureSize=ImageSize.getOptimalSize(!Driver->queryFeature(EVDF_TEXTURE_NPOT));
295
296 ColorFormat = getBestColorFormat(image->getColorFormat());
297}
298
299
300//! copies the the texture into an open gl texture.
301void COpenGLTexture::uploadTexture(bool newTexture, void* mipmapData, u32 level)
302{
303 // check which image needs to be uploaded
304 IImage* image = level?MipImage:Image;
305 if (!image)
306 {
307 os::Printer::log("No image for OpenGL texture to upload", ELL_ERROR);
308 return;
309 }
310
311 // get correct opengl color data values
312 GLenum oldInternalFormat = InternalFormat;
313 GLint filtering;
314 InternalFormat = getOpenGLFormatAndParametersFromColorFormat(ColorFormat, filtering, PixelFormat, PixelType);
315 // make sure we don't change the internal format of existing images
316 if (!newTexture)
317 InternalFormat=oldInternalFormat;
318
319 Driver->setActiveTexture(0, this);
320 if (Driver->testGLError())
321 os::Printer::log("Could not bind Texture", ELL_ERROR);
322
323 // mipmap handling for main texture
324 if (!level && newTexture)
325 {
326#ifndef DISABLE_MIPMAPPING
327#ifdef GL_SGIS_generate_mipmap
328 // auto generate if possible and no mipmap data is given
329 if (HasMipMaps && !mipmapData && Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE))
330 {
331 if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))
332 glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST);
333 else if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY))
334 glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
335 else
336 glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_DONT_CARE);
337
338 AutomaticMipmapUpdate=true;
339
340 if (!Driver->queryFeature(EVDF_FRAMEBUFFER_OBJECT))
341 {
342 glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
343 MipmapLegacyMode=true;
344 }
345 else
346 MipmapLegacyMode=false;
347 }
348 else
349#endif
350 {
351 // Either generate manually due to missing capability
352 // or use predefined mipmap data
353 AutomaticMipmapUpdate=false;
354 regenerateMipMapLevels(mipmapData);
355 }
356 if (HasMipMaps) // might have changed in regenerateMipMapLevels
357 {
358 // enable bilinear mipmap filter
359 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
360 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
361 }
362 else
363#else
364 HasMipMaps=false;
365 os::Printer::log("Did not create OpenGL texture mip maps.", ELL_INFORMATION);
366#endif
367 {
368 // enable bilinear filter without mipmaps
369 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
370 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
371 }
372 }
373
374 // now get image data and upload to GPU
375 void* source = image->lock();
376 if (newTexture)
377 glTexImage2D(GL_TEXTURE_2D, level, InternalFormat, image->getDimension().Width,
378 image->getDimension().Height, 0, PixelFormat, PixelType, source);
379 else
380 glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, image->getDimension().Width,
381 image->getDimension().Height, PixelFormat, PixelType, source);
382 image->unlock();
383
384 if (!MipmapLegacyMode && AutomaticMipmapUpdate)
385 {
386 glEnable(GL_TEXTURE_2D);
387 Driver->extGlGenerateMipmap(GL_TEXTURE_2D);
388 }
389
390 if (Driver->testGLError())
391 os::Printer::log("Could not glTexImage2D", ELL_ERROR);
392}
393
394
395//! lock function
396void* COpenGLTexture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel)
397{
398 // store info about which image is locked
399 IImage* image = (mipmapLevel==0)?Image:MipImage;
400 ReadOnlyLock |= (mode==ETLM_READ_ONLY);
401 MipLevelStored = mipmapLevel;
402 if (!ReadOnlyLock && mipmapLevel)
403 {
404#ifdef GL_SGIS_generate_mipmap
405 if (Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE))
406 {
407 // do not automatically generate and update mipmaps
408 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
409 }
410#endif
411 AutomaticMipmapUpdate=false;
412 }
413
414 // if data not available or might have changed on GPU download it
415 if (!image || IsRenderTarget)
416 {
417 // prepare the data storage if necessary
418 if (!image)
419 {
420 if (mipmapLevel)
421 {
422 u32 i=0;
423 u32 width = TextureSize.Width;
424 u32 height = TextureSize.Height;
425 do
426 {
427 if (width>1)
428 width>>=1;
429 if (height>1)
430 height>>=1;
431 ++i;
432 }
433 while (i != mipmapLevel);
434 MipImage = image = Driver->createImage(ECF_A8R8G8B8, core::dimension2du(width,height));
435 }
436 else
437 Image = image = Driver->createImage(ECF_A8R8G8B8, ImageSize);
438 ColorFormat = ECF_A8R8G8B8;
439 }
440 if (!image)
441 return 0;
442
443 if (mode != ETLM_WRITE_ONLY)
444 {
445 u8* pixels = static_cast<u8*>(image->lock());
446 if (!pixels)
447 return 0;
448
449 // we need to keep the correct texture bound later on
450 GLint tmpTexture;
451 glGetIntegerv(GL_TEXTURE_BINDING_2D, &tmpTexture);
452 glBindTexture(GL_TEXTURE_2D, TextureName);
453
454 // we need to flip textures vertical
455 // however, it seems that this does not hold for mipmap
456 // textures, for unknown reasons.
457
458 // allows to read pixels in top-to-bottom order
459#ifdef GL_MESA_pack_invert
460 if (!mipmapLevel && Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_MESA_pack_invert))
461 glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
462#endif
463
464 // download GPU data as ARGB8 to pixels;
465 glGetTexImage(GL_TEXTURE_2D, mipmapLevel, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
466
467 if (!mipmapLevel)
468 {
469#ifdef GL_MESA_pack_invert
470 if (Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_MESA_pack_invert))
471 glPixelStorei(GL_PACK_INVERT_MESA, GL_FALSE);
472 else
473#endif
474 {
475 // opengl images are horizontally flipped, so we have to fix that here.
476 const s32 pitch=image->getPitch();
477 u8* p2 = pixels + (image->getDimension().Height - 1) * pitch;
478 u8* tmpBuffer = new u8[pitch];
479 for (u32 i=0; i < image->getDimension().Height; i += 2)
480 {
481 memcpy(tmpBuffer, pixels, pitch);
482 memcpy(pixels, p2, pitch);
483 memcpy(p2, tmpBuffer, pitch);
484 pixels += pitch;
485 p2 -= pitch;
486 }
487 delete [] tmpBuffer;
488 }
489 }
490 image->unlock();
491
492 //reset old bound texture
493 glBindTexture(GL_TEXTURE_2D, tmpTexture);
494 }
495 }
496 return image->lock();
497}
498
499
500//! unlock function
501void COpenGLTexture::unlock()
502{
503 // test if miplevel or main texture was locked
504 IImage* image = MipImage?MipImage:Image;
505 if (!image)
506 return;
507 // unlock image to see changes
508 image->unlock();
509 // copy texture data to GPU
510 if (!ReadOnlyLock)
511 uploadTexture(false, 0, MipLevelStored);
512 ReadOnlyLock = false;
513 // cleanup local image
514 if (MipImage)
515 {
516 MipImage->drop();
517 MipImage=0;
518 }
519 else if (!KeepImage)
520 {
521 Image->drop();
522 Image=0;
523 }
524 // update information
525 if (Image)
526 ColorFormat=Image->getColorFormat();
527 else
528 ColorFormat=ECF_A8R8G8B8;
529}
530
531
532//! Returns size of the original image.
533const core::dimension2d<u32>& COpenGLTexture::getOriginalSize() const
534{
535 return ImageSize;
536}
537
538
539//! Returns size of the texture.
540const core::dimension2d<u32>& COpenGLTexture::getSize() const
541{
542 return TextureSize;
543}
544
545
546//! returns driver type of texture, i.e. the driver, which created the texture
547E_DRIVER_TYPE COpenGLTexture::getDriverType() const
548{
549 return EDT_OPENGL;
550}
551
552
553//! returns color format of texture
554ECOLOR_FORMAT COpenGLTexture::getColorFormat() const
555{
556 return ColorFormat;
557}
558
559
560//! returns pitch of texture (in bytes)
561u32 COpenGLTexture::getPitch() const
562{
563 if (Image)
564 return Image->getPitch();
565 else
566 return 0;
567}
568
569
570//! return open gl texture name
571GLuint COpenGLTexture::getOpenGLTextureName() const
572{
573 return TextureName;
574}
575
576
577//! Returns whether this texture has mipmaps
578bool COpenGLTexture::hasMipMaps() const
579{
580 return HasMipMaps;
581}
582
583
584//! Regenerates the mip map levels of the texture. Useful after locking and
585//! modifying the texture
586void COpenGLTexture::regenerateMipMapLevels(void* mipmapData)
587{
588 if (AutomaticMipmapUpdate || !HasMipMaps || !Image)
589 return;
590 if ((Image->getDimension().Width==1) && (Image->getDimension().Height==1))
591 return;
592
593 // Manually create mipmaps or use prepared version
594 u32 width=Image->getDimension().Width;
595 u32 height=Image->getDimension().Height;
596 u32 i=0;
597 u8* target = static_cast<u8*>(mipmapData);
598 do
599 {
600 if (width>1)
601 width>>=1;
602 if (height>1)
603 height>>=1;
604 ++i;
605 if (!target)
606 target = new u8[width*height*Image->getBytesPerPixel()];
607 // create scaled version if no mipdata available
608 if (!mipmapData)
609 Image->copyToScaling(target, width, height, Image->getColorFormat());
610 glTexImage2D(GL_TEXTURE_2D, i, InternalFormat, width, height,
611 0, PixelFormat, PixelType, target);
612 // get next prepared mipmap data if available
613 if (mipmapData)
614 {
615 mipmapData = static_cast<u8*>(mipmapData)+width*height*Image->getBytesPerPixel();
616 target = static_cast<u8*>(mipmapData);
617 }
618 }
619 while (width!=1 || height!=1);
620 // cleanup
621 if (!mipmapData)
622 delete [] target;
623}
624
625
626bool COpenGLTexture::isRenderTarget() const
627{
628 return IsRenderTarget;
629}
630
631
632void COpenGLTexture::setIsRenderTarget(bool isTarget)
633{
634 IsRenderTarget = isTarget;
635}
636
637
638bool COpenGLTexture::isFrameBufferObject() const
639{
640 return false;
641}
642
643
644//! Bind Render Target Texture
645void COpenGLTexture::bindRTT()
646{
647}
648
649
650//! Unbind Render Target Texture
651void COpenGLTexture::unbindRTT()
652{
653 Driver->setActiveTexture(0, this);
654
655 // Copy Our ViewPort To The Texture
656 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, getSize().Width, getSize().Height);
657}
658
659
660/* FBO Textures */
661
662// helper function for render to texture
663static bool checkFBOStatus(COpenGLDriver* Driver);
664
665//! RTT ColorFrameBuffer constructor
666COpenGLFBOTexture::COpenGLFBOTexture(const core::dimension2d<u32>& size,
667 const io::path& name, COpenGLDriver* driver,
668 ECOLOR_FORMAT format)
669 : COpenGLTexture(name, driver), DepthTexture(0), ColorFrameBuffer(0)
670{
671 #ifdef _DEBUG
672 setDebugName("COpenGLTexture_FBO");
673 #endif
674
675 ImageSize = size;
676 TextureSize = size;
677
678 if (ECF_UNKNOWN == format)
679 format = getBestColorFormat(driver->getColorFormat());
680
681 ColorFormat = format;
682
683 GLint FilteringType;
684 InternalFormat = getOpenGLFormatAndParametersFromColorFormat(format, FilteringType, PixelFormat, PixelType);
685
686 HasMipMaps = false;
687 IsRenderTarget = true;
688
689#ifdef GL_EXT_framebuffer_object
690 // generate frame buffer
691 Driver->extGlGenFramebuffers(1, &ColorFrameBuffer);
692 bindRTT();
693
694 // generate color texture
695 glGenTextures(1, &TextureName);
696 Driver->setActiveTexture(0, this);
697 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, FilteringType);
698 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
699 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
700 glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, ImageSize.Width,
701 ImageSize.Height, 0, PixelFormat, PixelType, 0);
702#ifdef _DEBUG
703 driver->testGLError();
704#endif
705
706 // attach color texture to frame buffer
707 Driver->extGlFramebufferTexture2D(GL_FRAMEBUFFER_EXT,
708 GL_COLOR_ATTACHMENT0_EXT,
709 GL_TEXTURE_2D,
710 TextureName,
711 0);
712#ifdef _DEBUG
713 checkFBOStatus(Driver);
714#endif
715
716#endif
717 unbindRTT();
718}
719
720
721//! destructor
722COpenGLFBOTexture::~COpenGLFBOTexture()
723{
724 if (DepthTexture)
725 if (DepthTexture->drop())
726 Driver->removeDepthTexture(DepthTexture);
727 if (ColorFrameBuffer)
728 Driver->extGlDeleteFramebuffers(1, &ColorFrameBuffer);
729}
730
731
732bool COpenGLFBOTexture::isFrameBufferObject() const
733{
734 return true;
735}
736
737
738//! Bind Render Target Texture
739void COpenGLFBOTexture::bindRTT()
740{
741#ifdef GL_EXT_framebuffer_object
742 if (ColorFrameBuffer != 0)
743 Driver->extGlBindFramebuffer(GL_FRAMEBUFFER_EXT, ColorFrameBuffer);
744 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
745#endif
746}
747
748
749//! Unbind Render Target Texture
750void COpenGLFBOTexture::unbindRTT()
751{
752#ifdef GL_EXT_framebuffer_object
753 if (ColorFrameBuffer != 0)
754 Driver->extGlBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
755#endif
756}
757
758
759/* FBO Depth Textures */
760
761//! RTT DepthBuffer constructor
762COpenGLFBODepthTexture::COpenGLFBODepthTexture(
763 const core::dimension2d<u32>& size,
764 const io::path& name,
765 COpenGLDriver* driver,
766 bool useStencil)
767 : COpenGLTexture(name, driver), DepthRenderBuffer(0),
768 StencilRenderBuffer(0), UseStencil(useStencil)
769{
770#ifdef _DEBUG
771 setDebugName("COpenGLTextureFBO_Depth");
772#endif
773
774 ImageSize = size;
775 TextureSize = size;
776 InternalFormat = GL_RGBA;
777 PixelFormat = GL_RGBA;
778 PixelType = GL_UNSIGNED_BYTE;
779 HasMipMaps = false;
780
781 if (useStencil)
782 {
783 glGenTextures(1, &DepthRenderBuffer);
784 glBindTexture(GL_TEXTURE_2D, DepthRenderBuffer);
785 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
786 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
787 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
788#ifdef GL_EXT_packed_depth_stencil
789 if (Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_EXT_packed_depth_stencil))
790 {
791 // generate packed depth stencil texture
792 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_STENCIL_EXT, ImageSize.Width,
793 ImageSize.Height, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 0);
794 StencilRenderBuffer = DepthRenderBuffer; // stencil is packed with depth
795 }
796 else // generate separate stencil and depth textures
797#endif
798 {
799 // generate depth texture
800 glTexImage2D(GL_TEXTURE_2D, 0, Driver->getZBufferBits(), ImageSize.Width,
801 ImageSize.Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
802
803 // generate stencil texture
804 glGenTextures(1, &StencilRenderBuffer);
805 glBindTexture(GL_TEXTURE_2D, StencilRenderBuffer);
806 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
807 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
808 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
809 glTexImage2D(GL_TEXTURE_2D, 0, GL_STENCIL_INDEX, ImageSize.Width,
810 ImageSize.Height, 0, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, 0);
811 }
812 }
813#ifdef GL_EXT_framebuffer_object
814 else
815 {
816 // generate depth buffer
817 Driver->extGlGenRenderbuffers(1, &DepthRenderBuffer);
818 Driver->extGlBindRenderbuffer(GL_RENDERBUFFER_EXT, DepthRenderBuffer);
819 Driver->extGlRenderbufferStorage(GL_RENDERBUFFER_EXT,
820 Driver->getZBufferBits(), ImageSize.Width,
821 ImageSize.Height);
822 }
823#endif
824}
825
826
827//! destructor
828COpenGLFBODepthTexture::~COpenGLFBODepthTexture()
829{
830 if (DepthRenderBuffer && UseStencil)
831 glDeleteTextures(1, &DepthRenderBuffer);
832 else
833 Driver->extGlDeleteRenderbuffers(1, &DepthRenderBuffer);
834 if (StencilRenderBuffer && StencilRenderBuffer != DepthRenderBuffer)
835 glDeleteTextures(1, &StencilRenderBuffer);
836}
837
838
839//combine depth texture and rtt
840bool COpenGLFBODepthTexture::attach(ITexture* renderTex)
841{
842 if (!renderTex)
843 return false;
844 video::COpenGLFBOTexture* rtt = static_cast<video::COpenGLFBOTexture*>(renderTex);
845 rtt->bindRTT();
846#ifdef GL_EXT_framebuffer_object
847 if (UseStencil)
848 {
849 // attach stencil texture to stencil buffer
850 Driver->extGlFramebufferTexture2D(GL_FRAMEBUFFER_EXT,
851 GL_STENCIL_ATTACHMENT_EXT,
852 GL_TEXTURE_2D,
853 StencilRenderBuffer,
854 0);
855
856 // attach depth texture to depth buffer
857 Driver->extGlFramebufferTexture2D(GL_FRAMEBUFFER_EXT,
858 GL_DEPTH_ATTACHMENT_EXT,
859 GL_TEXTURE_2D,
860 DepthRenderBuffer,
861 0);
862 }
863 else
864 {
865 // attach depth renderbuffer to depth buffer
866 Driver->extGlFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT,
867 GL_DEPTH_ATTACHMENT_EXT,
868 GL_RENDERBUFFER_EXT,
869 DepthRenderBuffer);
870 }
871#endif
872 // check the status
873 if (!checkFBOStatus(Driver))
874 {
875 os::Printer::log("FBO incomplete");
876 return false;
877 }
878 rtt->DepthTexture=this;
879 grab(); // grab the depth buffer, not the RTT
880 rtt->unbindRTT();
881 return true;
882}
883
884
885//! Bind Render Target Texture
886void COpenGLFBODepthTexture::bindRTT()
887{
888}
889
890
891//! Unbind Render Target Texture
892void COpenGLFBODepthTexture::unbindRTT()
893{
894}
895
896
897bool checkFBOStatus(COpenGLDriver* Driver)
898{
899#ifdef GL_EXT_framebuffer_object
900 GLenum status = Driver->extGlCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
901
902 switch (status)
903 {
904 //Our FBO is perfect, return true
905 case GL_FRAMEBUFFER_COMPLETE_EXT:
906 return true;
907
908 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
909 os::Printer::log("FBO has invalid read buffer", ELL_ERROR);
910 break;
911
912 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
913 os::Printer::log("FBO has invalid draw buffer", ELL_ERROR);
914 break;
915
916 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
917 os::Printer::log("FBO has one or several incomplete image attachments", ELL_ERROR);
918 break;
919
920 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
921 os::Printer::log("FBO has one or several image attachments with different internal formats", ELL_ERROR);
922 break;
923
924 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
925 os::Printer::log("FBO has one or several image attachments with different dimensions", ELL_ERROR);
926 break;
927
928// not part of fbo_object anymore, but won't harm as it is just a return value
929#ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
930 case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
931 os::Printer::log("FBO has a duplicate image attachment", ELL_ERROR);
932 break;
933#endif
934
935 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
936 os::Printer::log("FBO missing an image attachment", ELL_ERROR);
937 break;
938
939#ifdef GL_EXT_framebuffer_multisample
940 case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
941 os::Printer::log("FBO wrong multisample setup", ELL_ERROR);
942 break;
943#endif
944
945 case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
946 os::Printer::log("FBO format unsupported", ELL_ERROR);
947 break;
948
949 default:
950 break;
951 }
952#endif
953 os::Printer::log("FBO error", ELL_ERROR);
954// _IRR_DEBUG_BREAK_IF(true);
955 return false;
956}
957
958
959} // end namespace video
960} // end namespace irr
961
962#endif // _IRR_COMPILE_WITH_OPENGL_
963