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 | } |
---|