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
5 #include "CImageLoaderTGA.h"
\r
7 #include "IReadFile.h"
\r
9 #include "CColorConverter.h"
\r
11 #include "irrString.h"
\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
24 return core::hasFileExtension ( filename, "tga" );
\r
28 //! loads a compressed tga.
\r
29 u8 *CImageLoaderTGA::loadCompressedImage(io::IReadFile *file, const STGAHeader& header) const
\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
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
39 while(currentByte < imageSize)
\r
42 file->read(&chunkheader, sizeof(u8)); // Read The Chunk's Header
\r
44 if(chunkheader < 128) // If The Chunk Is A 'RAW' Chunk
\r
46 chunkheader++; // Add 1 To The Value To Get Total Number Of Raw Pixels
\r
48 file->read(&data[currentByte], bytesPerPixel * chunkheader);
\r
49 currentByte += bytesPerPixel * chunkheader;
\r
53 // thnx to neojzs for some fixes with this code
\r
55 // If It's An RLE Header
\r
56 chunkheader -= 127; // Subtract 127 To Get Rid Of The ID Bit
\r
58 s32 dataOffset = currentByte;
\r
59 file->read(&data[dataOffset], bytesPerPixel);
\r
61 currentByte += bytesPerPixel;
\r
63 for(s32 counter = 1; counter < chunkheader; counter++)
\r
65 for(s32 elementCounter=0; elementCounter < bytesPerPixel; elementCounter++)
\r
66 data[currentByte + elementCounter] = data[dataOffset + elementCounter];
\r
68 currentByte += bytesPerPixel;
\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
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
93 //! creates a surface from the file
\r
94 IImage* CImageLoaderTGA::loadImage(io::IReadFile* file) const
\r
99 file->read(&header, sizeof(STGAHeader));
\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
107 if (!checkImageDimensions(header.ImageWidth, header.ImageHeight))
\r
109 os::Printer::log("Image dimensions too large in file", file->getFileName(), ELL_ERROR);
\r
113 // skip image identification field
\r
114 if (header.IdLength)
\r
115 file->seek(header.IdLength, true);
\r
117 if (header.ColorMapType)
\r
119 // create 32 bit palette
\r
120 palette = new u32[ header.ColorMapLength];
\r
123 u8 * colorMap = new u8[header.ColorMapEntrySize/8 * header.ColorMapLength];
\r
124 file->read(colorMap,header.ColorMapEntrySize/8 * header.ColorMapLength);
\r
126 // convert to 32-bit palette
\r
127 switch ( header.ColorMapEntrySize )
\r
130 CColorConverter::convert_A1R5G5B5toA8R8G8B8(colorMap, header.ColorMapLength, palette);
\r
133 CColorConverter::convert_B8G8R8toA8R8G8B8(colorMap, header.ColorMapLength, palette);
\r
136 CColorConverter::convert_B8G8R8A8toA8R8G8B8(colorMap, header.ColorMapLength, palette);
\r
139 delete [] colorMap;
\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
151 const s32 imageSize = header.ImageHeight * header.ImageWidth * header.PixelDepth/8;
\r
152 data = new u8[imageSize];
\r
153 file->read(data, imageSize);
\r
156 if(header.ImageType == 10)
\r
158 // Runlength encoded RGB images
\r
159 data = loadCompressedImage(file, header);
\r
163 os::Printer::log("Unsupported TGA file type", file->getFileName(), ELL_ERROR);
\r
170 switch(header.PixelDepth)
\r
174 if (header.ImageType==3) // grey image
\r
176 image = new CImage(ECF_R8G8B8,
\r
177 core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));
\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
186 image = new CImage(ECF_A1R5G5B5,
\r
187 core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));
\r
189 CColorConverter::convert8BitTo16Bit((u8*)data,
\r
190 (s16*)image->getData(),
\r
191 header.ImageWidth,header.ImageHeight,
\r
193 (header.ImageDescriptor&0x20)==0);
\r
198 image = new CImage(ECF_A1R5G5B5,
\r
199 core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));
\r
201 CColorConverter::convert16BitTo16Bit((s16*)data,
\r
202 (s16*)image->getData(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0);
\r
205 image = new CImage(ECF_R8G8B8,
\r
206 core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));
\r
208 CColorConverter::convert24BitTo24Bit(
\r
209 (u8*)data, (u8*)image->getData(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0, true);
\r
212 image = new CImage(ECF_A8R8G8B8,
\r
213 core::dimension2d<u32>(header.ImageWidth, header.ImageHeight));
\r
215 CColorConverter::convert32BitTo32Bit((s32*)data,
\r
216 (s32*)image->getData(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0);
\r
219 os::Printer::log("Unsupported TGA format", file->getFileName(), ELL_ERROR);
\r
230 //! creates a loader which is able to load tgas
\r
231 IImageLoader* createImageLoaderTGA()
\r
233 return new CImageLoaderTGA();
\r
237 } // end namespace video
\r
238 } // end namespace irr
\r