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