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