/** ** ** Copyright 2010, The Android Open Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ #ifndef _PIXELFLINGER2_IMAGE_FILE_H_ #define _PIXELFLINGER2_IMAGE_FILE_H_ #include #include #include typedef union { unsigned char channels[4]; unsigned int val; } Pixel; static void SaveBMP(const char * filePath, unsigned * data, unsigned int width, unsigned int height) { FILE * file = fopen(filePath, "wb"); if (!file) printf("SaveMap failed fopen '%s'\n", filePath); fwrite("BM", 2, 1, file); const unsigned int dataOffset = 0x36; const unsigned int dataSize = width * height * 4; const unsigned int fileSize = dataSize + dataOffset; fwrite((const char *)&fileSize, 4, 1, file); fwrite("\0\0\0\0", 4, 1, file); // unused fwrite((const char *)&dataOffset, 4, 1, file); fwrite("\x28\0\0\0", 4, 1, file); // header size from this point fwrite((const char *)&width, 4, 1, file); fwrite((const char *)&height, 4, 1, file); fwrite("\x01\0", 2, 1, file); // 1 color plane fwrite("\x20\0", 2, 1, file); // 32bpp fwrite("\0\0\0\0", 4, 1, file); // BI_RGB no compression fwrite((const char *)&dataSize, 4, 1, file); fwrite("\x13\0\0\0", 4, 1, file); // horz res, 2.835 pixel/meter fwrite("\x13\0\0\0", 4, 1, file); // vert res fwrite("\0\0\0\0", 4, 1, file); // number of colours in palette fwrite("\0\0\0\0", 4, 1, file); // number of important colours, 0 means all are important // for non 32bpp image, need padding at end of each row for 4 byte alignment unsigned x, y; //for (y = 0; y < height; y++) // flip vertically // fwrite((const char *)&data[(height - y - 1) * width], width * 4, 1, file); //fwrite(data, width * height * 4, 1, file); // vertical flip and convert rgba to bgra for (y = 0; y < height; y++) for (x = 0; x < width; x++) { unsigned pixel = data[(height - y - 1) * width + x]; unsigned r = (pixel & 0xff) << 16; unsigned b = (pixel & 0xff0000) >> 16; pixel = (pixel & 0xff00ff00) | r | b; fwrite(&pixel, sizeof(pixel), 1, file); } fclose(file); } #if USE_16BPP_TEXTURE #define TO_16BPP(rgba) ((((rgba) & 0xF8) >> 3) | (((rgba) & 0xFC00) >> 5) | (((rgba) & 0xF80000) >> 8)) #else #define TO_16BPP(rgba) (rgba) #endif static int LoadTGA(const char * filePath, unsigned int * width, unsigned int * height, void ** data) { FILE * file = fopen(filePath, "rb"); if (!file) { printf("LoadTGA failed to open %s \n", filePath); assert(file); return -1; } struct TGAHeader { unsigned char idLength, cMapType; enum TGAType { NoImageData = 0, UncompressedCM = 1, UncompressedRGB = 2, UncompressedBW = 3, RLECM = 9, RLERGB = 10, CompressedBW = 11, CompressedCM = 32, //32 - Compressed color-mapped data, using Huffman, Delta, and runlength encoding. CompressedCM4 = 33 //33 - Compressed color-mapped data, using Huffman, Delta, and runlength encoding. 4-pass quadtree-type process. } type : 8; unsigned short cMapStart/* __attribute__ ((packed))*/; unsigned short cMapLength/* __attribute__ ((packed))*/; unsigned char cMapDepth; unsigned short xOffset/* __attribute__ ((packed))*/; unsigned short yOffset/* __attribute__ ((packed))*/; unsigned short width/* __attribute__ ((packed))*/; unsigned short height/* __attribute__ ((packed))*/; unsigned char bpp; struct { unsigned attribs : 4; unsigned reserved : 1; unsigned origin : 1; enum InterleaveType { None = 0, TwoWay = 1, FourWay = 2, Reserved = 3 } interleave : 2; } __attribute__ ((packed)) imageDescriptor; } __attribute__ ((packed)) header; assert(18 == sizeof(header)); fread(&header, sizeof(header), 1, file); #if USE_16BPP_TEXTURE unsigned short * dest = (unsigned short *)malloc(header.width * header.height * 2); #else unsigned * dest = (unsigned *)malloc(header.width * header.height * 4); #endif *data = dest; *width = header.width; *height = header.height; if (!*data) { fclose(file); return -1; } Pixel pixel; unsigned int i; if (TGAHeader::UncompressedRGB == header.type) { if (24 == header.bpp) { pixel.channels[3] = 255; for (i = 0; i < (unsigned)header.width * header.height; i++) { pixel.channels[2] = fgetc(file); pixel.channels[1] = fgetc(file); pixel.channels[0] = fgetc(file); *dest++ = TO_16BPP(pixel.val); } } else if (32 == header.bpp) { for (i = 0; i < (unsigned)header.width * header.height; i++) { pixel.channels[2] = fgetc(file); pixel.channels[1] = fgetc(file); pixel.channels[0] = fgetc(file); pixel.channels[3] = fgetc(file); *dest++ = TO_16BPP(pixel.val); } //fread(dest, header.width * header.height * 4, 1, file); } } else if (TGAHeader::UncompressedBW == header.type) { if (8 == header.bpp) { for (i = 0; i < (unsigned)header.width * header.height; i++) { pixel.channels[3] = pixel.channels[2] = pixel.channels[1] = pixel.channels[0] = fgetc(file); *dest++ = TO_16BPP(pixel.val); } } else assert(0); } else if (TGAHeader::RLERGB == header.type) { if (24 == header.bpp) { pixel.channels[3] = 255; for (i = 0; i < (unsigned)header.width * header.height;) { unsigned char count = fgetc(file); if (0x80 & count) // repeated run { count = (0x7f & count) + 1; pixel.channels[2] = fgetc(file); pixel.channels[1] = fgetc(file); pixel.channels[0] = fgetc(file); for (unsigned j = 0; j < count; j++) *dest++ = TO_16BPP(pixel.val); } else // literal run { count += 1; for (unsigned j = 0; j < count; j++) { pixel.channels[2] = fgetc(file); pixel.channels[1] = fgetc(file); pixel.channels[0] = fgetc(file); *dest++ = TO_16BPP(pixel.val); } } i += count; } } else if (32 == header.bpp) { for (i = 0; i < (unsigned)header.width * header.height;) { unsigned char count = fgetc(file); if (0x80 & count) // repeated run { count = (0x7f & count) + 1; pixel.channels[2] = fgetc(file); pixel.channels[1] = fgetc(file); pixel.channels[0] = fgetc(file); pixel.channels[3] = fgetc(file); for (unsigned j = 0; j < count; j++) *dest++ = TO_16BPP(pixel.val); } else // literal run { count += 1; for (unsigned j = 0; j < count; j++) { pixel.channels[2] = fgetc(file); pixel.channels[1] = fgetc(file); pixel.channels[0] = fgetc(file); pixel.channels[3] = fgetc(file); *dest++ = TO_16BPP(pixel.val); } } i += count; } } else assert(0); } else assert(0); fclose(file); return -1; }; static unsigned GenerateMipmaps(void ** data, const unsigned width, const unsigned height) { unsigned levels = 1; unsigned dim = (width > height ? width : height) >> 1; unsigned size = 0, w = width, h = height; while (dim) { levels++; w = (w + 1) / 2; h = (h + 1) / 2; size += w * h; dim >>= 1; } Pixel * buffer = (Pixel *)malloc(size * sizeof(*buffer)); Pixel * previous = (Pixel *)data[0]; w = width; h = height; for (unsigned i = 1; i < levels; i++) { const unsigned cw = (w + 1) / 2, ch = (h + 1) / 2; unsigned * current = (unsigned *)(data[i] = buffer); for (unsigned y = 0; y < ch; y++) for (unsigned x = 0; x < cw; x++) { unsigned channels[4] = {0,0,0,0}; for (unsigned yy = 0; yy < 2; yy++) for (unsigned xx = 0; xx < 2; xx++) { unsigned s = x * 2 + xx; unsigned t = y * 2 + yy; s = s < w - 1 ? s : w - 1; t = t < h - 1 ? t : h - 1; const Pixel * p = previous + t * w + s; for (unsigned i = 0; i < 4; i++) channels[i] += p->channels[i]; } for (unsigned i = 0; i < 4; i++) channels[i] /= 4; current[y * cw + x] = channels[0] | (channels[1] << 8) | (channels[2] << 16) | (channels[3] << 24); } buffer += cw * ch; w = cw; h = ch; previous = (Pixel *)current; } return levels; } #endif // _PIXELFLINGER2_IMAGE_FILE_H_