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