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

OgreImage.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://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