1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4
5 #include "CImageWriterTGA.h"
6
7 #ifdef _IRR_COMPILE_WITH_TGA_WRITER_
8
9 #include "CImageLoaderTGA.h"
10 #include "IWriteFile.h"
11 #include "CColorConverter.h"
12 #include "irrString.h"
13
14 namespace irr
15 {
16 namespace video
17 {
18
createImageWriterTGA()19 IImageWriter* createImageWriterTGA()
20 {
21 return new CImageWriterTGA;
22 }
23
CImageWriterTGA()24 CImageWriterTGA::CImageWriterTGA()
25 {
26 #ifdef _DEBUG
27 setDebugName("CImageWriterTGA");
28 #endif
29 }
30
isAWriteableFileExtension(const io::path & filename) const31 bool CImageWriterTGA::isAWriteableFileExtension(const io::path& filename) const
32 {
33 return core::hasFileExtension ( filename, "tga" );
34 }
35
writeImage(io::IWriteFile * file,IImage * image,u32 param) const36 bool CImageWriterTGA::writeImage(io::IWriteFile *file, IImage *image,u32 param) const
37 {
38 STGAHeader imageHeader;
39 imageHeader.IdLength = 0;
40 imageHeader.ColorMapType = 0;
41 imageHeader.ImageType = 2;
42 imageHeader.FirstEntryIndex[0] = 0;
43 imageHeader.FirstEntryIndex[1] = 0;
44 imageHeader.ColorMapLength = 0;
45 imageHeader.ColorMapEntrySize = 0;
46 imageHeader.XOrigin[0] = 0;
47 imageHeader.XOrigin[1] = 0;
48 imageHeader.YOrigin[0] = 0;
49 imageHeader.YOrigin[1] = 0;
50 imageHeader.ImageWidth = image->getDimension().Width;
51 imageHeader.ImageHeight = image->getDimension().Height;
52
53 // top left of image is the top. the image loader needs to
54 // be fixed to only swap/flip
55 imageHeader.ImageDescriptor = (1 << 5);
56
57 // chances are good we'll need to swizzle data, so i'm going
58 // to convert and write one scan line at a time. it's also
59 // a bit cleaner this way
60 void (*CColorConverter_convertFORMATtoFORMAT)(const void*, s32, void*) = 0;
61 switch(image->getColorFormat())
62 {
63 case ECF_A8R8G8B8:
64 CColorConverter_convertFORMATtoFORMAT
65 = CColorConverter::convert_A8R8G8B8toA8R8G8B8;
66 imageHeader.PixelDepth = 32;
67 imageHeader.ImageDescriptor |= 8;
68 break;
69 case ECF_A1R5G5B5:
70 CColorConverter_convertFORMATtoFORMAT
71 = CColorConverter::convert_A1R5G5B5toA1R5G5B5;
72 imageHeader.PixelDepth = 16;
73 imageHeader.ImageDescriptor |= 1;
74 break;
75 case ECF_R5G6B5:
76 CColorConverter_convertFORMATtoFORMAT
77 = CColorConverter::convert_R5G6B5toA1R5G5B5;
78 imageHeader.PixelDepth = 16;
79 imageHeader.ImageDescriptor |= 1;
80 break;
81 case ECF_R8G8B8:
82 CColorConverter_convertFORMATtoFORMAT
83 = CColorConverter::convert_R8G8B8toR8G8B8;
84 imageHeader.PixelDepth = 24;
85 imageHeader.ImageDescriptor |= 0;
86 break;
87 #ifndef _DEBUG
88 default:
89 break;
90 #endif
91 }
92
93 // couldn't find a color converter
94 if (!CColorConverter_convertFORMATtoFORMAT)
95 return false;
96
97 if (file->write(&imageHeader, sizeof(imageHeader)) != sizeof(imageHeader))
98 return false;
99
100 u8* scan_lines = (u8*)image->lock();
101 if (!scan_lines)
102 return false;
103
104 // size of one pixel in bytes
105 u32 pixel_size = image->getBytesPerPixel();
106
107 // length of one row of the source image in bytes
108 u32 row_stride = (pixel_size * imageHeader.ImageWidth);
109
110 // length of one output row in bytes
111 s32 row_size = ((imageHeader.PixelDepth / 8) * imageHeader.ImageWidth);
112
113 // allocate a row do translate data into
114 u8* row_pointer = new u8[row_size];
115
116 u32 y;
117 for (y = 0; y < imageHeader.ImageHeight; ++y)
118 {
119 // source, length [pixels], destination
120 if (image->getColorFormat()==ECF_R8G8B8)
121 CColorConverter::convert24BitTo24Bit(&scan_lines[y * row_stride], row_pointer, imageHeader.ImageWidth, 1, 0, 0, true);
122 else
123 CColorConverter_convertFORMATtoFORMAT(&scan_lines[y * row_stride], imageHeader.ImageWidth, row_pointer);
124 if (file->write(row_pointer, row_size) != row_size)
125 break;
126 }
127
128 delete [] row_pointer;
129
130 image->unlock();
131
132 STGAFooter imageFooter;
133 imageFooter.ExtensionOffset = 0;
134 imageFooter.DeveloperOffset = 0;
135 strncpy(imageFooter.Signature, "TRUEVISION-XFILE.", 18);
136
137 if (file->write(&imageFooter, sizeof(imageFooter)) < (s32)sizeof(imageFooter))
138 return false;
139
140 return imageHeader.ImageHeight <= y;
141 }
142
143 } // namespace video
144 } // namespace irr
145
146 #endif
147
148