00001 /* 00002 ----------------------------------------------------------------------------- 00003 This source file is part of OGRE 00004 (Object-oriented Graphics Rendering Engine) 00005 For the latest info, see http://www.ogre3d.org/ 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 #include "OgreStableHeaders.h" 00026 #include "OgreImage.h" 00027 00028 #include "OgreArchiveManager.h" 00029 #include "OgreException.h" 00030 #include "OgreImageCodec.h" 00031 #include "OgreSDDataChunk.h" 00032 // Dependency on IL/ILU for resize 00033 #include <IL/il.h> 00034 #include <IL/ilu.h> 00035 namespace Ogre { 00036 ImageCodec::~ImageCodec() { 00037 } 00038 00039 //----------------------------------------------------------------------------- 00040 Image::Image() 00041 : m_uDepth(0), 00042 m_uSize(0), 00043 m_uNumMipmaps(0), 00044 m_uFlags(0), 00045 m_pBuffer( NULL ), 00046 m_bAutoDelete( true ) 00047 { 00048 } 00049 00050 //----------------------------------------------------------------------------- 00051 Image::Image( const Image &img ) 00052 { 00053 // call assignment operator 00054 *this = img; 00055 } 00056 00057 //----------------------------------------------------------------------------- 00058 Image::~Image() 00059 { 00060 //Only delete if this was not a dynamic image (meaning app holds & destroys buffer) 00061 if( m_pBuffer && m_bAutoDelete ) 00062 { 00063 delete[] m_pBuffer; 00064 m_pBuffer = NULL; 00065 } 00066 } 00067 00068 //----------------------------------------------------------------------------- 00069 Image & Image::operator = ( const Image &img ) 00070 { 00071 m_uWidth = img.m_uWidth; 00072 m_uHeight = img.m_uHeight; 00073 m_uDepth = img.m_uDepth; 00074 m_eFormat = img.m_eFormat; 00075 m_uSize = img.m_uSize; 00076 m_uFlags = img.m_uFlags; 00077 m_ucPixelSize = img.m_ucPixelSize; 00078 m_uNumMipmaps = img.m_uNumMipmaps; 00079 m_bAutoDelete = img.m_bAutoDelete; 00080 00081 //Only create/copy when previous data was not dynamic data 00082 if( m_bAutoDelete ) 00083 { 00084 m_pBuffer = new uchar[ m_uSize ]; 00085 memcpy( m_pBuffer, img.m_pBuffer, m_uSize ); 00086 } 00087 else 00088 { 00089 m_pBuffer = img.m_pBuffer; 00090 } 00091 00092 return *this; 00093 } 00094 00095 //----------------------------------------------------------------------------- 00096 Image & Image::flipAroundY() 00097 { 00098 OgreGuard( "Image::flipAroundY" ); 00099 00100 if( !m_pBuffer ) 00101 { 00102 Except( 00103 Exception::ERR_INTERNAL_ERROR, 00104 "Can not flip an unitialized texture", 00105 "Image::flipAroundY" ); 00106 } 00107 00108 uchar *pTempBuffer1 = NULL; 00109 ushort *pTempBuffer2 = NULL; 00110 uchar *pTempBuffer3 = NULL; 00111 uint *pTempBuffer4 = NULL; 00112 00113 uchar *src1 = m_pBuffer, *dst1 = NULL; 00114 ushort *src2 = (ushort *)m_pBuffer, *dst2 = NULL; 00115 uchar *src3 = m_pBuffer, *dst3 = NULL; 00116 uint *src4 = (uint *)m_pBuffer, *dst4 = NULL; 00117 00118 ushort y; 00119 switch (m_ucPixelSize) 00120 { 00121 case 1: 00122 pTempBuffer1 = new uchar[m_uWidth * m_uHeight]; 00123 for (y = 0; y < m_uHeight; y++) 00124 { 00125 dst1 = (pTempBuffer1 + ((y * m_uWidth) + m_uWidth - 1)); 00126 for (ushort x = 0; x < m_uWidth; x++) 00127 memcpy(dst1--, src1++, sizeof(uchar)); 00128 } 00129 00130 memcpy(m_pBuffer, pTempBuffer1, m_uWidth * m_uHeight * sizeof(uchar)); 00131 delete [] pTempBuffer1; 00132 break; 00133 00134 case 2: 00135 pTempBuffer2 = new ushort[m_uWidth * m_uHeight]; 00136 for (y = 0; y < m_uHeight; y++) 00137 { 00138 dst2 = (pTempBuffer2 + ((y * m_uWidth) + m_uWidth - 1)); 00139 for (ushort x = 0; x < m_uWidth; x++) 00140 memcpy(dst2--, src2++, sizeof(ushort)); 00141 } 00142 00143 memcpy(m_pBuffer, pTempBuffer2, m_uWidth * m_uHeight * sizeof(ushort)); 00144 delete [] pTempBuffer2; 00145 break; 00146 00147 case 3: 00148 pTempBuffer3 = new uchar[m_uWidth * m_uHeight * 3]; 00149 for (y = 0; y < m_uHeight; y++) 00150 { 00151 uint offset = ((y * m_uWidth) + (m_uWidth - 1)) * 3; 00152 dst3 = pTempBuffer3; 00153 dst3 += offset; 00154 for (ushort x = 0; x < m_uWidth; x++) 00155 { 00156 memcpy(dst3, src3, sizeof(uchar) * 3); 00157 dst3 -= 3; src3 += 3; 00158 } 00159 } 00160 00161 memcpy(m_pBuffer, pTempBuffer3, m_uWidth * m_uHeight * sizeof(uchar) * 3); 00162 delete [] pTempBuffer3; 00163 break; 00164 00165 case 4: 00166 pTempBuffer4 = new uint[m_uWidth * m_uHeight]; 00167 for (y = 0; y < m_uHeight; y++) 00168 { 00169 dst4 = (pTempBuffer4 + ((y * m_uWidth) + m_uWidth - 1)); 00170 for (ushort x = 0; x < m_uWidth; x++) 00171 memcpy(dst4--, src4++, sizeof(uint)); 00172 } 00173 00174 memcpy(m_pBuffer, pTempBuffer4, m_uWidth * m_uHeight * sizeof(uint)); 00175 delete [] pTempBuffer4; 00176 break; 00177 00178 default: 00179 Except( 00180 Exception::ERR_INTERNAL_ERROR, 00181 "Unknown pixel depth", 00182 "Image::flipAroundY" ); 00183 break; 00184 } 00185 00186 OgreUnguardRet( *this ); 00187 } 00188 00189 //----------------------------------------------------------------------------- 00190 Image & Image::flipAroundX() 00191 { 00192 OgreGuard( "Image::flipAroundX" ); 00193 00194 if( !m_pBuffer ) 00195 { 00196 Except( 00197 Exception::ERR_INTERNAL_ERROR, 00198 "Can not flip an unitialized texture", 00199 "Image::flipAroundX" ); 00200 } 00201 00202 size_t rowSpan = m_uWidth * m_ucPixelSize; 00203 00204 uchar *pTempBuffer = new uchar[ rowSpan * m_uHeight ]; 00205 uchar *ptr1 = m_pBuffer, *ptr2 = pTempBuffer + ( ( m_uHeight - 1 ) * rowSpan ); 00206 00207 for( ushort i = 0; i < m_uHeight; i++ ) 00208 { 00209 memcpy( ptr2, ptr1, rowSpan ); 00210 ptr1 += rowSpan; ptr2 -= rowSpan; 00211 } 00212 00213 memcpy( m_pBuffer, pTempBuffer, rowSpan * m_uHeight); 00214 00215 delete [] pTempBuffer; 00216 00217 OgreUnguardRet( *this ); 00218 } 00219 00220 //----------------------------------------------------------------------------- 00221 Image& Image::loadDynamicImage( uchar* pData, ushort uWidth, ushort uHeight, 00222 PixelFormat eFormat ) 00223 { 00224 OgreGuard( "Image::loadDynamicImage" ); 00225 00226 m_uWidth = uWidth; 00227 m_uHeight = uHeight; 00228 m_eFormat = eFormat; 00229 m_ucPixelSize = PF2PS( m_eFormat ); 00230 m_uSize = m_uWidth * m_uHeight * m_ucPixelSize; 00231 00232 m_pBuffer = pData; 00233 00234 m_bAutoDelete = false; 00235 00236 OgreUnguardRet( *this ); 00237 } 00238 00239 //----------------------------------------------------------------------------- 00240 Image & Image::loadRawData( 00241 const DataChunk &pData, 00242 ushort uWidth, ushort uHeight, 00243 PixelFormat eFormat ) 00244 { 00245 OgreGuard( "Image::loadRawData" ); 00246 00247 m_uWidth = uWidth; 00248 m_uHeight = uHeight; 00249 m_eFormat = eFormat; 00250 m_ucPixelSize = PF2PS( m_eFormat ); 00251 m_uSize = m_uWidth * m_uHeight * m_ucPixelSize; 00252 00253 m_pBuffer = new uchar[ uWidth * uHeight * m_ucPixelSize ]; 00254 memcpy( m_pBuffer, pData.getPtr(), uWidth * uHeight * m_ucPixelSize ); 00255 00256 OgreUnguardRet( *this ); 00257 } 00258 00259 //----------------------------------------------------------------------------- 00260 Image & Image::load( const String& strFileName ) 00261 { 00262 OgreGuard( "Image::load" ); 00263 00264 if( m_pBuffer ) 00265 { 00266 delete[] m_pBuffer; 00267 m_pBuffer = NULL; 00268 } 00269 00270 String strExt; 00271 00272 size_t pos = strFileName.find_last_of("."); 00273 if( pos == String::npos ) 00274 Except( 00275 Exception::ERR_INVALIDPARAMS, 00276 "Unable to load image file '" + strFileName + "' - invalid extension.", 00277 "Image::load" ); 00278 00279 while( pos != strFileName.length() - 1 ) 00280 strExt += strFileName[++pos]; 00281 00282 Codec * pCodec = Codec::getCodec(strExt); 00283 if( !pCodec ) 00284 Except( 00285 Exception::ERR_INVALIDPARAMS, 00286 "Unable to load image file '" + strFileName + "' - invalid extension.", 00287 "Image::load" ); 00288 00289 SDDataChunk encoded; 00290 DataChunk decoded; 00291 00292 if( !ArchiveManager::getSingleton()._findResourceData( 00293 strFileName, 00294 encoded ) ) 00295 { 00296 Except( 00297 Exception::ERR_INVALIDPARAMS, 00298 "Unable to find image file '" + strFileName + "'.", 00299 "Image::load" ); 00300 } 00301 00302 ImageCodec::ImageData * pData = static_cast< ImageCodec::ImageData * > ( 00303 pCodec->decode( encoded, &decoded ) ); 00304 00305 // Get the format and compute the pixel size 00306 m_uWidth = pData->width; 00307 m_uHeight = pData->height; 00308 m_uDepth = pData->depth; 00309 m_uSize = pData->size; 00310 m_eFormat = pData->format; 00311 m_uNumMipmaps = pData->num_mipmaps; 00312 m_ucPixelSize = PF2PS( m_eFormat ); 00313 m_uFlags = pData->flags; 00314 00315 delete pData; 00316 00317 m_pBuffer = decoded.getPtr(); 00318 00319 OgreUnguardRet( *this ); 00320 } 00321 //----------------------------------------------------------------------------- 00322 void Image::save(const String& filename) 00323 { 00324 if( !m_pBuffer ) 00325 { 00326 Except(Exception::ERR_INVALIDPARAMS, "No image data loaded", 00327 "Image::save"); 00328 } 00329 00330 String strExt; 00331 size_t pos = filename.find_last_of("."); 00332 if( pos == String::npos ) 00333 Except( 00334 Exception::ERR_INVALIDPARAMS, 00335 "Unable to save image file '" + filename + "' - invalid extension.", 00336 "Image::save" ); 00337 00338 while( pos != filename.length() - 1 ) 00339 strExt += filename[++pos]; 00340 00341 Codec * pCodec = Codec::getCodec(strExt); 00342 if( !pCodec ) 00343 Except( 00344 Exception::ERR_INVALIDPARAMS, 00345 "Unable to save image file '" + filename + "' - invalid extension.", 00346 "Image::save" ); 00347 00348 ImageCodec::ImageData imgData; 00349 imgData.format = m_eFormat; 00350 imgData.height = m_uHeight; 00351 imgData.width = m_uWidth; 00352 DataChunk wrapper(m_pBuffer, m_uSize); 00353 00354 pCodec->codeToFile(wrapper, filename, &imgData); 00355 } 00356 //----------------------------------------------------------------------------- 00357 Image & Image::load( const DataChunk& chunk, const String& type ) 00358 { 00359 OgreGuard( "Image::load" ); 00360 00361 String strType = type; 00362 00363 Codec * pCodec = Codec::getCodec(strType); 00364 if( !pCodec ) 00365 Except( 00366 Exception::ERR_INVALIDPARAMS, 00367 "Unable to load image - invalid extension.", 00368 "Image::load" ); 00369 00370 DataChunk decoded; 00371 00372 ImageCodec::ImageData * pData = static_cast< ImageCodec::ImageData * >( 00373 pCodec->decode( chunk, &decoded ) ); 00374 00375 m_uWidth = pData->width; 00376 m_uHeight = pData->height; 00377 m_uDepth = pData->depth; 00378 m_uSize = pData->size; 00379 m_uNumMipmaps = pData->num_mipmaps; 00380 m_uFlags = pData->flags; 00381 00382 // Get the format and compute the pixel size 00383 m_eFormat = pData->format; 00384 m_ucPixelSize = PF2PS( m_eFormat ); 00385 00386 delete pData; 00387 00388 m_pBuffer = decoded.getPtr(); 00389 00390 OgreUnguardRet( *this ); 00391 } 00392 00393 //----------------------------------------------------------------------------- 00394 uchar* Image::getData() 00395 { 00396 return m_pBuffer; 00397 } 00398 00399 //----------------------------------------------------------------------------- 00400 const uchar* Image::getData() const 00401 { 00402 assert( m_pBuffer ); 00403 return m_pBuffer; 00404 } 00405 00406 //----------------------------------------------------------------------------- 00407 size_t Image::getSize() const 00408 { 00409 return m_uSize; 00410 } 00411 00412 //----------------------------------------------------------------------------- 00413 unsigned short Image::getNumMipmaps() const 00414 { 00415 return m_uNumMipmaps; 00416 } 00417 00418 //----------------------------------------------------------------------------- 00419 bool Image::hasFlag(const ImageFlags imgFlag) const 00420 { 00421 if(m_uFlags & imgFlag) 00422 { 00423 return true; 00424 } 00425 else 00426 { 00427 return false; 00428 } 00429 } 00430 00431 //----------------------------------------------------------------------------- 00432 ushort Image::getDepth() const 00433 { 00434 return m_uDepth; 00435 } 00436 //----------------------------------------------------------------------------- 00437 ushort Image::getWidth() const 00438 { 00439 return m_uWidth; 00440 } 00441 00442 //----------------------------------------------------------------------------- 00443 ushort Image::getHeight() const 00444 { 00445 return m_uHeight; 00446 } 00447 00448 //----------------------------------------------------------------------------- 00449 ushort Image::getRowSpan() const 00450 { 00451 return m_uWidth * m_ucPixelSize; 00452 } 00453 00454 //----------------------------------------------------------------------------- 00455 PixelFormat Image::getFormat() const 00456 { 00457 return m_eFormat; 00458 } 00459 00460 //----------------------------------------------------------------------------- 00461 uchar Image::getBPP() const 00462 { 00463 return m_ucPixelSize * 8; 00464 } 00465 00466 //----------------------------------------------------------------------------- 00467 bool Image::getHasAlpha(void) const 00468 { 00469 return Image::formatHasAlpha(m_eFormat); 00470 } 00471 //----------------------------------------------------------------------------- 00472 bool Image::formatHasAlpha(PixelFormat format) 00473 { 00474 switch( format ) 00475 { 00476 case PF_A8: 00477 case PF_A4L4: 00478 case PF_L4A4: 00479 case PF_A4R4G4B4: 00480 case PF_B4G4R4A4: 00481 case PF_A8R8G8B8: 00482 case PF_B8G8R8A8: 00483 case PF_A2R10G10B10: 00484 case PF_B10G10R10A2: 00485 return true; 00486 00487 case PF_UNKNOWN: 00488 case PF_L8: 00489 case PF_R5G6B5: 00490 case PF_B5G6R5: 00491 case PF_R8G8B8: 00492 case PF_B8G8R8: 00493 default: 00494 return false; 00495 } 00496 } 00497 //----------------------------------------------------------------------------- 00498 void Image::applyGamma( unsigned char *buffer, Real gamma, size_t size, uchar bpp ) 00499 { 00500 if( gamma == 1.0f ) 00501 return; 00502 00503 //NB only 24/32-bit supported 00504 if( bpp != 24 && bpp != 32 ) return; 00505 00506 uint stride = bpp >> 3; 00507 00508 for( size_t i = 0, j = size / stride; i < j; i++, buffer += stride ) 00509 { 00510 float r, g, b; 00511 00512 r = (float)buffer[0]; 00513 g = (float)buffer[1]; 00514 b = (float)buffer[2]; 00515 00516 r = r * gamma; 00517 g = g * gamma; 00518 b = b * gamma; 00519 00520 float scale = 1.0f, tmp; 00521 00522 if( r > 255.0f && (tmp=(255.0f/r)) < scale ) 00523 scale = tmp; 00524 if( g > 255.0f && (tmp=(255.0f/g)) < scale ) 00525 scale = tmp; 00526 if( b > 255.0f && (tmp=(255.0f/b)) < scale ) 00527 scale = tmp; 00528 00529 r *= scale; g *= scale; b *= scale; 00530 00531 buffer[0] = (uchar)r; 00532 buffer[1] = (uchar)g; 00533 buffer[2] = (uchar)b; 00534 } 00535 } 00536 //----------------------------------------------------------------------------- 00537 // Local declaration of DevIL functions to prevent DevIL dependencies on header users 00538 ILenum getILFilter(Image::Filter filter) 00539 { 00540 switch (filter) 00541 { 00542 case Image::FILTER_NEAREST: 00543 return ILU_NEAREST; 00544 case Image::FILTER_LINEAR: 00545 return ILU_LINEAR; 00546 case Image::FILTER_BILINEAR: 00547 return ILU_BILINEAR; 00548 case Image::FILTER_BOX: 00549 return ILU_SCALE_BOX; 00550 case Image::FILTER_TRIANGLE: 00551 return ILU_SCALE_TRIANGLE; 00552 case Image::FILTER_BICUBIC: 00553 return ILU_SCALE_BSPLINE; 00554 }; 00555 // keep compiler happy 00556 return ILU_NEAREST; 00557 } 00558 //----------------------------------------------------------------------------- 00559 void Image::resize(ushort width, ushort height, Filter filter) 00560 { 00561 ILuint ImageName; 00562 00563 ilGenImages( 1, &ImageName ); 00564 ilBindImage( ImageName ); 00565 00566 std::pair< int, int > fmt_bpp = OgreFormat2ilFormat( m_eFormat ); 00567 ilTexImage( 00568 m_uWidth, m_uHeight, 1, fmt_bpp.second, fmt_bpp.first, IL_UNSIGNED_BYTE, 00569 static_cast< void * >( m_pBuffer ) ); 00570 00571 // set filter 00572 iluImageParameter(ILU_FILTER, getILFilter(filter)); 00573 00574 iluScale(width, height, 1); 00575 00576 // delete existing buffer and recreate with new settings 00577 delete [] m_pBuffer; 00578 m_uWidth = width; 00579 m_uHeight = height; 00580 size_t dataSize = width * height * m_ucPixelSize; 00581 m_pBuffer = new uchar[dataSize]; 00582 memcpy(m_pBuffer, ilGetData(), dataSize); 00583 00584 ilDeleteImages(1, &ImageName); 00585 00586 // return to default filter 00587 iluImageParameter(ILU_FILTER, ILU_NEAREST); 00588 } 00589 00590 }
Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:30 2004