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 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 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 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