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