Home | History | Annotate | Download | only in test
      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