• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  **
3  ** Copyright 2010, The Android Open Source Project
4  **
5  ** Licensed under the Apache License, Version 2.0 (the "License");
6  ** you may not use this file except in compliance with the License.
7  ** You may obtain a copy of the License at
8  **
9  **     http://www.apache.org/licenses/LICENSE-2.0
10  **
11  ** Unless required by applicable law or agreed to in writing, software
12  ** distributed under the License is distributed on an "AS IS" BASIS,
13  ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  ** See the License for the specific language governing permissions and
15  ** limitations under the License.
16  */
17 
18 #ifndef _PIXELFLINGER2_IMAGE_FILE_H_
19 #define _PIXELFLINGER2_IMAGE_FILE_H_
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <assert.h>
24 
25 typedef union {	unsigned char channels[4]; unsigned int val; } Pixel;
26 
SaveBMP(const char * filePath,unsigned * data,unsigned int width,unsigned int height)27 static void SaveBMP(const char * filePath, unsigned * data, unsigned int width, unsigned int height)
28 {
29 	FILE * file = fopen(filePath, "wb");
30     if (!file)
31 		printf("SaveMap failed fopen '%s'\n", filePath);
32 
33 	fwrite("BM", 2, 1, file);
34 	const unsigned int dataOffset = 0x36;
35 	const unsigned int dataSize = width * height * 4;
36 	const unsigned int fileSize = dataSize + dataOffset;
37 	fwrite((const char *)&fileSize, 4, 1, file);
38 	fwrite("\0\0\0\0", 4, 1, file); // unused
39 	fwrite((const char *)&dataOffset, 4, 1, file);
40 	fwrite("\x28\0\0\0", 4, 1, file); // header size from this point
41 	fwrite((const char *)&width, 4, 1, file);
42 	fwrite((const char *)&height, 4, 1, file);
43 	fwrite("\x01\0", 2, 1, file); // 1 color plane
44 	fwrite("\x20\0", 2, 1, file); // 32bpp
45 	fwrite("\0\0\0\0", 4, 1, file); // BI_RGB no compression
46 	fwrite((const char *)&dataSize, 4, 1, file);
47 	fwrite("\x13\0\0\0", 4, 1, file); // horz res, 2.835 pixel/meter
48 	fwrite("\x13\0\0\0", 4, 1, file); // vert res
49 	fwrite("\0\0\0\0", 4, 1, file); // number of colours in palette
50 	fwrite("\0\0\0\0", 4, 1, file); // number of important colours, 0 means all are important
51 
52 	// for non 32bpp image, need padding at end of each row for 4 byte alignment
53 	unsigned x, y;
54 	//for (y = 0; y < height; y++) // flip vertically
55 	//	fwrite((const char *)&data[(height - y - 1) * width], width * 4, 1, file);
56 
57 	//fwrite(data, width * height * 4, 1, file);
58 
59     // vertical flip and convert rgba to bgra
60     for (y = 0; y < height; y++)
61         for (x = 0; x < width; x++)
62         {
63             unsigned pixel = data[(height - y - 1) * width + x];
64             unsigned r = (pixel & 0xff) << 16;
65             unsigned b = (pixel & 0xff0000) >> 16;
66             pixel = (pixel & 0xff00ff00) | r | b;
67             fwrite(&pixel, sizeof(pixel), 1, file);
68         }
69 
70 	fclose(file);
71 }
72 
73 #if USE_16BPP_TEXTURE
74 #define TO_16BPP(rgba) ((((rgba) & 0xF8) >> 3) | (((rgba) & 0xFC00) >> 5) | (((rgba) & 0xF80000) >> 8))
75 #else
76 #define TO_16BPP(rgba) (rgba)
77 #endif
78 
LoadTGA(const char * filePath,unsigned int * width,unsigned int * height,void ** data)79 static int LoadTGA(const char * filePath, unsigned int * width, unsigned int * height, void ** data)
80 {
81 	FILE * file = fopen(filePath, "rb");
82 	if (!file)
83 	{
84 		printf("LoadTGA failed to open %s \n", filePath);
85 		assert(file);
86 		return -1;
87 	}
88 
89 	struct TGAHeader
90 	{
91 		unsigned char idLength, cMapType;
92 		enum TGAType { NoImageData = 0, UncompressedCM = 1,
93 			UncompressedRGB = 2, UncompressedBW = 3, RLECM = 9,
94 			RLERGB = 10, CompressedBW = 11,
95 			CompressedCM = 32, //32  -  Compressed color-mapped data, using Huffman, Delta, and runlength encoding.
96 			CompressedCM4 = 33 //33  -  Compressed color-mapped data, using Huffman, Delta, and runlength encoding.  4-pass quadtree-type process.
97 		} type : 8;
98         unsigned short cMapStart/* __attribute__ ((packed))*/;
99         unsigned short cMapLength/* __attribute__ ((packed))*/;
100 		unsigned char cMapDepth;
101         unsigned short xOffset/* __attribute__ ((packed))*/;
102         unsigned short yOffset/* __attribute__ ((packed))*/;
103 		unsigned short width/* __attribute__ ((packed))*/;
104         unsigned short height/* __attribute__ ((packed))*/;
105 		unsigned char bpp;
106         struct {
107             unsigned attribs : 4;
108             unsigned reserved : 1;
109             unsigned origin : 1;
110             enum InterleaveType { None = 0, TwoWay = 1, FourWay = 2, Reserved = 3 } interleave : 2;
111         } __attribute__ ((packed)) imageDescriptor;
112 	} __attribute__ ((packed)) header;
113 
114     assert(18 == sizeof(header));
115     fread(&header, sizeof(header), 1, file);
116 
117 #if USE_16BPP_TEXTURE
118     unsigned short * dest = (unsigned short *)malloc(header.width * header.height * 2);
119 #else
120     unsigned * dest = (unsigned *)malloc(header.width * header.height * 4);
121 #endif
122 
123 	*data = dest;
124 	*width = header.width;
125 	*height = header.height;
126 
127 	if (!*data)
128     {
129         fclose(file);
130 		return -1;
131 	}
132 
133     Pixel pixel;
134 	unsigned int i;
135 
136 	if (TGAHeader::UncompressedRGB == header.type)
137 	{
138 		if (24 == header.bpp)
139 		{
140             pixel.channels[3] = 255;
141             for (i = 0; i < (unsigned)header.width * header.height; i++)
142 			{
143 				pixel.channels[2] = fgetc(file);
144                 pixel.channels[1] = fgetc(file);
145                 pixel.channels[0] = fgetc(file);
146 				*dest++ = TO_16BPP(pixel.val);
147 			}
148 		}
149 		else if (32 == header.bpp)
150         {
151             for (i = 0; i < (unsigned)header.width * header.height; i++)
152             {
153                 pixel.channels[2] = fgetc(file);
154                 pixel.channels[1] = fgetc(file);
155                 pixel.channels[0] = fgetc(file);
156                 pixel.channels[3] = fgetc(file);
157                 *dest++ = TO_16BPP(pixel.val);
158             }
159 			//fread(dest, header.width * header.height * 4, 1, file);
160         }
161 	}
162 	else if (TGAHeader::UncompressedBW == header.type)
163 	{
164 		if (8 == header.bpp)
165 		{
166 			for (i = 0; i < (unsigned)header.width * header.height; i++)
167 			{
168 				pixel.channels[3] = pixel.channels[2] =
169 				pixel.channels[1] = pixel.channels[0] = fgetc(file);
170 				*dest++ = TO_16BPP(pixel.val);
171 			}
172 		}
173 		else
174 			assert(0);
175 	}
176     else if (TGAHeader::RLERGB == header.type)
177     {
178         if (24 == header.bpp)
179         {
180             pixel.channels[3] = 255;
181             for (i = 0; i < (unsigned)header.width * header.height;)
182             {
183                 unsigned char count = fgetc(file);
184                 if (0x80 & count) // repeated run
185                 {
186                     count = (0x7f & count) + 1;
187                     pixel.channels[2] = fgetc(file);
188                     pixel.channels[1] = fgetc(file);
189                     pixel.channels[0] = fgetc(file);
190                     for (unsigned j = 0; j < count; j++)
191                         *dest++ = TO_16BPP(pixel.val);
192                 }
193                 else // literal run
194                 {
195                     count += 1;
196                     for (unsigned j = 0; j < count; j++)
197                     {
198                         pixel.channels[2] = fgetc(file);
199                         pixel.channels[1] = fgetc(file);
200                         pixel.channels[0] = fgetc(file);
201                         *dest++ = TO_16BPP(pixel.val);
202                     }
203                 }
204                 i += count;
205             }
206         }
207         else if (32 == header.bpp)
208         {
209             for (i = 0; i < (unsigned)header.width * header.height;)
210             {
211                 unsigned char count = fgetc(file);
212                 if (0x80 & count) // repeated run
213                 {
214                     count = (0x7f & count) + 1;
215                     pixel.channels[2] = fgetc(file);
216                     pixel.channels[1] = fgetc(file);
217                     pixel.channels[0] = fgetc(file);
218                     pixel.channels[3] = fgetc(file);
219                     for (unsigned j = 0; j < count; j++)
220                         *dest++ = TO_16BPP(pixel.val);
221                 }
222                 else // literal run
223                 {
224                     count += 1;
225                     for (unsigned j = 0; j < count; j++)
226                     {
227                         pixel.channels[2] = fgetc(file);
228                         pixel.channels[1] = fgetc(file);
229                         pixel.channels[0] = fgetc(file);
230                         pixel.channels[3] = fgetc(file);
231                         *dest++ = TO_16BPP(pixel.val);
232                     }
233                 }
234                 i += count;
235             }
236 
237         }
238         else
239             assert(0);
240     }
241 	else
242 		assert(0);
243 
244 	fclose(file);
245 
246 	return -1;
247 };
248 
GenerateMipmaps(void ** data,const unsigned width,const unsigned height)249 static unsigned GenerateMipmaps(void ** data, const unsigned width, const unsigned height)
250 {
251     unsigned levels = 1;
252     unsigned dim = (width > height ? width : height) >> 1;
253     unsigned size = 0, w = width, h = height;
254     while (dim)
255     {
256         levels++;
257         w = (w + 1) / 2;
258         h = (h + 1) / 2;
259         size += w * h;
260         dim >>= 1;
261     }
262     Pixel * buffer = (Pixel *)malloc(size * sizeof(*buffer));
263     Pixel * previous = (Pixel *)data[0];
264     w = width; h = height;
265     for (unsigned i = 1; i < levels; i++)
266     {
267         const unsigned cw = (w + 1) / 2, ch = (h + 1) / 2;
268         unsigned * current = (unsigned *)(data[i] = buffer);
269         for (unsigned y = 0; y < ch; y++)
270             for (unsigned x = 0; x < cw; x++)
271             {
272                 unsigned channels[4] = {0,0,0,0};
273                 for (unsigned yy = 0; yy < 2; yy++)
274                     for (unsigned xx = 0; xx < 2; xx++)
275                     {
276                         unsigned s = x * 2 + xx;
277                         unsigned t = y * 2 + yy;
278                         s = s < w - 1 ? s : w - 1;
279                         t = t < h - 1 ? t : h - 1;
280                         const Pixel * p = previous + t * w + s;
281                         for (unsigned i = 0; i < 4; i++)
282                             channels[i] += p->channels[i];
283                     }
284                 for (unsigned i = 0; i < 4; i++)
285                     channels[i] /= 4;
286                 current[y * cw + x] = channels[0] | (channels[1] << 8) |
287                 (channels[2] << 16) | (channels[3] << 24);
288 
289             }
290 
291 
292         buffer += cw * ch;
293         w = cw;
294         h = ch;
295         previous = (Pixel *)current;
296     }
297 
298     return levels;
299 }
300 
301 #endif // _PIXELFLINGER2_IMAGE_FILE_H_
302 
303