]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CImageLoaderTGA.cpp
Unify & improve log messages
[irrlicht.git] / source / Irrlicht / CImageLoaderTGA.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "CImageLoaderTGA.h"\r
6 \r
7 #include "IReadFile.h"\r
8 #include "os.h"\r
9 #include "CColorConverter.h"\r
10 #include "CImage.h"\r
11 #include "irrString.h"\r
12 \r
13 \r
14 namespace irr\r
15 {\r
16 namespace video\r
17 {\r
18 \r
19 \r
20 //! returns true if the file maybe is able to be loaded by this class\r
21 //! based on the file extension (e.g. ".tga")\r
22 bool CImageLoaderTGA::isALoadableFileExtension(const io::path& filename) const\r
23 {\r
24         return core::hasFileExtension ( filename, "tga" );\r
25 }\r
26 \r
27 \r
28 //! loads a compressed tga.\r
29 u8 *CImageLoaderTGA::loadCompressedImage(io::IReadFile *file, const STGAHeader& header) const\r
30 {\r
31         // This was written and sent in by Jon Pry, thank you very much!\r
32         // I only changed the formatting a little bit.\r
33 \r
34         s32 bytesPerPixel = header.PixelDepth/8;\r
35         s32 imageSize =  header.ImageHeight * header.ImageWidth * bytesPerPixel;\r
36         u8* data = new u8[imageSize];\r
37         s32 currentByte = 0;\r
38 \r
39         while(currentByte < imageSize)\r
40         {\r
41                 u8 chunkheader = 0;\r
42                 file->read(&chunkheader, sizeof(u8)); // Read The Chunk's Header\r
43 \r
44                 if(chunkheader < 128) // If The Chunk Is A 'RAW' Chunk\r
45                 {\r
46                         chunkheader++; // Add 1 To The Value To Get Total Number Of Raw Pixels\r
47 \r
48                         file->read(&data[currentByte], bytesPerPixel * chunkheader);\r
49                         currentByte += bytesPerPixel * chunkheader;\r
50                 }\r
51                 else\r
52                 {\r
53                         // thnx to neojzs for some fixes with this code\r
54 \r
55                         // If It's An RLE Header\r
56                         chunkheader -= 127; // Subtract 127 To Get Rid Of The ID Bit\r
57 \r
58                         s32 dataOffset = currentByte;\r
59                         file->read(&data[dataOffset], bytesPerPixel);\r
60 \r
61                         currentByte += bytesPerPixel;\r
62 \r
63                         for(s32 counter = 1; counter < chunkheader; counter++)\r
64                         {\r
65                                 for(s32 elementCounter=0; elementCounter < bytesPerPixel; elementCounter++)\r
66                                         data[currentByte + elementCounter] = data[dataOffset + elementCounter];\r
67 \r
68                                 currentByte += bytesPerPixel;\r
69                         }\r
70                 }\r
71         }\r
72 \r
73         return data;\r
74 }\r
75 \r
76 \r
77 \r
78 //! returns true if the file maybe is able to be loaded by this class\r
79 bool CImageLoaderTGA::isALoadableFileFormat(io::IReadFile* file) const\r
80 {\r
81         if (!file)\r
82                 return false;\r
83 \r
84         STGAFooter footer;\r
85         memset(&footer, 0, sizeof(STGAFooter));\r
86         file->seek(file->getSize()-sizeof(STGAFooter));\r
87         file->read(&footer, sizeof(STGAFooter));\r
88         return (!strcmp(footer.Signature,"TRUEVISION-XFILE.")); // very old tgas are refused.\r
89 }\r
90 \r
91 \r
92 \r
93 //! creates a surface from the file\r
94 IImage* CImageLoaderTGA::loadImage(io::IReadFile* file) const\r
95 {\r
96         STGAHeader header;\r
97         u32 *palette = 0;\r
98 \r
99         file->read(&header, sizeof(STGAHeader));\r
100 \r
101 #ifdef __BIG_ENDIAN__\r
102         header.ColorMapLength = os::Byteswap::byteswap(header.ColorMapLength);\r
103         header.ImageWidth = os::Byteswap::byteswap(header.ImageWidth);\r
104         header.ImageHeight = os::Byteswap::byteswap(header.ImageHeight);\r
105 #endif\r
106 \r
107         if (!checkImageDimensions(header.ImageWidth, header.ImageHeight))\r
108         {\r
109                 os::Printer::log("Image dimensions too large in file", file->getFileName(), ELL_ERROR);\r
110                 return 0;\r
111         }\r
112 \r
113         // skip image identification field\r
114         if (header.IdLength)\r
115                 file->seek(header.IdLength, true);\r
116 \r
117         if (header.ColorMapType)\r
118         {\r
119                 // create 32 bit palette\r
120                 palette = new u32[ header.ColorMapLength];\r
121 \r
122                 // read color map\r
123                 u8 * colorMap = new u8[header.ColorMapEntrySize/8 * header.ColorMapLength];\r
124                 file->read(colorMap,header.ColorMapEntrySize/8 * header.ColorMapLength);\r
125 \r
126                 // convert to 32-bit palette\r
127                 switch ( header.ColorMapEntrySize )\r
128                 {\r
129                         case 16:\r
130                                 CColorConverter::convert_A1R5G5B5toA8R8G8B8(colorMap, header.ColorMapLength, palette);\r
131                                 break;\r
132                         case 24:\r
133                                 CColorConverter::convert_B8G8R8toA8R8G8B8(colorMap, header.ColorMapLength, palette);\r
134                                 break;\r
135                         case 32:\r
136                                 CColorConverter::convert_B8G8R8A8toA8R8G8B8(colorMap, header.ColorMapLength, palette);\r
137                                 break;\r
138                 }\r
139                 delete [] colorMap;\r
140         }\r
141 \r
142         // read image\r
143 \r
144         u8* data = 0;\r
145 \r
146         if (    header.ImageType == 1 || // Uncompressed, color-mapped images.\r
147                         header.ImageType == 2 || // Uncompressed, RGB images\r
148                         header.ImageType == 3 // Uncompressed, black and white images\r
149                 )\r
150         {\r
151                 const s32 imageSize = header.ImageHeight * header.ImageWidth * header.PixelDepth/8;\r
152                 data = new u8[imageSize];\r
153                 file->read(data, imageSize);\r
154         }\r
155         else\r
156         if(header.ImageType == 10)\r
157         {\r
158                 // Runlength encoded RGB images\r
159                 data = loadCompressedImage(file, header);\r
160         }\r
161         else\r
162         {\r
163                 os::Printer::log("Unsupported TGA file type", file->getFileName(), ELL_ERROR);\r
164                 delete [] palette;\r
165                 return 0;\r
166         }\r
167 \r
168         IImage* image = 0;\r
169 \r
170         switch(header.PixelDepth)\r
171         {\r
172         case 8:\r
173                 {\r
174                         if (header.ImageType==3) // grey image\r
175                         {\r
176                                 image = new CImage(ECF_R8G8B8,\r
177                                         core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));\r
178                                 if (image)\r
179                                         CColorConverter::convert8BitTo24Bit((u8*)data,\r
180                                                 (u8*)image->getData(),\r
181                                                 header.ImageWidth,header.ImageHeight,\r
182                                                 0, 0, (header.ImageDescriptor&0x20)==0);\r
183                         }\r
184                         else\r
185                         {\r
186                                 image = new CImage(ECF_A1R5G5B5,\r
187                                         core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));\r
188                                 if (image)\r
189                                         CColorConverter::convert8BitTo16Bit((u8*)data,\r
190                                                 (s16*)image->getData(),\r
191                                                 header.ImageWidth,header.ImageHeight,\r
192                                                 (s32*) palette, 0,\r
193                                                 (header.ImageDescriptor&0x20)==0);\r
194                         }\r
195                 }\r
196                 break;\r
197         case 16:\r
198                 image = new CImage(ECF_A1R5G5B5,\r
199                         core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));\r
200                 if (image)\r
201                         CColorConverter::convert16BitTo16Bit((s16*)data,\r
202                                 (s16*)image->getData(), header.ImageWidth,      header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0);\r
203                 break;\r
204         case 24:\r
205                         image = new CImage(ECF_R8G8B8,\r
206                                 core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));\r
207                         if (image)\r
208                                 CColorConverter::convert24BitTo24Bit(\r
209                                         (u8*)data, (u8*)image->getData(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0, true);\r
210                 break;\r
211         case 32:\r
212                         image = new CImage(ECF_A8R8G8B8,\r
213                                 core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));\r
214                         if (image)\r
215                                 CColorConverter::convert32BitTo32Bit((s32*)data,\r
216                                         (s32*)image->getData(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0);\r
217                 break;\r
218         default:\r
219                 os::Printer::log("Unsupported TGA format", file->getFileName(), ELL_ERROR);\r
220                 break;\r
221         }\r
222 \r
223         delete [] data;\r
224         delete [] palette;\r
225 \r
226         return image;\r
227 }\r
228 \r
229 \r
230 //! creates a loader which is able to load tgas\r
231 IImageLoader* createImageLoaderTGA()\r
232 {\r
233         return new CImageLoaderTGA();\r
234 }\r
235 \r
236 \r
237 } // end namespace video\r
238 } // end namespace irr\r