/* ----------------------------------------------------------------------------- This source file is part of OGRE (Object-oriented Graphics Rendering Engine) For the latest info, see http://www.ogre3d.org/ Copyright (c) 2000-2006 Torus Knot Software Ltd Also see acknowledgements in Readme.html This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to http://www.gnu.org/copyleft/lesser.txt. You may alternatively use this source under the terms of a specific version of the OGRE Unrestricted License provided you have obtained such a license from Torus Knot Software Ltd. ----------------------------------------------------------------------------- */ #include #include "OgreILUtil.h" #include #include #include #include #include #include namespace Ogre { /************************************************************************* * IL specific functions */ PixelFormat ILUtil::ilFormat2OgreFormat( int ImageFormat, int ImageType ) { PixelFormat fmt = PF_UNKNOWN; switch( ImageFormat ) { /* Compressed formats -- ignore type */ case IL_DXT1: fmt = PF_DXT1; break; case IL_DXT2: fmt = PF_DXT2; break; case IL_DXT3: fmt = PF_DXT3; break; case IL_DXT4: fmt = PF_DXT4; break; case IL_DXT5: fmt = PF_DXT5; break; /* Normal formats */ case IL_RGB: switch(ImageType) { case IL_FLOAT: fmt = PF_FLOAT32_RGB; break; case IL_UNSIGNED_SHORT: case IL_SHORT: fmt = PF_SHORT_RGBA; break; default: fmt = PF_BYTE_RGB; break; } break; case IL_BGR: switch(ImageType) { case IL_FLOAT: fmt = PF_FLOAT32_RGB; break; case IL_UNSIGNED_SHORT: case IL_SHORT: fmt = PF_SHORT_RGBA; break; default: fmt = PF_BYTE_BGR; break; } break; case IL_RGBA: switch(ImageType) { case IL_FLOAT: fmt = PF_FLOAT32_RGBA; break; case IL_UNSIGNED_SHORT: case IL_SHORT: fmt = PF_SHORT_RGBA; break; default: fmt = PF_BYTE_RGBA; break; } break; case IL_BGRA: switch(ImageType) { case IL_FLOAT: fmt = PF_FLOAT32_RGBA; break; case IL_UNSIGNED_SHORT: case IL_SHORT: fmt = PF_SHORT_RGBA; break; default: fmt = PF_BYTE_BGRA; break; } break; case IL_LUMINANCE: switch(ImageType) { case IL_BYTE: case IL_UNSIGNED_BYTE: fmt = PF_L8; break; default: fmt = PF_L16; } break; case IL_LUMINANCE_ALPHA: fmt = PF_BYTE_LA; break; } return fmt; } //----------------------------------------------------------------------- ILUtil::ILFormat ILUtil::OgreFormat2ilFormat( PixelFormat format ) { switch(format) { case PF_BYTE_L: return ILFormat(1, IL_LUMINANCE, IL_UNSIGNED_BYTE); case PF_BYTE_A: return ILFormat(1, IL_LUMINANCE, IL_UNSIGNED_BYTE); case PF_SHORT_L: return ILFormat(1, IL_LUMINANCE, IL_UNSIGNED_SHORT); case PF_BYTE_LA: return ILFormat(2, IL_LUMINANCE_ALPHA, IL_UNSIGNED_BYTE); case PF_BYTE_RGB: return ILFormat(3, IL_RGB, IL_UNSIGNED_BYTE); case PF_BYTE_RGBA: return ILFormat(4, IL_RGBA, IL_UNSIGNED_BYTE); case PF_BYTE_BGR: return ILFormat(3, IL_BGR, IL_UNSIGNED_BYTE); case PF_BYTE_BGRA: return ILFormat(4, IL_BGRA, IL_UNSIGNED_BYTE); case PF_SHORT_RGBA: return ILFormat(4, IL_RGBA, IL_UNSIGNED_SHORT); case PF_FLOAT32_RGB: return ILFormat(3, IL_RGB, IL_FLOAT); case PF_FLOAT32_RGBA: return ILFormat(4, IL_RGBA, IL_FLOAT); case PF_DXT1: return ILFormat(0, IL_DXT1); case PF_DXT2: return ILFormat(0, IL_DXT2); case PF_DXT3: return ILFormat(0, IL_DXT3); case PF_DXT4: return ILFormat(0, IL_DXT4); case PF_DXT5: return ILFormat(0, IL_DXT5); default: return ILFormat(); } } //----------------------------------------------------------------------- /// Helper functions for DevIL to Ogre conversion inline void packI(uint8 r, uint8 g, uint8 b, uint8 a, PixelFormat pf, void* dest) { PixelUtil::packColour(r, g, b, a, pf, dest); } inline void packI(uint16 r, uint16 g, uint16 b, uint16 a, PixelFormat pf, void* dest) { PixelUtil::packColour((float)r/65535.0f, (float)g/65535.0f, (float)b/65535.0f, (float)a/65535.0f, pf, dest); } inline void packI(float r, float g, float b, float a, PixelFormat pf, void* dest) { PixelUtil::packColour(r, g, b, a, pf, dest); } template void ilToOgreInternal(uint8 *tar, PixelFormat ogrefmt, T r, T g, T b, T a) { const int ilfmt = ilGetInteger( IL_IMAGE_FORMAT ); T *src = (T*)ilGetData(); T *srcend = (T*)((uint8*)ilGetData() + ilGetInteger( IL_IMAGE_SIZE_OF_DATA )); const size_t elemSize = PixelUtil::getNumElemBytes(ogrefmt); while(src < srcend) { switch(ilfmt) { case IL_RGB: r = src[0]; g = src[1]; b = src[2]; src += 3; break; case IL_BGR: b = src[0]; g = src[1]; r = src[2]; src += 3; break; case IL_LUMINANCE: r = src[0]; g = src[0]; b = src[0]; src += 1; break; case IL_LUMINANCE_ALPHA: r = src[0]; g = src[0]; b = src[0]; a = src[1]; src += 2; break; case IL_RGBA: r = src[0]; g = src[1]; b = src[2]; a = src[3]; src += 4; break; case IL_BGRA: b = src[0]; g = src[1]; r = src[2]; a = src[3]; src += 4; break; default: return; } packI(r, g, b, a, ogrefmt, tar); tar += elemSize; } } //----------------------------------------------------------------------- /// Utility function to convert IL data types to UNSIGNED_ ILenum ILabs(ILenum in) { switch(in) { case IL_INT: return IL_UNSIGNED_INT; case IL_BYTE: return IL_UNSIGNED_BYTE; case IL_SHORT: return IL_UNSIGNED_SHORT; default: return in; } } //----------------------------------------------------------------------- void ILUtil::toOgre(const PixelBox &dst) { if(!dst.isConsecutive()) OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED, "Destination must currently be consecutive", "ILUtil::ilToOgre" ) ; if(dst.getWidth() != static_cast(ilGetInteger( IL_IMAGE_WIDTH )) || dst.getHeight() != static_cast(ilGetInteger( IL_IMAGE_HEIGHT )) || dst.getDepth() != static_cast(ilGetInteger( IL_IMAGE_DEPTH ))) OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, "Destination dimensions must equal IL dimension", "ILUtil::ilToOgre" ) ; int ilfmt = ilGetInteger( IL_IMAGE_FORMAT ); int iltp = ilGetInteger( IL_IMAGE_TYPE ); // Check if in-memory format just matches // If yes, we can just copy it and save conversion ILFormat ifmt = OgreFormat2ilFormat( dst.format ); if(ifmt.format == ilfmt && ILabs(ifmt.type) == ILabs(iltp)) { memcpy(dst.data, ilGetData(), ilGetInteger( IL_IMAGE_SIZE_OF_DATA )); return; } // Try if buffer is in a known OGRE format so we can use OGRE its // conversion routines PixelFormat bufFmt = ilFormat2OgreFormat((int)ilfmt, (int)iltp); ifmt = OgreFormat2ilFormat( bufFmt ); if(ifmt.format == ilfmt && ILabs(ifmt.type) == ILabs(iltp)) { // IL format matches another OGRE format PixelBox src(dst.getWidth(), dst.getHeight(), dst.getDepth(), bufFmt, ilGetData()); PixelUtil::bulkPixelConversion(src, dst); return; } // Thee extremely slow method if(iltp == IL_UNSIGNED_BYTE || iltp == IL_BYTE) { ilToOgreInternal(static_cast(dst.data), dst.format, (uint8)0x00,(uint8)0x00,(uint8)0x00,(uint8)0xFF); } else if(iltp == IL_FLOAT) { ilToOgreInternal(static_cast(dst.data), dst.format, 0.0f,0.0f,0.0f,1.0f); } else if(iltp == IL_SHORT || iltp == IL_UNSIGNED_SHORT) { ilToOgreInternal(static_cast(dst.data), dst.format, (uint16)0x0000,(uint16)0x0000,(uint16)0x0000,(uint16)0xFFFF); } else { OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED, "Cannot convert this DevIL type", "ILUtil::ilToOgre" ) ; } } //----------------------------------------------------------------------- void ILUtil::fromOgre(const PixelBox &src) { // ilTexImage http://openil.sourceforge.net/docs/il/f00059.htm ILFormat ifmt = OgreFormat2ilFormat( src.format ); if(src.isConsecutive() && ifmt.isValid()) { // The easy case, the buffer is laid out in memory just like // we want it to be and is in a format DevIL can understand directly // We could even save the copy if DevIL would let us ilTexImage(static_cast(src.getWidth()), static_cast(src.getHeight()), static_cast(src.getDepth()), ifmt.numberOfChannels, ifmt.format, ifmt.type, src.data); } else if(ifmt.isValid()) { // The format can be understood directly by DevIL. The only // problem is that ilTexImage expects our image data consecutively // so we cannot use that directly. // Let DevIL allocate the memory for us, and copy the data consecutively // to its memory ilTexImage(static_cast(src.getWidth()), static_cast(src.getHeight()), static_cast(src.getDepth()), ifmt.numberOfChannels, ifmt.format, ifmt.type, 0); PixelBox dst(src.getWidth(), src.getHeight(), src.getDepth(), src.format, ilGetData()); PixelUtil::bulkPixelConversion(src, dst); } else { // Here it gets ugly. We're stuck with a pixel format that DevIL // can't do anything with. We will do a bulk pixel conversion and // then feed it to DevIL anyway. The problem is finding the best // format to convert to. // most general format supported by OGRE and DevIL PixelFormat fmt = PixelUtil::hasAlpha(src.format)?PF_FLOAT32_RGBA:PF_FLOAT32_RGB; // Make up a pixel format // We don't have to consider luminance formats as they have // straight conversions to DevIL, just weird permutations of RGBA an LA int depths[4]; PixelUtil::getBitDepths(src.format, depths); // Native endian format with all bit depths<8 can safely and quickly be // converted to 24/32 bit if(PixelUtil::isNativeEndian(src.format) && depths[0]<=8 && depths[1]<=8 && depths[2]<=8 && depths[3]<=8) { if(PixelUtil::hasAlpha(src.format)) { fmt = PF_A8R8G8B8; } else { fmt = PF_R8G8B8; } } // Let DevIL allocate the memory for us, then do the conversion ourselves ifmt = OgreFormat2ilFormat( fmt ); ilTexImage(static_cast(src.getWidth()), static_cast(src.getHeight()), static_cast(src.getDepth()), ifmt.numberOfChannels, ifmt.format, ifmt.type, 0); PixelBox dst(src.getWidth(), src.getHeight(), src.getDepth(), fmt, ilGetData()); PixelUtil::bulkPixelConversion(src, dst); } } }