Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreGLTexture.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://ogre.sourceforge.net/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 
00026 #include "OgreGLTexture.h"
00027 #include "OgreGLSupport.h"
00028 #include "OgreTextureManager.h"
00029 #include "OgreDataChunk.h"
00030 #include "OgreImage.h"
00031 #include "OgreLogManager.h"
00032 #include "OgreCamera.h"
00033 #include "OgreException.h"
00034 #include "OgreRoot.h"
00035 #include "OgreCodec.h"
00036 #include "OgreSDDataChunk.h"
00037 
00038 #if OGRE_PLATFORM == PLATFORM_WIN32
00039 #   include <windows.h>
00040 #   include <wingdi.h>
00041 #endif
00042 
00043 namespace Ogre {
00044 
00045     unsigned int mostSignificantBitSet(unsigned int value)
00046     {
00047         unsigned int result = 0;
00048         while (value != 0) {
00049             ++result;
00050             value >>= 1;
00051         }
00052         return result-1;
00053     }
00054 
00055     GLTexture::GLTexture(const String& name, GLSupport& support, TextureType texType) :
00056         mGLSupport(support)
00057     {
00058         mName = name;
00059         mTextureType = texType;
00060 
00061         mUsage = TU_DEFAULT;
00062         enable32Bit(false);
00063     }
00064 
00065     // XXX init rather than assign
00066     GLTexture::GLTexture(const String& name, GLSupport& support, TextureType texType, 
00067         uint width, uint height, uint num_mips, PixelFormat format, 
00068         TextureUsage usage) : mGLSupport(support)
00069     {
00070         mName = name;
00071         mTextureType = texType;
00072 
00073         mSrcWidth = width;
00074         mSrcHeight = height;
00075         // Same dest dimensions for GL
00076         mWidth = mSrcWidth;
00077         mHeight = mSrcHeight;
00078         mDepth = 1;
00079 
00080         mNumMipMaps = num_mips;
00081 
00082         mUsage = usage;
00083         mFormat = format;
00084 
00085         mSrcBpp = Image::PF2BPP(mFormat);
00086 
00087         enable32Bit(false);
00088     }
00089 
00090     GLTexture::~GLTexture()
00091     {
00092         unload();
00093     }
00094 
00095     GLenum GLTexture::getGLTextureType(void) const
00096     {
00097         switch(mTextureType)
00098         {
00099             case TEX_TYPE_1D:
00100                 return GL_TEXTURE_1D;
00101             case TEX_TYPE_2D:
00102                 return GL_TEXTURE_2D;
00103             case TEX_TYPE_3D:
00104                 return GL_TEXTURE_3D;
00105             case TEX_TYPE_CUBE_MAP:
00106                 return GL_TEXTURE_CUBE_MAP;
00107             default:
00108                 return 0;
00109         };
00110     }
00111 
00112     GLenum GLTexture::getGLTextureFormat(void) const
00113     {
00114         switch(mFormat)
00115         {
00116             case PF_L8:
00117                 return GL_LUMINANCE;
00118             case PF_R8G8B8:
00119                 return GL_RGB;
00120             case PF_B8G8R8:
00121                 return GL_BGR;
00122             case PF_B8G8R8A8:
00123                 return GL_BGRA;
00124             case PF_A8R8G8B8:
00125                 return GL_RGBA;
00126             case PF_DXT1:
00127                 return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
00128             case PF_DXT3:
00129                  return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
00130             case PF_DXT5:
00131                  return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
00132             default:
00133                 return 0;
00134         }
00135     }
00136 
00137     void GLTexture::blitToTexture( 
00138         const Image& src, 
00139         unsigned uStartX, unsigned uStartY )
00140     {
00141         if (this->getTextureType() != TEX_TYPE_2D)
00142           Except( Exception::UNIMPLEMENTED_FEATURE, "**** Blit to texture implemented only for 2D textures!!! ****", "GLTexture::blitToTexture" );
00143 
00144         mGLSupport.begin_context();
00145         glBindTexture( GL_TEXTURE_2D, mTextureID );
00146         glTexSubImage2D( 
00147             GL_TEXTURE_2D, 0, 
00148             uStartX, uStartY,
00149             src.getWidth(), src.getHeight(),
00150             getGLTextureFormat(),
00151             GL_UNSIGNED_BYTE, src.getData() );
00152         mGLSupport.end_context();
00153     }
00154 
00155     uchar* GLTexture::rescaleNPower2( const Image& src ) 
00156     {
00157         // Scale image to n^2 dimensions
00158         unsigned int newWidth = (1 << mostSignificantBitSet(mSrcWidth));
00159         if (newWidth != mSrcWidth)
00160             newWidth <<= 1;
00161 
00162         unsigned int newHeight = (1 << mostSignificantBitSet(mSrcHeight));
00163         if (newHeight != mSrcHeight)
00164             newHeight <<= 1;
00165 
00166         uchar *pTempData;
00167         if(newWidth != mSrcWidth || newHeight != mSrcHeight)
00168         {
00169           unsigned int newImageSize = newWidth * newHeight * 
00170             (mHasAlpha ? 4 : 3);
00171 
00172           pTempData = new uchar[ newImageSize ];
00173           mGLSupport.begin_context();
00174           if(gluScaleImage(getGLTextureFormat(), mSrcWidth, mSrcHeight,
00175                 GL_UNSIGNED_BYTE, src.getData(), newWidth, newHeight, 
00176                 GL_UNSIGNED_BYTE, pTempData) != 0)
00177           {
00178             Except(Exception::ERR_INTERNAL_ERROR, 
00179                 "Error while rescaling image!", "GLTexture::rescaleNPower2");
00180           }
00181           mGLSupport.end_context();
00182 
00183           Image::applyGamma( pTempData, mGamma, newImageSize, mSrcBpp );
00184 
00185           mSrcWidth = mWidth = newWidth; 
00186           mSrcHeight = mHeight = newHeight;
00187         }
00188         else
00189         {
00190           pTempData = new uchar[ src.getSize() ];
00191           memcpy( pTempData, src.getData(), src.getSize() );
00192           Image::applyGamma( pTempData, mGamma, src.getSize(), mSrcBpp );
00193         }
00194 
00195         return pTempData;
00196     }
00197 
00198     void GLTexture::loadImage( const Image& img )
00199     {
00200         std::vector<Image> images;
00201         
00202         images.push_back(img);
00203         loadImages(images);
00204         images.clear();
00205     }
00206 
00207     void GLTexture::loadImages( const std::vector<Image>& images )
00208     {
00209         bool useSoftwareMipmaps = true;
00210 
00211         if( mIsLoaded )
00212         {
00213             std::cout << "Unloading image" << std::endl;
00214             unload();
00215         }
00216 
00217         // Create the GL texture
00218         mGLSupport.begin_context();
00219         glGenTextures( 1, &mTextureID );
00220         glBindTexture( getGLTextureType(), mTextureID );
00221 
00222         if(mNumMipMaps && Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_AUTOMIPMAP))
00223         {
00224             glTexParameteri( getGLTextureType(), GL_GENERATE_MIPMAP, GL_TRUE );
00225             useSoftwareMipmaps = false;
00226         }
00227 
00228         for(size_t i = 0; i < images.size(); i++)
00229         {
00230             Image img = images[i];
00231 
00232             LogManager::getSingleton().logMessage( 
00233                 LML_NORMAL,
00234                 "GLTexture: Loading %s with %d mipmaps from Image.", 
00235                 mName.c_str(), mNumMipMaps );        
00236 
00237             mFormat = img.getFormat();
00238 
00239             mSrcBpp = Image::PF2BPP(mFormat);
00240             mHasAlpha = img.getHasAlpha();
00241 
00242             mSrcWidth = img.getWidth();
00243             mSrcHeight = img.getHeight();
00244             // Same dest dimensions for GL
00245             mWidth = mSrcWidth;
00246             mHeight = mSrcHeight;
00247 
00248             mDepth = img.getDepth();
00249 
00250             unsigned short imageMipmaps = img.getNumMipmaps();
00251             if(imageMipmaps)
00252                 mNumMipMaps = imageMipmaps;
00253 
00254             glTexParameteri(getGLTextureType(), GL_TEXTURE_MAX_LEVEL, mNumMipMaps);
00255 
00256             uchar *pTempData = rescaleNPower2(img);
00257 
00258             generateMipMaps( pTempData, useSoftwareMipmaps, img.hasFlag(IF_COMPRESSED), i );
00259             delete [] pTempData;
00260         }
00261         mGLSupport.end_context();
00262 
00263         // Update size (the final size, not including temp space)
00264         unsigned short bytesPerPixel = mFinalBpp >> 3;
00265         if( !mHasAlpha && mFinalBpp == 32 )
00266         {
00267             bytesPerPixel--;
00268         }
00269         mSize = mWidth * mHeight * bytesPerPixel;
00270 
00271         mIsLoaded = true;     
00272     }
00273     
00274     void GLTexture::createRenderTexture(void)
00275     {
00276         if (this->getTextureType() != TEX_TYPE_2D)
00277             Except( Exception::UNIMPLEMENTED_FEATURE, "**** Create render texture implemented only for 2D textures!!! ****", "GLTexture::createRenderTexture" );
00278 
00279         // Create the GL texture
00280         mGLSupport.begin_context();
00281         glGenTextures( 1, &mTextureID );
00282         glBindTexture( GL_TEXTURE_2D, mTextureID );
00283 
00284         glTexImage2D( GL_TEXTURE_2D, 0, getGLTextureFormat(),
00285             mWidth, mHeight, 0, getGLTextureFormat(), GL_UNSIGNED_BYTE, 0 );
00286 
00287         // This needs to be set otherwise the texture doesn't get rendered
00288         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mNumMipMaps );
00289         mGLSupport.end_context();
00290     }
00291 
00292     void GLTexture::load()
00293     {
00294         if( mUsage == TU_RENDERTARGET )
00295         {
00296             createRenderTexture();
00297             mIsLoaded = true;     
00298         }
00299         else
00300         {
00301             if(mTextureType == TEX_TYPE_1D || mTextureType == TEX_TYPE_2D || 
00302                 mTextureType == TEX_TYPE_3D)
00303             {
00304                 Image img;
00305                 img.load( mName );
00306 
00307                 if (getName().endsWith(".dds") && img.hasFlag(IF_CUBEMAP))
00308                 {
00309                     Image newImage;
00310                     std::vector<Image> images;
00311                     uint imageSize = img.getSize() / 6;
00312 
00313                     mTextureType = TEX_TYPE_CUBE_MAP;
00314 
00315                     uint offset = 0;
00316                     for(int i = 0; i < 6; i++)
00317                     {
00318                         DataChunk chunk(img.getData() + offset, imageSize);
00319                         newImage.loadRawData(chunk, img.getWidth(), 
00320                             img.getHeight(), img.getFormat());
00321                         offset += imageSize;
00322                         images.push_back(newImage);
00323                     }
00324 
00325                     loadImages( images );
00326                     images.clear();
00327                 }
00328                 else
00329                 {
00330                     // If this is a dds volumetric texture set the texture type flag accordingly.
00331                     if(getName().endsWith(".dds") && img.getDepth() > 1)
00332                         mTextureType = TEX_TYPE_3D;
00333 
00334                     loadImage( img );
00335                 }
00336             }
00337             else if (mTextureType == TEX_TYPE_CUBE_MAP)
00338             {
00339                 Image img;
00340                 String baseName, ext;
00341                 std::vector<Image> images;
00342                 static const String suffixes[6] = {"_rt", "_lf", "_up", "_dn", "_fr", "_bk"};
00343 
00344                 for(size_t i = 0; i < 6; i++)
00345                 {
00346                     size_t pos = mName.find_last_of(".");
00347                     baseName = mName.substr(0, pos);
00348                     ext = mName.substr(pos);
00349                     String fullName = baseName + suffixes[i] + ext;
00350 
00351                     img.load( fullName );
00352                     images.push_back(img);
00353                 }
00354 
00355                 loadImages( images );
00356                 images.clear();
00357             }
00358             else
00359                 Except( Exception::UNIMPLEMENTED_FEATURE, "**** Unknown texture type ****", "GLTexture::load" );
00360         }
00361     }
00362     
00363     void GLTexture::unload()
00364     {
00365         if( mIsLoaded )
00366         {
00367             glDeleteTextures( 1, &mTextureID );
00368             mIsLoaded = false;
00369         }
00370     }
00371 
00372     void GLTexture::generateMipMaps( uchar *data, bool useSoftware, 
00373         bool isCompressed, size_t faceNumber )
00374     {
00375         mGLSupport.begin_context();
00376         if(useSoftware && mNumMipMaps)
00377         {
00378             if(mTextureType == TEX_TYPE_1D)
00379             {
00380                 gluBuild1DMipmaps(
00381                     getGLTextureType(), mHasAlpha ? GL_RGBA8 : GL_RGB8, 
00382                     mSrcWidth, getGLTextureFormat(), GL_UNSIGNED_BYTE, data);
00383             }
00384             else if (mTextureType == TEX_TYPE_3D)
00385             {
00386                 /* Requires GLU 1.3 which is harder to come by
00387                    Most 3D textures don't need mipmaps?
00388                 gluBuild3DMipmaps(
00389                     getGLTextureType(), mHasAlpha ? GL_RGBA8 : GL_RGB8, 
00390                     mSrcWidth, mSrcHeight, mDepth, getGLTextureFormat(), 
00391                     GL_UNSIGNED_BYTE, data);
00392                 */
00393                 glTexImage3D(
00394                     getGLTextureType(), 0, mHasAlpha ? GL_RGBA8 : GL_RGB8, 
00395                     mSrcWidth, mSrcHeight, mDepth, 0, getGLTextureFormat(), 
00396                     GL_UNSIGNED_BYTE, data );
00397             }
00398             else
00399             {
00400                 gluBuild2DMipmaps(
00401                     mTextureType == TEX_TYPE_CUBE_MAP ? 
00402                         GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceNumber : 
00403                         getGLTextureType(), 
00404                     mHasAlpha ? GL_RGBA8 : GL_RGB8, mSrcWidth, mSrcHeight, 
00405                     getGLTextureFormat(), GL_UNSIGNED_BYTE, data);
00406             }
00407         }
00408         else
00409         {
00410             if(mTextureType == TEX_TYPE_1D)
00411             {
00412                 glTexImage1D(
00413                     getGLTextureType(), 0, mHasAlpha ? GL_RGBA8 : GL_RGB8, 
00414                     mSrcWidth, 0, getGLTextureFormat(), GL_UNSIGNED_BYTE, data);
00415             }
00416             else if (mTextureType == TEX_TYPE_3D)
00417             {
00418                 glTexImage3D(
00419                     getGLTextureType(), 0, mHasAlpha ? GL_RGBA8 : GL_RGB8, 
00420                     mSrcWidth, mSrcHeight, mDepth, 0, getGLTextureFormat(), 
00421                     GL_UNSIGNED_BYTE, data );
00422             }
00423             else
00424             {
00425                 if(isCompressed && Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability( RSC_TEXTURE_COMPRESSION_DXT ))
00426                 {    
00427                     unsigned short blockSize = (mFormat == PF_DXT1) ? 8 : 16;
00428                     int size = ((mWidth+3)/4)*((mHeight+3)/4)*blockSize; 
00429 
00430                     glCompressedTexImage2DARB_ptr(
00431                         mTextureType == TEX_TYPE_CUBE_MAP ?
00432                             GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceNumber :
00433                             getGLTextureType(), 0,
00434                          getGLTextureFormat(), mSrcWidth, mSrcHeight, 0, 
00435                          size, data);
00436                 }
00437                 else
00438                 {
00439                     glTexImage2D(
00440                         mTextureType == TEX_TYPE_CUBE_MAP ? 
00441                             GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceNumber : 
00442                             getGLTextureType(), 0, 
00443                         mHasAlpha ? GL_RGBA8 : GL_RGB8, mSrcWidth, mSrcHeight, 
00444                         0, getGLTextureFormat(), GL_UNSIGNED_BYTE, data );
00445                 }
00446             }
00447         }
00448 
00449         mGLSupport.end_context();
00450     }
00451 
00452     void GLRenderTexture::_copyToTexture(void)
00453     {
00454         
00455         glBindTexture(GL_TEXTURE_2D,
00456             static_cast<GLTexture*>(mTexture)->getGLID());
00457             
00458         glCopyTexSubImage2D(GL_TEXTURE_2D, mTexture->getNumMipMaps(), 0, 0,
00459             0, 0, mWidth, mHeight);
00460 
00461     }
00462 }
00463 

Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:12 2004