[5] | 1 | /* |
---|
| 2 | ----------------------------------------------------------------------------- |
---|
| 3 | This source file is part of OGRE |
---|
| 4 | (Object-oriented Graphics Rendering Engine) |
---|
| 5 | For the latest info, see http://www.ogre3d.org/ |
---|
| 6 | |
---|
| 7 | Copyright (c) 2000-2006 Torus Knot Software Ltd |
---|
| 8 | Also see acknowledgements in Readme.html |
---|
| 9 | |
---|
| 10 | This program is free software; you can redistribute it and/or modify it under |
---|
| 11 | the terms of the GNU Lesser General Public License as published by the Free Software |
---|
| 12 | Foundation; either version 2 of the License, or (at your option) any later |
---|
| 13 | version. |
---|
| 14 | |
---|
| 15 | This program is distributed in the hope that it will be useful, but WITHOUT |
---|
| 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
---|
| 17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. |
---|
| 18 | |
---|
| 19 | You should have received a copy of the GNU Lesser General Public License along with |
---|
| 20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
---|
| 21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to |
---|
| 22 | http://www.gnu.org/copyleft/lesser.txt. |
---|
| 23 | |
---|
| 24 | You may alternatively use this source under the terms of a specific version of |
---|
| 25 | the OGRE Unrestricted License provided you have obtained such a license from |
---|
| 26 | Torus Knot Software Ltd. |
---|
| 27 | ----------------------------------------------------------------------------- |
---|
| 28 | */ |
---|
| 29 | |
---|
| 30 | #include <OgreStableHeaders.h> |
---|
| 31 | |
---|
| 32 | #include <OgreRoot.h> |
---|
| 33 | #include <OgreRenderSystem.h> |
---|
| 34 | #include "OgreILImageCodec.h" |
---|
| 35 | #include <OgreImage.h> |
---|
| 36 | #include <OgreException.h> |
---|
| 37 | #include "OgreILUtil.h" |
---|
| 38 | |
---|
| 39 | #include <OgreLogManager.h> |
---|
| 40 | #include <OgreStringConverter.h> |
---|
| 41 | |
---|
| 42 | #include <IL/il.h> |
---|
| 43 | #include <IL/ilu.h> |
---|
| 44 | |
---|
| 45 | namespace Ogre { |
---|
| 46 | |
---|
| 47 | bool ILImageCodec::_is_initialised = false; |
---|
| 48 | //--------------------------------------------------------------------- |
---|
| 49 | |
---|
| 50 | ILImageCodec::ILImageCodec(const String &type, unsigned int ilType): |
---|
| 51 | mType(type), |
---|
| 52 | mIlType(ilType) |
---|
| 53 | { |
---|
| 54 | initialiseIL(); |
---|
| 55 | } |
---|
| 56 | |
---|
| 57 | //--------------------------------------------------------------------- |
---|
| 58 | DataStreamPtr ILImageCodec::code(MemoryDataStreamPtr& input, Codec::CodecDataPtr& pData) const |
---|
| 59 | { |
---|
| 60 | |
---|
| 61 | OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "code to memory not implemented", |
---|
| 62 | "ILCodec::code"); |
---|
| 63 | |
---|
| 64 | |
---|
| 65 | } |
---|
| 66 | //--------------------------------------------------------------------- |
---|
| 67 | void ILImageCodec::codeToFile(MemoryDataStreamPtr& input, |
---|
| 68 | const String& outFileName, Codec::CodecDataPtr& pData) const |
---|
| 69 | { |
---|
| 70 | |
---|
| 71 | ILuint ImageName; |
---|
| 72 | |
---|
| 73 | ilGenImages( 1, &ImageName ); |
---|
| 74 | ilBindImage( ImageName ); |
---|
| 75 | |
---|
| 76 | ImageData* pImgData = static_cast< ImageData * >( pData.getPointer() ); |
---|
| 77 | PixelBox src(pImgData->width, pImgData->height, pImgData->depth, pImgData->format, input->getPtr()); |
---|
| 78 | |
---|
| 79 | // Convert image from OGRE to current IL image |
---|
| 80 | ILUtil::fromOgre(src); |
---|
| 81 | |
---|
| 82 | iluFlipImage(); |
---|
| 83 | |
---|
| 84 | // Implicitly pick DevIL codec |
---|
| 85 | ilSaveImage(const_cast< char * >( outFileName.c_str() ) ); |
---|
| 86 | |
---|
| 87 | // Check if everything was ok |
---|
| 88 | ILenum PossibleError = ilGetError() ; |
---|
| 89 | if( PossibleError != IL_NO_ERROR ) { |
---|
| 90 | ilDeleteImages(1, &ImageName); |
---|
| 91 | OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED, |
---|
| 92 | "IL Error, could not save file: " + outFileName, |
---|
| 93 | iluErrorString(PossibleError) ) ; |
---|
| 94 | } |
---|
| 95 | |
---|
| 96 | ilDeleteImages(1, &ImageName); |
---|
| 97 | |
---|
| 98 | } |
---|
| 99 | //--------------------------------------------------------------------- |
---|
| 100 | Codec::DecodeResult ILImageCodec::decode(DataStreamPtr& input) const |
---|
| 101 | { |
---|
| 102 | |
---|
| 103 | // DevIL variables |
---|
| 104 | ILuint ImageName; |
---|
| 105 | |
---|
| 106 | ILint ImageFormat, BytesPerPixel, ImageType; |
---|
| 107 | ImageData* imgData = new ImageData(); |
---|
| 108 | MemoryDataStreamPtr output; |
---|
| 109 | |
---|
| 110 | // Load the image |
---|
| 111 | ilGenImages( 1, &ImageName ); |
---|
| 112 | ilBindImage( ImageName ); |
---|
| 113 | |
---|
| 114 | // Put it right side up |
---|
| 115 | ilEnable(IL_ORIGIN_SET); |
---|
| 116 | ilSetInteger(IL_ORIGIN_MODE, IL_ORIGIN_UPPER_LEFT); |
---|
| 117 | |
---|
| 118 | // Keep DXTC(compressed) data if present |
---|
| 119 | ilSetInteger(IL_KEEP_DXTC_DATA, IL_TRUE); |
---|
| 120 | |
---|
| 121 | // Load image from stream, cache into memory |
---|
| 122 | MemoryDataStream memInput(input); |
---|
| 123 | ilLoadL( |
---|
| 124 | mIlType, |
---|
| 125 | memInput.getPtr(), |
---|
| 126 | static_cast< ILuint >(memInput.size())); |
---|
| 127 | |
---|
| 128 | // Check if everything was ok |
---|
| 129 | ILenum PossibleError = ilGetError() ; |
---|
| 130 | if( PossibleError != IL_NO_ERROR ) { |
---|
| 131 | OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED, |
---|
| 132 | "IL Error", |
---|
| 133 | iluErrorString(PossibleError) ) ; |
---|
| 134 | } |
---|
| 135 | |
---|
| 136 | ImageFormat = ilGetInteger( IL_IMAGE_FORMAT ); |
---|
| 137 | ImageType = ilGetInteger( IL_IMAGE_TYPE ); |
---|
| 138 | |
---|
| 139 | // Convert image if ImageType is incompatible with us (double or long) |
---|
| 140 | if(ImageType != IL_BYTE && ImageType != IL_UNSIGNED_BYTE && |
---|
| 141 | ImageType != IL_FLOAT && |
---|
| 142 | ImageType != IL_UNSIGNED_SHORT && ImageType != IL_SHORT) { |
---|
| 143 | ilConvertImage(ImageFormat, IL_FLOAT); |
---|
| 144 | ImageType = IL_FLOAT; |
---|
| 145 | } |
---|
| 146 | // Converted paletted images |
---|
| 147 | if(ImageFormat == IL_COLOUR_INDEX) |
---|
| 148 | { |
---|
| 149 | ilConvertImage(IL_BGRA, IL_UNSIGNED_BYTE); |
---|
| 150 | ImageFormat = IL_BGRA; |
---|
| 151 | ImageType = IL_UNSIGNED_BYTE; |
---|
| 152 | } |
---|
| 153 | |
---|
| 154 | // Now sets some variables |
---|
| 155 | BytesPerPixel = ilGetInteger( IL_IMAGE_BYTES_PER_PIXEL ); |
---|
| 156 | |
---|
| 157 | imgData->format = ILUtil::ilFormat2OgreFormat( ImageFormat, ImageType ); |
---|
| 158 | imgData->width = ilGetInteger( IL_IMAGE_WIDTH ); |
---|
| 159 | imgData->height = ilGetInteger( IL_IMAGE_HEIGHT ); |
---|
| 160 | imgData->depth = ilGetInteger( IL_IMAGE_DEPTH ); |
---|
| 161 | imgData->num_mipmaps = ilGetInteger ( IL_NUM_MIPMAPS ); |
---|
| 162 | imgData->flags = 0; |
---|
| 163 | |
---|
| 164 | if(imgData->format == PF_UNKNOWN) |
---|
| 165 | { |
---|
| 166 | std::stringstream err; |
---|
| 167 | err << "Unsupported devil format ImageFormat=" << std::hex << ImageFormat << |
---|
| 168 | " ImageType="<< ImageType << std::dec; |
---|
| 169 | ilDeleteImages( 1, &ImageName ); |
---|
| 170 | |
---|
| 171 | OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED, |
---|
| 172 | err.str(), |
---|
| 173 | "ILImageCodec::decode" ) ; |
---|
| 174 | } |
---|
| 175 | |
---|
| 176 | // Check for cubemap |
---|
| 177 | //ILuint cubeflags = ilGetInteger ( IL_IMAGE_CUBEFLAGS ); |
---|
| 178 | size_t numFaces = ilGetInteger ( IL_NUM_IMAGES ) + 1; |
---|
| 179 | if(numFaces == 6) |
---|
| 180 | imgData->flags |= IF_CUBEMAP; |
---|
| 181 | else |
---|
| 182 | numFaces = 1; // Support only 1 or 6 face images for now |
---|
| 183 | |
---|
| 184 | // Keep DXT data (if present at all and the GPU supports it) |
---|
| 185 | ILuint dxtFormat = ilGetInteger( IL_DXTC_DATA_FORMAT ); |
---|
| 186 | if(dxtFormat != IL_DXT_NO_COMP && Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability( RSC_TEXTURE_COMPRESSION_DXT )) |
---|
| 187 | { |
---|
| 188 | imgData->format = ILUtil::ilFormat2OgreFormat( dxtFormat, ImageType ); |
---|
| 189 | imgData->flags |= IF_COMPRESSED; |
---|
| 190 | |
---|
| 191 | // Validate that this devil version saves DXT mipmaps |
---|
| 192 | if(imgData->num_mipmaps>0) |
---|
| 193 | { |
---|
| 194 | ilBindImage(ImageName); |
---|
| 195 | ilActiveMipmap(1); |
---|
| 196 | if((size_t)ilGetInteger( IL_DXTC_DATA_FORMAT ) != dxtFormat) |
---|
| 197 | { |
---|
| 198 | imgData->num_mipmaps=0; |
---|
| 199 | LogManager::getSingleton().logMessage( |
---|
| 200 | "Warning: Custom mipmaps for compressed image "+input->getName()+" were ignored because they are not loaded by this DevIL version"); |
---|
| 201 | } |
---|
| 202 | } |
---|
| 203 | } |
---|
| 204 | |
---|
| 205 | // Calculate total size from number of mipmaps, faces and size |
---|
| 206 | imgData->size = Image::calculateSize(imgData->num_mipmaps, numFaces, |
---|
| 207 | imgData->width, imgData->height, imgData->depth, imgData->format); |
---|
| 208 | |
---|
| 209 | // Bind output buffer |
---|
| 210 | output.bind(new MemoryDataStream(imgData->size)); |
---|
| 211 | size_t offset = 0; |
---|
| 212 | |
---|
| 213 | // Dimensions of current mipmap |
---|
| 214 | size_t width = imgData->width; |
---|
| 215 | size_t height = imgData->height; |
---|
| 216 | size_t depth = imgData->depth; |
---|
| 217 | |
---|
| 218 | // Transfer data |
---|
| 219 | for(size_t mip=0; mip<=imgData->num_mipmaps; ++mip) |
---|
| 220 | { |
---|
| 221 | for(size_t i = 0; i < numFaces; ++i) |
---|
| 222 | { |
---|
| 223 | ilBindImage(ImageName); |
---|
| 224 | if(numFaces > 1) |
---|
| 225 | ilActiveImage(i); |
---|
| 226 | if(imgData->num_mipmaps > 0) |
---|
| 227 | ilActiveMipmap(mip); |
---|
| 228 | /// Size of this face |
---|
| 229 | size_t imageSize = PixelUtil::getMemorySize( |
---|
| 230 | width, height, depth, imgData->format); |
---|
| 231 | if(imgData->flags & IF_COMPRESSED) |
---|
| 232 | { |
---|
| 233 | |
---|
| 234 | // Compare DXT size returned by DevIL with our idea of the compressed size |
---|
| 235 | if(imageSize == ilGetDXTCData(NULL, 0, dxtFormat)) |
---|
| 236 | { |
---|
| 237 | // Retrieve data from DevIL |
---|
| 238 | ilGetDXTCData((unsigned char*)output->getPtr()+offset, imageSize, dxtFormat); |
---|
| 239 | } else |
---|
| 240 | { |
---|
| 241 | LogManager::getSingleton().logMessage( |
---|
| 242 | "Warning: compressed image "+input->getName()+" size mismatch, devilsize="+StringConverter::toString(ilGetDXTCData(NULL, 0, dxtFormat))+" oursize="+ |
---|
| 243 | StringConverter::toString(imageSize)); |
---|
| 244 | } |
---|
| 245 | } |
---|
| 246 | else |
---|
| 247 | { |
---|
| 248 | /// Retrieve data from DevIL |
---|
| 249 | PixelBox dst(width, height, depth, imgData->format, (unsigned char*)output->getPtr()+offset); |
---|
| 250 | ILUtil::toOgre(dst); |
---|
| 251 | } |
---|
| 252 | offset += imageSize; |
---|
| 253 | } |
---|
| 254 | /// Next mip |
---|
| 255 | if(width!=1) width /= 2; |
---|
| 256 | if(height!=1) height /= 2; |
---|
| 257 | if(depth!=1) depth /= 2; |
---|
| 258 | } |
---|
| 259 | |
---|
| 260 | // Restore IL state |
---|
| 261 | ilDisable(IL_ORIGIN_SET); |
---|
| 262 | ilDisable(IL_FORMAT_SET); |
---|
| 263 | |
---|
| 264 | ilDeleteImages( 1, &ImageName ); |
---|
| 265 | |
---|
| 266 | DecodeResult ret; |
---|
| 267 | ret.first = output; |
---|
| 268 | ret.second = CodecDataPtr(imgData); |
---|
| 269 | |
---|
| 270 | |
---|
| 271 | return ret; |
---|
| 272 | } |
---|
| 273 | //--------------------------------------------------------------------- |
---|
| 274 | void ILImageCodec::initialiseIL(void) |
---|
| 275 | { |
---|
| 276 | if( !_is_initialised ) |
---|
| 277 | { |
---|
| 278 | ilInit(); |
---|
| 279 | ilEnable( IL_FILE_OVERWRITE ); |
---|
| 280 | _is_initialised = true; |
---|
| 281 | } |
---|
| 282 | } |
---|
| 283 | //--------------------------------------------------------------------- |
---|
| 284 | String ILImageCodec::getType() const |
---|
| 285 | { |
---|
| 286 | return mType; |
---|
| 287 | } |
---|
| 288 | } |
---|