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 GLTexture::GLTexture(const String& name, GLSupport& support, TextureType texType, 00066 uint width, uint height, uint num_mips, PixelFormat format, 00067 TextureUsage usage) : 00068 Texture(name, texType, width, height, 1, num_mips, format, usage), 00069 mGLSupport(support), 00070 mTextureID(0) 00071 { 00072 } 00073 00074 GLTexture::~GLTexture() 00075 { 00076 unload(); 00077 } 00078 00079 GLenum GLTexture::getGLTextureType(void) const 00080 { 00081 switch(mTextureType) 00082 { 00083 case TEX_TYPE_1D: 00084 return GL_TEXTURE_1D; 00085 case TEX_TYPE_2D: 00086 return GL_TEXTURE_2D; 00087 case TEX_TYPE_3D: 00088 return GL_TEXTURE_3D; 00089 case TEX_TYPE_CUBE_MAP: 00090 return GL_TEXTURE_CUBE_MAP; 00091 default: 00092 return 0; 00093 }; 00094 } 00095 00096 GLenum GLTexture::getGLTextureFormat(void) const 00097 { 00098 switch(mFormat) 00099 { 00100 case PF_L8: 00101 return GL_LUMINANCE; 00102 case PF_R8G8B8: 00103 return GL_RGB; 00104 case PF_B8G8R8: 00105 return GL_BGR; 00106 case PF_B8G8R8A8: 00107 return GL_BGRA; 00108 case PF_A8R8G8B8: 00109 return GL_RGBA; 00110 case PF_DXT1: 00111 return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; 00112 case PF_DXT3: 00113 return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; 00114 case PF_DXT5: 00115 return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; 00116 default: 00117 return 0; 00118 } 00119 } 00120 00121 void GLTexture::blitToTexture( 00122 const Image& src, 00123 unsigned uStartX, unsigned uStartY ) 00124 { 00125 if (this->getTextureType() != TEX_TYPE_2D) 00126 Except( Exception::UNIMPLEMENTED_FEATURE, "**** Blit to texture implemented only for 2D textures!!! ****", "GLTexture::blitToTexture" ); 00127 00128 mGLSupport.begin_context(); 00129 glBindTexture( GL_TEXTURE_2D, mTextureID ); 00130 glTexSubImage2D( 00131 GL_TEXTURE_2D, 0, 00132 uStartX, uStartY, 00133 src.getWidth(), src.getHeight(), 00134 getGLTextureFormat(), 00135 GL_UNSIGNED_BYTE, src.getData() ); 00136 mGLSupport.end_context(); 00137 } 00138 00139 uchar* GLTexture::rescaleNPower2( const Image& src ) 00140 { 00141 // Scale image to n^2 dimensions 00142 unsigned int newWidth = (1 << mostSignificantBitSet(mSrcWidth)); 00143 if (newWidth != mSrcWidth) 00144 newWidth <<= 1; 00145 00146 unsigned int newHeight = (1 << mostSignificantBitSet(mSrcHeight)); 00147 if (newHeight != mSrcHeight) 00148 newHeight <<= 1; 00149 00150 uchar *pTempData; 00151 if(newWidth != mSrcWidth || newHeight != mSrcHeight) 00152 { 00153 unsigned int newImageSize = newWidth * newHeight * 00154 (mHasAlpha ? 4 : 3); 00155 00156 pTempData = new uchar[ newImageSize ]; 00157 mGLSupport.begin_context(); 00158 if(gluScaleImage(getGLTextureFormat(), mSrcWidth, mSrcHeight, 00159 GL_UNSIGNED_BYTE, src.getData(), newWidth, newHeight, 00160 GL_UNSIGNED_BYTE, pTempData) != 0) 00161 { 00162 Except(Exception::ERR_INTERNAL_ERROR, 00163 "Error while rescaling image!", "GLTexture::rescaleNPower2"); 00164 } 00165 mGLSupport.end_context(); 00166 00167 Image::applyGamma( pTempData, mGamma, newImageSize, mSrcBpp ); 00168 00169 mSrcWidth = mWidth = newWidth; 00170 mSrcHeight = mHeight = newHeight; 00171 } 00172 else 00173 { 00174 pTempData = new uchar[ src.getSize() ]; 00175 memcpy( pTempData, src.getData(), src.getSize() ); 00176 Image::applyGamma( pTempData, mGamma, src.getSize(), mSrcBpp ); 00177 } 00178 00179 return pTempData; 00180 } 00181 00182 void GLTexture::loadImage( const Image& img ) 00183 { 00184 std::vector<Image> images; 00185 00186 images.push_back(img); 00187 loadImages(images); 00188 images.clear(); 00189 } 00190 00191 void GLTexture::loadImages( const std::vector<Image>& images ) 00192 { 00193 bool useSoftwareMipmaps = true; 00194 00195 if( mIsLoaded ) 00196 { 00197 std::cout << "Unloading image" << std::endl; 00198 unload(); 00199 } 00200 00201 // Create the GL texture 00202 mGLSupport.begin_context(); 00203 glGenTextures( 1, &mTextureID ); 00204 glBindTexture( getGLTextureType(), mTextureID ); 00205 00206 if(mNumMipMaps && Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_AUTOMIPMAP)) 00207 { 00208 glTexParameteri( getGLTextureType(), GL_GENERATE_MIPMAP, GL_TRUE ); 00209 useSoftwareMipmaps = false; 00210 } 00211 00212 for(size_t i = 0; i < images.size(); i++) 00213 { 00214 const Image& img = images[i]; 00215 00216 LogManager::getSingleton().logMessage( 00217 LML_NORMAL, 00218 "GLTexture: Loading %s with %d mipmaps from Image.", 00219 mName.c_str(), mNumMipMaps ); 00220 00221 mFormat = img.getFormat(); 00222 00223 mSrcBpp = Image::PF2BPP(mFormat); 00224 mHasAlpha = img.getHasAlpha(); 00225 00226 mSrcWidth = img.getWidth(); 00227 mSrcHeight = img.getHeight(); 00228 // Same dest dimensions for GL 00229 mWidth = mSrcWidth; 00230 mHeight = mSrcHeight; 00231 00232 mDepth = img.getDepth(); 00233 00234 unsigned short imageMipmaps = img.getNumMipmaps(); 00235 if(imageMipmaps) 00236 mNumMipMaps = imageMipmaps; 00237 00238 glTexParameteri(getGLTextureType(), GL_TEXTURE_MAX_LEVEL, mNumMipMaps); 00239 00240 uchar *pTempData = rescaleNPower2(img); 00241 00242 generateMipMaps( pTempData, useSoftwareMipmaps, img.hasFlag(IF_COMPRESSED), i ); 00243 delete [] pTempData; 00244 } 00245 mGLSupport.end_context(); 00246 00247 // Update size (the final size, not including temp space) 00248 unsigned short bytesPerPixel = mFinalBpp >> 3; 00249 if( !mHasAlpha && mFinalBpp == 32 ) 00250 { 00251 bytesPerPixel--; 00252 } 00253 mSize = mWidth * mHeight * bytesPerPixel; 00254 00255 mIsLoaded = true; 00256 } 00257 00258 void GLTexture::createRenderTexture(void) 00259 { 00260 if (this->getTextureType() != TEX_TYPE_2D) 00261 Except( Exception::UNIMPLEMENTED_FEATURE, "**** Create render texture implemented only for 2D textures!!! ****", "GLTexture::createRenderTexture" ); 00262 00263 // Create the GL texture 00264 mGLSupport.begin_context(); 00265 glGenTextures( 1, &mTextureID ); 00266 glBindTexture( GL_TEXTURE_2D, mTextureID ); 00267 00268 glTexImage2D( GL_TEXTURE_2D, 0, getGLTextureFormat(), 00269 mWidth, mHeight, 0, getGLTextureFormat(), GL_UNSIGNED_BYTE, 0 ); 00270 00271 // This needs to be set otherwise the texture doesn't get rendered 00272 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mNumMipMaps ); 00273 mGLSupport.end_context(); 00274 } 00275 00276 void GLTexture::load() 00277 { 00278 if( mUsage == TU_RENDERTARGET ) 00279 { 00280 createRenderTexture(); 00281 mIsLoaded = true; 00282 } 00283 else 00284 { 00285 if(mTextureType == TEX_TYPE_1D || mTextureType == TEX_TYPE_2D || 00286 mTextureType == TEX_TYPE_3D) 00287 { 00288 Image img; 00289 img.load( mName ); 00290 00291 if (StringUtil::endsWith(getName(), "dds") && img.hasFlag(IF_CUBEMAP)) 00292 { 00293 Image newImage; 00294 std::vector<Image> images; 00295 uint imageSize = img.getSize() / 6; 00296 00297 mTextureType = TEX_TYPE_CUBE_MAP; 00298 00299 uint offset = 0; 00300 for(int i = 0; i < 6; i++) 00301 { 00302 DataChunk chunk(img.getData() + offset, imageSize); 00303 newImage.loadRawData(chunk, img.getWidth(), 00304 img.getHeight(), img.getFormat()); 00305 offset += imageSize; 00306 images.push_back(newImage); 00307 } 00308 00309 loadImages( images ); 00310 images.clear(); 00311 } 00312 else 00313 { 00314 // If this is a dds volumetric texture set the texture type flag accordingly. 00315 if(StringUtil::endsWith(getName(), ".dds") && img.getDepth() > 1) 00316 mTextureType = TEX_TYPE_3D; 00317 00318 loadImage( img ); 00319 } 00320 } 00321 else if (mTextureType == TEX_TYPE_CUBE_MAP) 00322 { 00323 Image img; 00324 String baseName, ext; 00325 std::vector<Image> images; 00326 static const String suffixes[6] = {"_rt", "_lf", "_up", "_dn", "_fr", "_bk"}; 00327 00328 for(size_t i = 0; i < 6; i++) 00329 { 00330 size_t pos = mName.find_last_of("."); 00331 baseName = mName.substr(0, pos); 00332 ext = mName.substr(pos); 00333 String fullName = baseName + suffixes[i] + ext; 00334 00335 img.load( fullName ); 00336 images.push_back(img); 00337 } 00338 00339 loadImages( images ); 00340 images.clear(); 00341 } 00342 else 00343 Except( Exception::UNIMPLEMENTED_FEATURE, "**** Unknown texture type ****", "GLTexture::load" ); 00344 } 00345 } 00346 00347 void GLTexture::unload() 00348 { 00349 if( mIsLoaded ) 00350 { 00351 glDeleteTextures( 1, &mTextureID ); 00352 mIsLoaded = false; 00353 } 00354 } 00355 00356 void GLTexture::generateMipMaps( const uchar *data, bool useSoftware, 00357 bool isCompressed, size_t faceNumber ) 00358 { 00359 mGLSupport.begin_context(); 00360 if(useSoftware && mNumMipMaps) 00361 { 00362 if(mTextureType == TEX_TYPE_1D) 00363 { 00364 gluBuild1DMipmaps( 00365 getGLTextureType(), mHasAlpha ? GL_RGBA8 : GL_RGB8, 00366 mSrcWidth, getGLTextureFormat(), GL_UNSIGNED_BYTE, data); 00367 } 00368 else if (mTextureType == TEX_TYPE_3D) 00369 { 00370 /* Requires GLU 1.3 which is harder to come by 00371 Most 3D textures don't need mipmaps? 00372 gluBuild3DMipmaps( 00373 getGLTextureType(), mHasAlpha ? GL_RGBA8 : GL_RGB8, 00374 mSrcWidth, mSrcHeight, mDepth, getGLTextureFormat(), 00375 GL_UNSIGNED_BYTE, data); 00376 */ 00377 glTexImage3D( 00378 getGLTextureType(), 0, mHasAlpha ? GL_RGBA8 : GL_RGB8, 00379 mSrcWidth, mSrcHeight, mDepth, 0, getGLTextureFormat(), 00380 GL_UNSIGNED_BYTE, data ); 00381 } 00382 else 00383 { 00384 gluBuild2DMipmaps( 00385 mTextureType == TEX_TYPE_CUBE_MAP ? 00386 GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceNumber : 00387 getGLTextureType(), 00388 mHasAlpha ? GL_RGBA8 : GL_RGB8, mSrcWidth, mSrcHeight, 00389 getGLTextureFormat(), GL_UNSIGNED_BYTE, data); 00390 } 00391 } 00392 else 00393 { 00394 if(mTextureType == TEX_TYPE_1D) 00395 { 00396 glTexImage1D( 00397 getGLTextureType(), 0, mHasAlpha ? GL_RGBA8 : GL_RGB8, 00398 mSrcWidth, 0, getGLTextureFormat(), GL_UNSIGNED_BYTE, data); 00399 } 00400 else if (mTextureType == TEX_TYPE_3D) 00401 { 00402 glTexImage3D( 00403 getGLTextureType(), 0, mHasAlpha ? GL_RGBA8 : GL_RGB8, 00404 mSrcWidth, mSrcHeight, mDepth, 0, getGLTextureFormat(), 00405 GL_UNSIGNED_BYTE, data ); 00406 } 00407 else 00408 { 00409 if(isCompressed && Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability( RSC_TEXTURE_COMPRESSION_DXT )) 00410 { 00411 unsigned short blockSize = (mFormat == PF_DXT1) ? 8 : 16; 00412 int size = ((mWidth+3)/4)*((mHeight+3)/4)*blockSize; 00413 00414 glCompressedTexImage2DARB_ptr( 00415 mTextureType == TEX_TYPE_CUBE_MAP ? 00416 GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceNumber : 00417 getGLTextureType(), 0, 00418 getGLTextureFormat(), mSrcWidth, mSrcHeight, 0, 00419 size, data); 00420 } 00421 else 00422 { 00423 glTexImage2D( 00424 mTextureType == TEX_TYPE_CUBE_MAP ? 00425 GL_TEXTURE_CUBE_MAP_POSITIVE_X + faceNumber : 00426 getGLTextureType(), 0, 00427 mHasAlpha ? GL_RGBA8 : GL_RGB8, mSrcWidth, mSrcHeight, 00428 0, getGLTextureFormat(), GL_UNSIGNED_BYTE, data ); 00429 } 00430 } 00431 } 00432 00433 mGLSupport.end_context(); 00434 } 00435 00436 void GLRenderTexture::_copyToTexture(void) 00437 { 00438 00439 glBindTexture(GL_TEXTURE_2D, 00440 static_cast<GLTexture*>(mTexture)->getGLID()); 00441 00442 glCopyTexSubImage2D(GL_TEXTURE_2D, mTexture->getNumMipMaps(), 0, 0, 00443 0, 0, mWidth, mHeight); 00444 00445 } 00446 } 00447
Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:26 2004