123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998 |
- // Copyright (C) 2002-2012 Nikolaus Gebhardt
- // This file is part of the "Irrlicht Engine".
- // For conditions of distribution and use, see copyright notice in irrlicht.h
- #include "IrrCompileConfig.h"
- #ifdef _IRR_COMPILE_WITH_OPENGL_
- #include "irrTypes.h"
- #include "COpenGLTexture.h"
- #include "COpenGLDriver.h"
- #include "os.h"
- #include "CColorConverter.h"
- #include "IAttributes.h"
- #include "IrrlichtDevice.h"
- #include "irrString.h"
- namespace irr
- {
- namespace video
- {
- extern bool useCoreContext;
- //! constructor for usual textures
- COpenGLTexture::COpenGLTexture(IImage* origImage, const io::path& name, void* mipmapData, COpenGLDriver* driver)
- : ITexture(name), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0), MipImage(0),
- TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT),
- PixelType(GL_UNSIGNED_BYTE), MipLevelStored(0), MipmapLegacyMode(true),
- IsRenderTarget(false), AutomaticMipmapUpdate(false),
- ReadOnlyLock(false), KeepImage(true)
- {
- #ifdef _DEBUG
- setDebugName("COpenGLTexture");
- #endif
- HasMipMaps = Driver->getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);
- getImageValues(origImage);
- glGenTextures(1, &TextureName);
- if (ImageSize==TextureSize)
- {
- Image = Driver->createImage(ColorFormat, ImageSize);
- origImage->copyTo(Image);
- }
- else
- {
- Image = Driver->createImage(ColorFormat, TextureSize);
- // scale texture
- origImage->copyToScaling(Image);
- }
- uploadTexture(true, mipmapData);
- if (!KeepImage)
- {
- Image->drop();
- Image=0;
- }
- }
- //! constructor for basic setup (only for derived classes)
- COpenGLTexture::COpenGLTexture(const io::path& name, COpenGLDriver* driver)
- : ITexture(name), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0), MipImage(0),
- TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT),
- PixelType(GL_UNSIGNED_BYTE), MipLevelStored(0), HasMipMaps(true),
- MipmapLegacyMode(true), IsRenderTarget(false), AutomaticMipmapUpdate(false),
- ReadOnlyLock(false), KeepImage(true)
- {
- #ifdef _DEBUG
- setDebugName("COpenGLTexture");
- #endif
- }
- //! destructor
- COpenGLTexture::~COpenGLTexture()
- {
- if (TextureName)
- glDeleteTextures(1, &TextureName);
- if (Image)
- Image->drop();
- }
- //! Choose best matching color format, based on texture creation flags
- ECOLOR_FORMAT COpenGLTexture::getBestColorFormat(ECOLOR_FORMAT format)
- {
- ECOLOR_FORMAT destFormat = ECF_A8R8G8B8;
- switch (format)
- {
- case ECF_A1R5G5B5:
- if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT))
- destFormat = ECF_A1R5G5B5;
- break;
- case ECF_R5G6B5:
- if (!Driver->getTextureCreationFlag(ETCF_ALWAYS_32_BIT))
- destFormat = ECF_A1R5G5B5;
- break;
- case ECF_A8R8G8B8:
- if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) ||
- Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))
- destFormat = ECF_A1R5G5B5;
- break;
- case ECF_R8G8B8:
- if (Driver->getTextureCreationFlag(ETCF_ALWAYS_16_BIT) ||
- Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))
- destFormat = ECF_A1R5G5B5;
- default:
- break;
- }
- if (Driver->getTextureCreationFlag(ETCF_NO_ALPHA_CHANNEL))
- {
- switch (destFormat)
- {
- case ECF_A1R5G5B5:
- destFormat = ECF_R5G6B5;
- break;
- case ECF_A8R8G8B8:
- destFormat = ECF_R8G8B8;
- break;
- default:
- break;
- }
- }
- return destFormat;
- }
- //! Get opengl values for the GPU texture storage
- GLint COpenGLTexture::getOpenGLFormatAndParametersFromColorFormat(ECOLOR_FORMAT format,
- GLint& filtering,
- GLenum& colorformat,
- GLenum& type)
- {
- // default
- filtering = GL_LINEAR;
- colorformat = GL_RGBA;
- type = GL_UNSIGNED_BYTE;
- GLenum internalformat = GL_RGBA;
- switch(format)
- {
- case ECF_A1R5G5B5:
- colorformat=GL_BGRA_EXT;
- type=GL_UNSIGNED_SHORT_1_5_5_5_REV;
- internalformat = GL_RGBA;
- break;
- case ECF_R5G6B5:
- colorformat=GL_RGB;
- type=GL_UNSIGNED_SHORT_5_6_5;
- internalformat = GL_RGB;
- break;
- case ECF_R8G8B8:
- colorformat=GL_BGR;
- type=GL_UNSIGNED_BYTE;
- internalformat = GL_RGB;
- break;
- case ECF_A8R8G8B8:
- colorformat=GL_BGRA_EXT;
- if (Driver->Version > 101)
- type=GL_UNSIGNED_INT_8_8_8_8_REV;
- internalformat = GL_RGBA;
- break;
- // _rg formats.
- case ECF_R8:
- colorformat = GL_RED;
- type = GL_UNSIGNED_BYTE;
- internalformat = GL_R8;
- break;
- case ECF_R16:
- colorformat = GL_RED;
- type = GL_UNSIGNED_SHORT;
- internalformat = GL_R16;
- break;
- case ECF_R8G8:
- colorformat = GL_RG;
- type = GL_UNSIGNED_BYTE;
- internalformat = GL_RG8;
- break;
- case ECF_R16G16:
- colorformat = GL_RG;
- type = GL_UNSIGNED_SHORT;
- internalformat = GL_RG16;
- break;
- // Floating Point texture formats. Thanks to Patryk "Nadro" Nadrowski.
- case ECF_R16F:
- {
- #ifdef GL_ARB_texture_rg
- filtering = GL_NEAREST;
- colorformat = GL_RED;
- type = GL_FLOAT;
- internalformat = GL_R16F;
- #else
- ColorFormat = ECF_A8R8G8B8;
- internalformat = GL_RGB8;
- #endif
- }
- break;
- case ECF_G16R16F:
- {
- #ifdef GL_ARB_texture_rg
- filtering = GL_NEAREST;
- colorformat = GL_RG;
- type = GL_FLOAT;
- internalformat = GL_RG16F;
- #else
- ColorFormat = ECF_A8R8G8B8;
- internalformat = GL_RGB8;
- #endif
- }
- break;
- case ECF_A16B16G16R16F:
- {
- #ifdef GL_ARB_texture_rg
- filtering = GL_NEAREST;
- colorformat = GL_RGBA;
- type = GL_FLOAT;
- internalformat = GL_RGBA16F_ARB;
- #else
- ColorFormat = ECF_A8R8G8B8;
- internalformat = GL_RGBA8;
- #endif
- }
- break;
- case ECF_R32F:
- {
- #ifdef GL_ARB_texture_rg
- filtering = GL_NEAREST;
- colorformat = GL_RED;
- type = GL_FLOAT;
- internalformat = GL_R32F;
- #else
- ColorFormat = ECF_A8R8G8B8;
- internalformat = GL_RGB8;
- #endif
- }
- break;
- case ECF_G32R32F:
- {
- #ifdef GL_ARB_texture_rg
- filtering = GL_NEAREST;
- colorformat = GL_RG;
- type = GL_FLOAT;
- internalformat = GL_RG32F;
- #else
- ColorFormat = ECF_A8R8G8B8;
- internalformat = GL_RGB8;
- #endif
- }
- break;
- case ECF_A32B32G32R32F:
- {
- #ifdef GL_ARB_texture_float
- filtering = GL_NEAREST;
- colorformat = GL_RGBA;
- type = GL_FLOAT;
- internalformat = GL_RGBA32F_ARB;
- #else
- ColorFormat = ECF_A8R8G8B8;
- internalformat = GL_RGBA8;
- #endif
- }
- break;
- default:
- {
- os::Printer::log("Unsupported texture format", ELL_ERROR);
- internalformat = GL_RGBA8;
- }
- }
- //#if defined(GL_ARB_framebuffer_sRGB) || defined(GL_EXT_framebuffer_sRGB)
- // if (Driver->Params.HandleSRGB)
- // {
- // if (internalformat==GL_RGBA)
- // internalformat=GL_SRGB_ALPHA_EXT;
- // else if (internalformat==GL_RGB)
- // internalformat=GL_SRGB_EXT;
- // }
- //#endif
- return internalformat;
- }
- // prepare values ImageSize, TextureSize, and ColorFormat based on image
- void COpenGLTexture::getImageValues(IImage* image)
- {
- if (!image)
- {
- os::Printer::log("No image for OpenGL texture.", ELL_ERROR);
- return;
- }
- ImageSize = image->getDimension();
- if ( !ImageSize.Width || !ImageSize.Height)
- {
- os::Printer::log("Invalid size of image for OpenGL Texture.", ELL_ERROR);
- return;
- }
- const f32 ratio = (f32)ImageSize.Width/(f32)ImageSize.Height;
- if ((ImageSize.Width>Driver->MaxTextureSize) && (ratio >= 1.0f))
- {
- ImageSize.Width = Driver->MaxTextureSize;
- ImageSize.Height = (u32)(Driver->MaxTextureSize/ratio);
- }
- else if (ImageSize.Height>Driver->MaxTextureSize)
- {
- ImageSize.Height = Driver->MaxTextureSize;
- ImageSize.Width = (u32)(Driver->MaxTextureSize*ratio);
- }
- TextureSize=ImageSize.getOptimalSize(!Driver->queryFeature(EVDF_TEXTURE_NPOT));
- const core::dimension2du max_size = Driver->getDriverAttributes()
- .getAttributeAsDimension2d("MAX_TEXTURE_SIZE");
- if (max_size.Width> 0 && TextureSize.Width > max_size.Width)
- {
- TextureSize.Width = max_size.Width;
- }
- if (max_size.Height> 0 && TextureSize.Height > max_size.Height)
- {
- TextureSize.Height = max_size.Height;
- }
- ColorFormat = getBestColorFormat(image->getColorFormat());
- }
- //! copies the the texture into an open gl texture.
- void COpenGLTexture::uploadTexture(bool newTexture, void* mipmapData, u32 level)
- {
- // check which image needs to be uploaded
- IImage* image = level?MipImage:Image;
- if (!image)
- {
- os::Printer::log("No image for OpenGL texture to upload", ELL_ERROR);
- return;
- }
- // get correct opengl color data values
- GLenum oldInternalFormat = InternalFormat;
- GLint filtering;
- InternalFormat = getOpenGLFormatAndParametersFromColorFormat(ColorFormat, filtering, PixelFormat, PixelType);
- // make sure we don't change the internal format of existing images
- if (!newTexture)
- InternalFormat=oldInternalFormat;
- Driver->setActiveTexture(0, this);
- if (Driver->testGLError())
- os::Printer::log("Could not bind Texture", ELL_ERROR);
- // mipmap handling for main texture
- if (!level && newTexture)
- {
- #ifndef DISABLE_MIPMAPPING
- #ifdef GL_SGIS_generate_mipmap
- // auto generate if possible and no mipmap data is given
- if (HasMipMaps && !mipmapData && Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE))
- {
- if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED) && !useCoreContext)
- glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST);
- else if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY) && !useCoreContext)
- glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST);
- else if (!useCoreContext)
- glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_DONT_CARE);
- AutomaticMipmapUpdate=true;
- if (!Driver->queryFeature(EVDF_FRAMEBUFFER_OBJECT))
- {
- glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
- MipmapLegacyMode=true;
- }
- else
- MipmapLegacyMode=false;
- }
- else
- #endif
- {
- // Either generate manually due to missing capability
- // or use predefined mipmap data
- AutomaticMipmapUpdate=false;
- regenerateMipMapLevels(mipmapData);
- }
- if (HasMipMaps) // might have changed in regenerateMipMapLevels
- {
- // enable bilinear mipmap filter
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- }
- else
- #else
- HasMipMaps=false;
- os::Printer::log("Did not create OpenGL texture mip maps.", ELL_INFORMATION);
- #endif
- {
- // enable bilinear filter without mipmaps
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- }
- }
- // now get image data and upload to GPU
- void* source = image->lock();
- if (newTexture)
- glTexImage2D(GL_TEXTURE_2D, level, InternalFormat, image->getDimension().Width,
- image->getDimension().Height, 0, PixelFormat, PixelType, source);
- else
- glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, image->getDimension().Width,
- image->getDimension().Height, PixelFormat, PixelType, source);
- image->unlock();
- if (!MipmapLegacyMode && AutomaticMipmapUpdate)
- {
- if (!useCoreContext)
- glEnable(GL_TEXTURE_2D);
- Driver->extGlGenerateMipmap(GL_TEXTURE_2D);
- }
- if (Driver->testGLError())
- os::Printer::log("Could not glTexImage2D", ELL_ERROR);
- }
- //! lock function
- void* COpenGLTexture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel)
- {
- // store info about which image is locked
- IImage* image = (mipmapLevel==0)?Image:MipImage;
- ReadOnlyLock |= (mode==ETLM_READ_ONLY);
- MipLevelStored = mipmapLevel;
- if (!ReadOnlyLock && mipmapLevel)
- {
- #ifdef GL_SGIS_generate_mipmap
- if (Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE))
- {
- // do not automatically generate and update mipmaps
- glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
- }
- #endif
- AutomaticMipmapUpdate=false;
- }
- // if data not available or might have changed on GPU download it
- if (!image || IsRenderTarget)
- {
- // prepare the data storage if necessary
- if (!image)
- {
- if (mipmapLevel)
- {
- u32 i=0;
- u32 width = TextureSize.Width;
- u32 height = TextureSize.Height;
- do
- {
- if (width>1)
- width>>=1;
- if (height>1)
- height>>=1;
- ++i;
- }
- while (i != mipmapLevel);
- MipImage = image = Driver->createImage(ECF_A8R8G8B8, core::dimension2du(width,height));
- }
- else
- Image = image = Driver->createImage(ECF_A8R8G8B8, ImageSize);
- ColorFormat = ECF_A8R8G8B8;
- }
- if (!image)
- return 0;
- if (mode != ETLM_WRITE_ONLY)
- {
- u8* pixels = static_cast<u8*>(image->lock());
- if (!pixels)
- return 0;
- // we need to keep the correct texture bound later on
- GLint tmpTexture;
- glGetIntegerv(GL_TEXTURE_BINDING_2D, &tmpTexture);
- glBindTexture(GL_TEXTURE_2D, TextureName);
- // we need to flip textures vertical
- // however, it seems that this does not hold for mipmap
- // textures, for unknown reasons.
- // allows to read pixels in top-to-bottom order
- #ifdef GL_MESA_pack_invert
- if (!mipmapLevel && Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_MESA_pack_invert))
- glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
- #endif
- // download GPU data as ARGB8 to pixels;
- glGetTexImage(GL_TEXTURE_2D, mipmapLevel, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
- if (!mipmapLevel)
- {
- #ifdef GL_MESA_pack_invert
- if (Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_MESA_pack_invert))
- glPixelStorei(GL_PACK_INVERT_MESA, GL_FALSE);
- else
- #endif
- {
- // opengl images are horizontally flipped, so we have to fix that here.
- const s32 pitch=image->getPitch();
- u8* p2 = pixels + (image->getDimension().Height - 1) * pitch;
- u8* tmpBuffer = new u8[pitch];
- for (u32 i=0; i < image->getDimension().Height; i += 2)
- {
- memcpy(tmpBuffer, pixels, pitch);
- memcpy(pixels, p2, pitch);
- memcpy(p2, tmpBuffer, pitch);
- pixels += pitch;
- p2 -= pitch;
- }
- delete [] tmpBuffer;
- }
- }
- image->unlock();
- //reset old bound texture
- glBindTexture(GL_TEXTURE_2D, tmpTexture);
- }
- }
- return image->lock();
- }
- //! unlock function
- void COpenGLTexture::unlock()
- {
- // test if miplevel or main texture was locked
- IImage* image = MipImage?MipImage:Image;
- if (!image)
- return;
- // unlock image to see changes
- image->unlock();
- // copy texture data to GPU
- if (!ReadOnlyLock)
- uploadTexture(false, 0, MipLevelStored);
- ReadOnlyLock = false;
- // cleanup local image
- if (MipImage)
- {
- MipImage->drop();
- MipImage=0;
- }
- else if (!KeepImage)
- {
- Image->drop();
- Image=0;
- }
- // update information
- if (Image)
- ColorFormat=Image->getColorFormat();
- else
- ColorFormat=ECF_A8R8G8B8;
- }
- //! Returns size of the original image.
- const core::dimension2d<u32>& COpenGLTexture::getOriginalSize() const
- {
- return ImageSize;
- }
- //! Returns size of the texture.
- const core::dimension2d<u32>& COpenGLTexture::getSize() const
- {
- return TextureSize;
- }
- //! returns driver type of texture, i.e. the driver, which created the texture
- E_DRIVER_TYPE COpenGLTexture::getDriverType() const
- {
- return EDT_OPENGL;
- }
- //! returns color format of texture
- ECOLOR_FORMAT COpenGLTexture::getColorFormat() const
- {
- return ColorFormat;
- }
- //! returns pitch of texture (in bytes)
- u32 COpenGLTexture::getPitch() const
- {
- if (Image)
- return Image->getPitch();
- else
- return 0;
- }
- //! return open gl texture name
- GLuint COpenGLTexture::getOpenGLTextureName() const
- {
- return TextureName;
- }
- //! Returns whether this texture has mipmaps
- bool COpenGLTexture::hasMipMaps() const
- {
- return HasMipMaps;
- }
- //! Regenerates the mip map levels of the texture. Useful after locking and
- //! modifying the texture
- void COpenGLTexture::regenerateMipMapLevels(void* mipmapData)
- {
- if (AutomaticMipmapUpdate || !HasMipMaps || !Image)
- return;
- if ((Image->getDimension().Width==1) && (Image->getDimension().Height==1))
- return;
- // Manually create mipmaps or use prepared version
- u32 width=Image->getDimension().Width;
- u32 height=Image->getDimension().Height;
- u32 i=0;
- u8* target = static_cast<u8*>(mipmapData);
- do
- {
- if (width>1)
- width>>=1;
- if (height>1)
- height>>=1;
- ++i;
- if (!target)
- target = new u8[width*height*Image->getBytesPerPixel()];
- // create scaled version if no mipdata available
- if (!mipmapData)
- Image->copyToScaling(target, width, height, Image->getColorFormat());
- glTexImage2D(GL_TEXTURE_2D, i, InternalFormat, width, height,
- 0, PixelFormat, PixelType, target);
- // get next prepared mipmap data if available
- if (mipmapData)
- {
- mipmapData = static_cast<u8*>(mipmapData)+width*height*Image->getBytesPerPixel();
- target = static_cast<u8*>(mipmapData);
- }
- }
- while (width!=1 || height!=1);
- // cleanup
- if (!mipmapData)
- delete [] target;
- }
- bool COpenGLTexture::isRenderTarget() const
- {
- return IsRenderTarget;
- }
- void COpenGLTexture::setIsRenderTarget(bool isTarget)
- {
- IsRenderTarget = isTarget;
- }
- bool COpenGLTexture::isFrameBufferObject() const
- {
- return false;
- }
- //! Bind Render Target Texture
- void COpenGLTexture::bindRTT()
- {
- }
- //! Unbind Render Target Texture
- void COpenGLTexture::unbindRTT()
- {
- Driver->setActiveTexture(0, this);
- // Copy Our ViewPort To The Texture
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, getSize().Width, getSize().Height);
- }
- /* FBO Textures */
- // helper function for render to texture
- static bool checkFBOStatus(COpenGLDriver* Driver);
- //! RTT ColorFrameBuffer constructor
- COpenGLFBOTexture::COpenGLFBOTexture(const core::dimension2d<u32>& size,
- const io::path& name, COpenGLDriver* driver,
- ECOLOR_FORMAT format)
- : COpenGLTexture(name, driver), DepthTexture(0), ColorFrameBuffer(0)
- {
- #ifdef _DEBUG
- setDebugName("COpenGLTexture_FBO");
- #endif
- ImageSize = size;
- TextureSize = size;
- if (ECF_UNKNOWN == format)
- format = getBestColorFormat(driver->getColorFormat());
- ColorFormat = format;
- GLint FilteringType;
- InternalFormat = getOpenGLFormatAndParametersFromColorFormat(format, FilteringType, PixelFormat, PixelType);
- HasMipMaps = false;
- IsRenderTarget = true;
- #ifdef GL_EXT_framebuffer_object
- // generate frame buffer
- Driver->extGlGenFramebuffers(1, &ColorFrameBuffer);
- bindRTT();
- // generate color texture
- glGenTextures(1, &TextureName);
- Driver->setActiveTexture(0, this);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, FilteringType);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, ImageSize.Width,
- ImageSize.Height, 0, PixelFormat, PixelType, 0);
- #ifdef _DEBUG
- driver->testGLError();
- #endif
- // attach color texture to frame buffer
- Driver->extGlFramebufferTexture2D(GL_FRAMEBUFFER_EXT,
- GL_COLOR_ATTACHMENT0_EXT,
- GL_TEXTURE_2D,
- TextureName,
- 0);
- #ifdef _DEBUG
- checkFBOStatus(Driver);
- #endif
- #endif
- unbindRTT();
- }
- //! destructor
- COpenGLFBOTexture::~COpenGLFBOTexture()
- {
- if (DepthTexture)
- if (DepthTexture->drop())
- Driver->removeDepthTexture(DepthTexture);
- if (ColorFrameBuffer)
- Driver->extGlDeleteFramebuffers(1, &ColorFrameBuffer);
- }
- bool COpenGLFBOTexture::isFrameBufferObject() const
- {
- return true;
- }
- //! Bind Render Target Texture
- void COpenGLFBOTexture::bindRTT()
- {
- #ifdef GL_EXT_framebuffer_object
- if (ColorFrameBuffer != 0)
- Driver->extGlBindFramebuffer(GL_FRAMEBUFFER_EXT, ColorFrameBuffer);
- glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
- #endif
- }
- //! Unbind Render Target Texture
- void COpenGLFBOTexture::unbindRTT()
- {
- #ifdef GL_EXT_framebuffer_object
- if (ColorFrameBuffer != 0)
- Driver->extGlBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
- #endif
- }
- /* FBO Depth Textures */
- //! RTT DepthBuffer constructor
- COpenGLFBODepthTexture::COpenGLFBODepthTexture(
- const core::dimension2d<u32>& size,
- const io::path& name,
- COpenGLDriver* driver,
- bool useStencil)
- : COpenGLTexture(name, driver), DepthRenderBuffer(0),
- StencilRenderBuffer(0), UseStencil(useStencil)
- {
- #ifdef _DEBUG
- setDebugName("COpenGLTextureFBO_Depth");
- #endif
- ImageSize = size;
- TextureSize = size;
- InternalFormat = GL_RGBA;
- PixelFormat = GL_RGBA;
- PixelType = GL_UNSIGNED_BYTE;
- HasMipMaps = false;
- if (useStencil)
- {
- glGenTextures(1, &DepthRenderBuffer);
- glBindTexture(GL_TEXTURE_2D, DepthRenderBuffer);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- #ifdef GL_EXT_packed_depth_stencil
- if (Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_EXT_packed_depth_stencil))
- {
- // generate packed depth stencil texture
- glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_STENCIL_EXT, ImageSize.Width,
- ImageSize.Height, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 0);
- StencilRenderBuffer = DepthRenderBuffer; // stencil is packed with depth
- }
- else // generate separate stencil and depth textures
- #endif
- {
- // generate depth texture
- glTexImage2D(GL_TEXTURE_2D, 0, Driver->getZBufferBits(), ImageSize.Width,
- ImageSize.Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
- // generate stencil texture
- glGenTextures(1, &StencilRenderBuffer);
- glBindTexture(GL_TEXTURE_2D, StencilRenderBuffer);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_STENCIL_INDEX, ImageSize.Width,
- ImageSize.Height, 0, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, 0);
- }
- }
- #ifdef GL_EXT_framebuffer_object
- else
- {
- // generate depth buffer
- Driver->extGlGenRenderbuffers(1, &DepthRenderBuffer);
- Driver->extGlBindRenderbuffer(GL_RENDERBUFFER_EXT, DepthRenderBuffer);
- Driver->extGlRenderbufferStorage(GL_RENDERBUFFER_EXT,
- Driver->getZBufferBits(), ImageSize.Width,
- ImageSize.Height);
- }
- #endif
- }
- //! destructor
- COpenGLFBODepthTexture::~COpenGLFBODepthTexture()
- {
- if (DepthRenderBuffer && UseStencil)
- glDeleteTextures(1, &DepthRenderBuffer);
- else
- Driver->extGlDeleteRenderbuffers(1, &DepthRenderBuffer);
- if (StencilRenderBuffer && StencilRenderBuffer != DepthRenderBuffer)
- glDeleteTextures(1, &StencilRenderBuffer);
- }
- //combine depth texture and rtt
- bool COpenGLFBODepthTexture::attach(ITexture* renderTex)
- {
- if (!renderTex)
- return false;
- video::COpenGLFBOTexture* rtt = static_cast<video::COpenGLFBOTexture*>(renderTex);
- rtt->bindRTT();
- #ifdef GL_EXT_framebuffer_object
- if (UseStencil)
- {
- // attach depth stencil texture to depth buffer
- Driver->extGlFramebufferTexture2D(GL_FRAMEBUFFER_EXT,
- GL_DEPTH_STENCIL_ATTACHMENT,
- GL_TEXTURE_2D,
- DepthRenderBuffer,
- 0);
- }
- else
- {
- // attach depth renderbuffer to depth buffer
- Driver->extGlFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT,
- GL_DEPTH_ATTACHMENT_EXT,
- GL_RENDERBUFFER_EXT,
- DepthRenderBuffer);
- }
- #endif
- // check the status
- if (!checkFBOStatus(Driver))
- {
- os::Printer::log("FBO incomplete");
- return false;
- }
- rtt->DepthTexture=this;
- rtt->DepthBufferTexture = DepthRenderBuffer;
- grab(); // grab the depth buffer, not the RTT
- rtt->unbindRTT();
- return true;
- }
- //! Bind Render Target Texture
- void COpenGLFBODepthTexture::bindRTT()
- {
- }
- //! Unbind Render Target Texture
- void COpenGLFBODepthTexture::unbindRTT()
- {
- }
- bool COpenGLFBODepthTexture::hasStencil()
- {
- return UseStencil;
- }
- bool checkFBOStatus(COpenGLDriver* Driver)
- {
- #ifdef GL_EXT_framebuffer_object
- GLenum status = Driver->extGlCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
- switch (status)
- {
- //Our FBO is perfect, return true
- case GL_FRAMEBUFFER_COMPLETE_EXT:
- return true;
- case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
- os::Printer::log("FBO has invalid read buffer", ELL_ERROR);
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
- os::Printer::log("FBO has invalid draw buffer", ELL_ERROR);
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
- os::Printer::log("FBO has one or several incomplete image attachments", ELL_ERROR);
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
- os::Printer::log("FBO has one or several image attachments with different internal formats", ELL_ERROR);
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
- os::Printer::log("FBO has one or several image attachments with different dimensions", ELL_ERROR);
- break;
- // not part of fbo_object anymore, but won't harm as it is just a return value
- #ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT
- case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
- os::Printer::log("FBO has a duplicate image attachment", ELL_ERROR);
- break;
- #endif
- case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
- os::Printer::log("FBO missing an image attachment", ELL_ERROR);
- break;
- #ifdef GL_EXT_framebuffer_multisample
- case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT:
- os::Printer::log("FBO wrong multisample setup", ELL_ERROR);
- break;
- #endif
- case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
- os::Printer::log("FBO format unsupported", ELL_ERROR);
- break;
- default:
- break;
- }
- #endif
- os::Printer::log("FBO error", ELL_ERROR);
- // _IRR_DEBUG_BREAK_IF(true);
- return false;
- }
- } // end namespace video
- } // end namespace irr
- #endif // _IRR_COMPILE_WITH_OPENGL_
|