//// etcpack v2.74 //// //// NO WARRANTY //// //// BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE THE PROGRAM IS PROVIDED //// "AS IS". ERICSSON MAKES NO REPRESENTATIONS OF ANY KIND, EXTENDS NO //// WARRANTIES OR CONDITIONS OF ANY KIND; EITHER EXPRESS, IMPLIED OR //// STATUTORY; INCLUDING, BUT NOT LIMITED TO, EXPRESS, IMPLIED OR //// STATUTORY WARRANTIES OR CONDITIONS OF TITLE, MERCHANTABILITY, //// SATISFACTORY QUALITY, SUITABILITY AND FITNESS FOR A PARTICULAR //// PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE //// PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME //// THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. ERICSSON //// MAKES NO WARRANTY THAT THE MANUFACTURE, SALE, OFFERING FOR SALE, //// DISTRIBUTION, LEASE, USE OR IMPORTATION UNDER THE LICENSE WILL BE FREE //// FROM INFRINGEMENT OF PATENTS, COPYRIGHTS OR OTHER INTELLECTUAL //// PROPERTY RIGHTS OF OTHERS, AND THE VALIDITY OF THE LICENSE IS SUBJECT //// TO YOUR SOLE RESPONSIBILITY TO MAKE SUCH DETERMINATION AND ACQUIRE //// SUCH LICENSES AS MAY BE NECESSARY WITH RESPECT TO PATENTS, COPYRIGHT //// AND OTHER INTELLECTUAL PROPERTY OF THIRD PARTIES. //// //// FOR THE AVOIDANCE OF DOUBT THE PROGRAM (I) IS NOT LICENSED FOR; (II) //// IS NOT DESIGNED FOR OR INTENDED FOR; AND (III) MAY NOT BE USED FOR; //// ANY MISSION CRITICAL APPLICATIONS SUCH AS, BUT NOT LIMITED TO //// OPERATION OF NUCLEAR OR HEALTHCARE COMPUTER SYSTEMS AND/OR NETWORKS, //// AIRCRAFT OR TRAIN CONTROL AND/OR COMMUNICATION SYSTEMS OR ANY OTHER //// COMPUTER SYSTEMS AND/OR NETWORKS OR CONTROL AND/OR COMMUNICATION //// SYSTEMS ALL IN WHICH CASE THE FAILURE OF THE PROGRAM COULD LEAD TO //// DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL, MATERIAL OR ENVIRONMENTAL //// DAMAGE. YOUR RIGHTS UNDER THIS LICENSE WILL TERMINATE AUTOMATICALLY //// AND IMMEDIATELY WITHOUT NOTICE IF YOU FAIL TO COMPLY WITH THIS //// PARAGRAPH. //// //// IN NO EVENT WILL ERICSSON, BE LIABLE FOR ANY DAMAGES WHATSOEVER, //// INCLUDING BUT NOT LIMITED TO PERSONAL INJURY, ANY GENERAL, SPECIAL, //// INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN //// CONNECTION WITH THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT //// NOT LIMITED TO LOSS OF PROFITS, BUSINESS INTERUPTIONS, OR ANY OTHER //// COMMERCIAL DAMAGES OR LOSSES, LOSS OF DATA OR DATA BEING RENDERED //// INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF //// THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) REGARDLESS OF THE //// THEORY OF LIABILITY (CONTRACT, TORT OR OTHERWISE), EVEN IF SUCH HOLDER //// OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. //// //// (C) Ericsson AB 2005-2013. All Rights Reserved. //// #include #include #include #include #include #include #include "image.h" // Typedefs typedef unsigned char uint8; typedef unsigned short uint16; typedef short int16; // Functions needed for decrompession ---- in etcdec.cxx void read_big_endian_2byte_word(unsigned short *blockadr, FILE *f); void read_big_endian_4byte_word(unsigned int *blockadr, FILE *f); void unstuff57bits(unsigned int planar_word1, unsigned int planar_word2, unsigned int &planar57_word1, unsigned int &planar57_word2); void unstuff59bits(unsigned int thumbT_word1, unsigned int thumbT_word2, unsigned int &thumbT59_word1, unsigned int &thumbT59_word2); void unstuff58bits(unsigned int thumbH_word1, unsigned int thumbH_word2, unsigned int &thumbH58_word1, unsigned int &thumbH58_word2); void decompressColor(int R_B, int G_B, int B_B, uint8 (colors_RGB444)[2][3], uint8 (colors)[2][3]); void calculatePaintColors59T(uint8 d, uint8 p, uint8 (colors)[2][3], uint8 (possible_colors)[4][3]); void calculatePaintColors58H(uint8 d, uint8 p, uint8 (colors)[2][3], uint8 (possible_colors)[4][3]); void decompressBlockTHUMB59T(unsigned int block_part1, unsigned int block_part2, uint8 *img,int width,int height,int startx,int starty); void decompressBlockTHUMB58H(unsigned int block_part1, unsigned int block_part2, uint8 *img,int width,int height,int startx,int starty); void decompressBlockPlanar57(unsigned int compressed57_1, unsigned int compressed57_2, uint8 *img,int width,int height,int startx,int starty); void decompressBlockDiffFlip(unsigned int block_part1, unsigned int block_part2, uint8 *img,int width,int height,int startx,int starty); void decompressBlockETC2(unsigned int block_part1, unsigned int block_part2, uint8 *img,int width,int height,int startx,int starty); void decompressBlockDifferentialWithAlpha(unsigned int block_part1,unsigned int block_part2, uint8* img, uint8* alpha, int width, int height, int startx, int starty); void decompressBlockETC21BitAlpha(unsigned int block_part1, unsigned int block_part2, uint8 *img, uint8* alphaimg, int width,int height,int startx,int starty); void decompressBlockTHUMB58HAlpha(unsigned int block_part1, unsigned int block_part2, uint8 *img, uint8* alpha,int width,int height,int startx,int starty); void decompressBlockTHUMB59TAlpha(unsigned int block_part1, unsigned int block_part2, uint8 *img, uint8* alpha,int width,int height,int startx,int starty); uint8 getbit(uint8 input, int frompos, int topos); int clamp(int val); void decompressBlockAlpha(uint8* data,uint8* img,int width,int height,int ix,int iy); uint16 get16bits11bits(int base, int table, int mul, int index); void decompressBlockAlpha16bit(uint8* data,uint8* img,int width,int height,int ix,int iy); int16 get16bits11signed(int base, int table, int mul, int index); void setupAlphaTable(); // This source code is quite long. You can make it shorter by not including the // code doing the exhaustive code. Then the -slow modes will not work, but the // code will be approximately half the number of lines of code. // Then the lines between "exhaustive code starts here" and "exhaustive code ends here" // can then be removed. #define EXHAUSTIVE_CODE_ACTIVE 1 // Remove warnings for unsafe functions such as strcpy #pragma warning(disable : 4996) // Remove warnings for conversions between different time variables #pragma warning(disable : 4244) // Remove warnings for negative or too big shifts //#pragma warning(disable : 4293) #define CLAMP(ll,x,ul) (((x)<(ll)) ? (ll) : (((x)>(ul)) ? (ul) : (x))) // The below code works as CLAMP(0, x, 255) if x < 255 #define CLAMP_LEFT_ZERO(x) ((~(((int)(x))>>31))&(x)) // The below code works as CLAMP(0, x, 255) if x is in [0,511] #define CLAMP_RIGHT_255(x) (((( ((((int)(x))<<23)>>31) ))|(x))&0x000000ff) #define SQUARE(x) ((x)*(x)) #define JAS_ROUND(x) (((x) < 0.0 ) ? ((int)((x)-0.5)) : ((int)((x)+0.5))) #define JAS_MIN(a,b) ((a) < (b) ? (a) : (b)) #define JAS_MAX(a,b) ((a) > (b) ? (a) : (b)) // The error metric Wr Wg Wb should be definied so that Wr^2 + Wg^2 + Wb^2 = 1. // Hence it is easier to first define the squared values and derive the weights // as their square-roots. #define PERCEPTUAL_WEIGHT_R_SQUARED 0.299 #define PERCEPTUAL_WEIGHT_G_SQUARED 0.587 #define PERCEPTUAL_WEIGHT_B_SQUARED 0.114 #define PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000 299 #define PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000 587 #define PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000 114 #define RED(img,width,x,y) img[3*(y*width+x)+0] #define GREEN(img,width,x,y) img[3*(y*width+x)+1] #define BLUE(img,width,x,y) img[3*(y*width+x)+2] #define SHIFT(size,startpos) ((startpos)-(size)+1) #define MASK(size, startpos) (((2<<(size-1))-1) << SHIFT(size,startpos)) #define PUTBITS( dest, data, size, startpos) dest = ((dest & ~MASK(size, startpos)) | ((data << SHIFT(size, startpos)) & MASK(size,startpos))) #define SHIFTHIGH(size, startpos) (((startpos)-32)-(size)+1) #define MASKHIGH(size, startpos) (((1<<(size))-1) << SHIFTHIGH(size,startpos)) #define PUTBITSHIGH(dest, data, size, startpos) dest = ((dest & ~MASKHIGH(size, startpos)) | ((data << SHIFTHIGH(size, startpos)) & MASKHIGH(size,startpos))) #define GETBITS(source, size, startpos) (( (source) >> ((startpos)-(size)+1) ) & ((1<<(size)) -1)) #define GETBITSHIGH(source, size, startpos) (( (source) >> (((startpos)-32)-(size)+1) ) & ((1<<(size)) -1)) // Thumb macros and definitions #define R_BITS59T 4 #define G_BITS59T 4 #define B_BITS59T 4 #define R_BITS58H 4 #define G_BITS58H 4 #define B_BITS58H 4 #define MAXIMUM_ERROR (255*255*16*1000) #define R 0 #define G 1 #define B 2 #define BLOCKHEIGHT 4 #define BLOCKWIDTH 4 #define BINPOW(power) (1<<(power)) //#define RADIUS 2 #define TABLE_BITS_59T 3 #define TABLE_BITS_58H 3 // Global tables static uint8 table59T[8] = {3,6,11,16,23,32,41,64}; // 3-bit table for the 59 bit T-mode static uint8 table58H[8] = {3,6,11,16,23,32,41,64}; // 3-bit table for the 58 bit H-mode uint8 weight[3] = {1,1,1}; // Color weight // Enums static enum{PATTERN_H = 0, PATTERN_T = 1}; static enum{MODE_ETC1, MODE_THUMB_T, MODE_THUMB_H, MODE_PLANAR}; // The ETC2 package of codecs includes the following codecs: // // codec enum // -------------------------------------------------------- // GL_COMPRESSED_R11_EAC 0x9270 // GL_COMPRESSED_SIGNED_R11_EAC 0x9271 // GL_COMPRESSED_RG11_EAC 0x9272 // GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 // GL_COMPRESSED_RGB8_ETC2 0x9274 // GL_COMPRESSED_SRGB8_ETC2 0x9275 // GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 // GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 // GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 // GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 // // The older codec ETC1 is not included in the package // GL_ETC1_RGB8_OES 0x8d64 // but since ETC2 is backwards compatible an ETC1 texture can // be decoded using the RGB8_ETC2 enum (0x9274) // // In a PKM-file, the codecs are stored using the following identifiers // // identifier value codec // -------------------------------------------------------------------- // ETC1_RGB_NO_MIPMAPS 0 GL_ETC1_RGB8_OES // ETC2PACKAGE_RGB_NO_MIPMAPS 1 GL_COMPRESSED_RGB8_ETC2 // ETC2PACKAGE_RGBA_NO_MIPMAPS_OLD 2, not used - // ETC2PACKAGE_RGBA_NO_MIPMAPS 3 GL_COMPRESSED_RGBA8_ETC2_EAC // ETC2PACKAGE_RGBA1_NO_MIPMAPS 4 GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 // ETC2PACKAGE_R_NO_MIPMAPS 5 GL_COMPRESSED_R11_EAC // ETC2PACKAGE_RG_NO_MIPMAPS 6 GL_COMPRESSED_RG11_EAC // ETC2PACKAGE_R_SIGNED_NO_MIPMAPS 7 GL_COMPRESSED_SIGNED_R11_EAC // ETC2PACKAGE_RG_SIGNED_NO_MIPMAPS 8 GL_COMPRESSED_SIGNED_RG11_EAC // // In the code, the identifiers are not always used strictly. For instance, the // identifier ETC2PACKAGE_R_NO_MIPMAPS is sometimes used for both the unsigned // (GL_COMPRESSED_R11_EAC) and signed (GL_COMPRESSED_SIGNED_R11_EAC) version of // the codec. // static enum{ETC1_RGB_NO_MIPMAPS,ETC2PACKAGE_RGB_NO_MIPMAPS,ETC2PACKAGE_RGBA_NO_MIPMAPS_OLD,ETC2PACKAGE_RGBA_NO_MIPMAPS,ETC2PACKAGE_RGBA1_NO_MIPMAPS,ETC2PACKAGE_R_NO_MIPMAPS,ETC2PACKAGE_RG_NO_MIPMAPS,ETC2PACKAGE_R_SIGNED_NO_MIPMAPS,ETC2PACKAGE_RG_SIGNED_NO_MIPMAPS,ETC2PACKAGE_sRGB_NO_MIPMAPS,ETC2PACKAGE_sRGBA_NO_MIPMAPS,ETC2PACKAGE_sRGBA1_NO_MIPMAPS}; static enum {MODE_COMPRESS, MODE_UNCOMPRESS, MODE_PSNR}; static enum {SPEED_SLOW, SPEED_FAST, SPEED_MEDIUM}; static enum {METRIC_PERCEPTUAL, METRIC_NONPERCEPTUAL}; static enum {CODEC_ETC, CODEC_ETC2}; int mode = MODE_COMPRESS; int speed = SPEED_FAST; int metric = METRIC_PERCEPTUAL; int codec = CODEC_ETC2; int format = ETC2PACKAGE_RGB_NO_MIPMAPS; int verbose = true; extern int formatSigned; int ktxFile=0; bool first_time_message = true; static int scramble[4] = {3, 2, 0, 1}; static int unscramble[4] = {2, 3, 1, 0}; typedef struct KTX_header_t { uint8 identifier[12]; unsigned int endianness; unsigned int glType; unsigned int glTypeSize; unsigned int glFormat; unsigned int glInternalFormat; unsigned int glBaseInternalFormat; unsigned int pixelWidth; unsigned int pixelHeight; unsigned int pixelDepth; unsigned int numberOfArrayElements; unsigned int numberOfFaces; unsigned int numberOfMipmapLevels; unsigned int bytesOfKeyValueData; } KTX_header; #define KTX_IDENTIFIER_REF { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A } #define KTX_ENDIAN_REF (0x04030201) #define KTX_ENDIAN_REF_REV (0x01020304) static enum {GL_R=0x1903,GL_RG=0x8227,GL_RGB=0x1907,GL_RGBA=0x1908}; #define GL_SRGB 0x8C40 #define GL_SRGB8 0x8C41 #define GL_SRGB8_ALPHA8 0x8C43 #define GL_ETC1_RGB8_OES 0x8d64 #define GL_COMPRESSED_R11_EAC 0x9270 #define GL_COMPRESSED_SIGNED_R11_EAC 0x9271 #define GL_COMPRESSED_RG11_EAC 0x9272 #define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273 #define GL_COMPRESSED_RGB8_ETC2 0x9274 #define GL_COMPRESSED_SRGB8_ETC2 0x9275 #define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276 #define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277 #define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 #define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279 int ktx_identifier[] = KTX_IDENTIFIER_REF; //converts indices from |a0|a1|e0|e1|i0|i1|m0|m1|b0|b1|f0|f1|j0|j1|n0|n1|c0|c1|g0|g1|k0|k1|o0|o1|d0|d1|h0|h1|l0|l1|p0|p1| previously used by T- and H-modes // into |p0|o0|n0|m0|l0|k0|j0|i0|h0|g0|f0|e0|d0|c0|b0|a0|p1|o1|n1|m1|l1|k1|j1|i1|h1|g1|f1|e1|d1|c1|b1|a1| which should be used for all modes. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. int indexConversion(int pixelIndices) { int correctIndices = 0; int LSB[4][4]; int MSB[4][4]; int shift=0; for(int y=3; y>=0; y--) { for(int x=3; x>=0; x--) { LSB[x][y] = (pixelIndices>>shift)&1; shift++; MSB[x][y] = (pixelIndices>>shift)&1; shift++; } } shift=0; for(int x=0; x<4; x++) { for(int y=0; y<4; y++) { correctIndices|=(LSB[x][y]<=0) // find file name extension { if(src[q]=='.') break; q--; } if(q<0) return -1; else return q; } // Read source file. Does conversion if file format is not .ppm. // Will expand file to be divisible by four in the x- and y- dimension. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. bool readSrcFile(char *filename,uint8 *&img,int &width,int &height, int &expandedwidth, int &expandedheight) { int w1,h1; int wdiv4, hdiv4; char str[255]; // Delete temp file if it exists. if(fileExist("tmp.ppm")) { sprintf(str, "del tmp.ppm\n"); system(str); } int q = find_pos_of_extension(filename); if(!strcmp(&filename[q],".ppm")) { // Already a .ppm file. Just copy. sprintf(str,"copy %s tmp.ppm \n", filename); printf("Copying source file to tmp.ppm\n", filename); } else { // Converting from other format to .ppm // // Use your favorite command line image converter program, // for instance Image Magick. Just make sure the syntax can // be written as below: // // C:\imconv source.jpg dest.ppm // sprintf(str,"imconv %s tmp.ppm\n", filename); printf("Converting source file from %s to .ppm\n", filename); } // Execute system call system(str); int bitrate=8; if(format==ETC2PACKAGE_RG_NO_MIPMAPS) bitrate=16; if(fReadPPM("tmp.ppm",w1,h1,img,bitrate)) { width=w1; height=h1; system("del tmp.ppm"); // Width must be divisible by 4 and height must be // divisible by 4. Otherwise, we will expand the image wdiv4 = width / 4; hdiv4 = height / 4; expandedwidth = width; expandedheight = height; if( !(wdiv4 * 4 == width) ) { printf(" Width = %d is not divisible by four... ", width); printf(" expanding image in x-dir... "); if(expandToWidthDivByFour(img, width, height, expandedwidth, expandedheight,bitrate)) { printf("OK.\n"); } else { printf("\n Error: could not expand image\n"); return false; } } if( !(hdiv4 * 4 == height)) { printf(" Height = %d is not divisible by four... ", height); printf(" expanding image in y-dir..."); if(expandToHeightDivByFour(img, expandedwidth, height, expandedwidth, expandedheight,bitrate)) { printf("OK.\n"); } else { printf("\n Error: could not expand image\n"); return false; } } if(!(expandedwidth == width && expandedheight == height)) printf("Active pixels: %dx%d. Expanded image: %dx%d\n",width,height,expandedwidth,expandedheight); return true; } else { printf("Could not read tmp.ppm file\n"); exit(1); } return false; } // Reads a file without expanding it to be divisible by 4. // Is used when doing PSNR calculation between two files. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. bool readSrcFileNoExpand(char *filename,uint8 *&img,int &width,int &height) { int w1,h1; char str[255]; // Delete temp file if it exists. if(fileExist("tmp.ppm")) { sprintf(str, "del tmp.ppm\n"); system(str); } int q = find_pos_of_extension(filename); if(!strcmp(&filename[q],".ppm")) { // Already a .ppm file. Just copy. sprintf(str,"copy %s tmp.ppm \n", filename); printf("Copying source file to tmp.ppm\n", filename); } else { // Converting from other format to .ppm // // Use your favorite command line image converter program, // for instance Image Magick. Just make sure the syntax can // be written as below: // // C:\imconv source.jpg dest.ppm // sprintf(str,"imconv %s tmp.ppm\n", filename); // printf("Converting source file from %s to .ppm\n", filename); } // Execute system call system(str); if(fReadPPM("tmp.ppm",w1,h1,img,8)) { width=w1; height=h1; system("del tmp.ppm"); return true; } return false; } // Parses the arguments from the command line. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void readArguments(int argc,char *argv[],char* src,char *dst) { int q; //new code!! do this in a more nicer way! bool srcfound=false,dstfound=false; for(int i=1; i> 1), 1, i); PUTBITS( pixel_indices_LSB, (pixel_indices & 1) , 1, i); i++; // In order to simplify hardware, the table {-12, -4, 4, 12} is indexed {11, 10, 00, 01} // so that first bit is sign bit and the other bit is size bit (4 or 12). // This means that we have to scramble the bits before storing them. sum_error+=min_error; } } *pixel_indices_MSBp = pixel_indices_MSB; *pixel_indices_LSBp = pixel_indices_LSB; return sum_error; } #define MAXERR1000 1000*255*255*16 // Finds all pixel indices for a 2x4 block using perceptual weighting of error. // Done using fixed poinit arithmetics where weights are multiplied by 1000. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int compressBlockWithTable2x4percep1000(uint8 *img,int width,int height,int startx,int starty,uint8 *avg_color,int table,unsigned int *pixel_indices_MSBp, unsigned int *pixel_indices_LSBp) { uint8 orig[3],approx[3]; unsigned int pixel_indices_MSB=0, pixel_indices_LSB=0, pixel_indices = 0; unsigned int sum_error=0; int q, i; i = 0; for(int x=startx; x> 1), 1, i); PUTBITS( pixel_indices_LSB, (pixel_indices & 1) , 1, i); i++; // In order to simplify hardware, the table {-12, -4, 4, 12} is indexed {11, 10, 00, 01} // so that first bit is sign bit and the other bit is size bit (4 or 12). // This means that we have to scramble the bits before storing them. sum_error+=min_error; } } *pixel_indices_MSBp = pixel_indices_MSB; *pixel_indices_LSBp = pixel_indices_LSB; return sum_error; } // Finds all pixel indices for a 2x4 block using perceptual weighting of error. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. float compressBlockWithTable2x4percep(uint8 *img,int width,int height,int startx,int starty,uint8 *avg_color,int table,unsigned int *pixel_indices_MSBp, unsigned int *pixel_indices_LSBp) { uint8 orig[3],approx[3]; unsigned int pixel_indices_MSB=0, pixel_indices_LSB=0, pixel_indices = 0; float sum_error=0; int q, i; double wR2 = PERCEPTUAL_WEIGHT_R_SQUARED; double wG2 = PERCEPTUAL_WEIGHT_G_SQUARED; double wB2 = PERCEPTUAL_WEIGHT_B_SQUARED; i = 0; for(int x=startx; x> 1), 1, i); PUTBITS( pixel_indices_LSB, (pixel_indices & 1) , 1, i); i++; // In order to simplify hardware, the table {-12, -4, 4, 12} is indexed {11, 10, 00, 01} // so that first bit is sign bit and the other bit is size bit (4 or 12). // This means that we have to scramble the bits before storing them. sum_error+=min_error; } } *pixel_indices_MSBp = pixel_indices_MSB; *pixel_indices_LSBp = pixel_indices_LSB; return sum_error; } // Finds all pixel indices for a 4x2 block. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. int compressBlockWithTable4x2(uint8 *img,int width,int height,int startx,int starty,uint8 *avg_color,int table,unsigned int *pixel_indices_MSBp, unsigned int *pixel_indices_LSBp) { uint8 orig[3],approx[3]; unsigned int pixel_indices_MSB=0, pixel_indices_LSB=0, pixel_indices = 0; int sum_error=0; int q; int i; i = 0; for(int x=startx; x> 1), 1, i); PUTBITS( pixel_indices_LSB, (pixel_indices & 1) , 1, i); i++; // In order to simplify hardware, the table {-12, -4, 4, 12} is indexed {11, 10, 00, 01} // so that first bit is sign bit and the other bit is size bit (4 or 12). // This means that we have to scramble the bits before storing them. sum_error+=min_error; } i+=2; } *pixel_indices_MSBp = pixel_indices_MSB; *pixel_indices_LSBp = pixel_indices_LSB; return sum_error; } // Finds all pixel indices for a 4x2 block using perceptual weighting of error. // Done using fixed point arithmetics where 1000 corresponds to 1.0. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int compressBlockWithTable4x2percep1000(uint8 *img,int width,int height,int startx,int starty,uint8 *avg_color,int table,unsigned int *pixel_indices_MSBp, unsigned int *pixel_indices_LSBp) { uint8 orig[3],approx[3]; unsigned int pixel_indices_MSB=0, pixel_indices_LSB=0, pixel_indices = 0; unsigned int sum_error=0; int q; int i; i = 0; for(int x=startx; x> 1), 1, i); PUTBITS( pixel_indices_LSB, (pixel_indices & 1) , 1, i); i++; // In order to simplify hardware, the table {-12, -4, 4, 12} is indexed {11, 10, 00, 01} // so that first bit is sign bit and the other bit is size bit (4 or 12). // This means that we have to scramble the bits before storing them. sum_error+=min_error; } i+=2; } *pixel_indices_MSBp = pixel_indices_MSB; *pixel_indices_LSBp = pixel_indices_LSB; return sum_error; } // Finds all pixel indices for a 4x2 block using perceptual weighting of error. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. float compressBlockWithTable4x2percep(uint8 *img,int width,int height,int startx,int starty,uint8 *avg_color,int table,unsigned int *pixel_indices_MSBp, unsigned int *pixel_indices_LSBp) { uint8 orig[3],approx[3]; unsigned int pixel_indices_MSB=0, pixel_indices_LSB=0, pixel_indices = 0; float sum_error=0; int q; int i; float wR2 = (float) PERCEPTUAL_WEIGHT_R_SQUARED; float wG2 = (float) PERCEPTUAL_WEIGHT_G_SQUARED; float wB2 = (float) PERCEPTUAL_WEIGHT_B_SQUARED; i = 0; for(int x=startx; x> 1), 1, i); PUTBITS( pixel_indices_LSB, (pixel_indices & 1) , 1, i); i++; // In order to simplify hardware, the table {-12, -4, 4, 12} is indexed {11, 10, 00, 01} // so that first bit is sign bit and the other bit is size bit (4 or 12). // This means that we have to scramble the bits before storing them. sum_error+=min_error; } i+=2; } *pixel_indices_MSBp = pixel_indices_MSB; *pixel_indices_LSBp = pixel_indices_LSB; return sum_error; } // Table for fast implementation of clamping to the interval [0,255] followed by addition of 255. const int clamp_table_plus_255[768] = {0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 0+255, 1+255, 2+255, 3+255, 4+255, 5+255, 6+255, 7+255, 8+255, 9+255, 10+255, 11+255, 12+255, 13+255, 14+255, 15+255, 16+255, 17+255, 18+255, 19+255, 20+255, 21+255, 22+255, 23+255, 24+255, 25+255, 26+255, 27+255, 28+255, 29+255, 30+255, 31+255, 32+255, 33+255, 34+255, 35+255, 36+255, 37+255, 38+255, 39+255, 40+255, 41+255, 42+255, 43+255, 44+255, 45+255, 46+255, 47+255, 48+255, 49+255, 50+255, 51+255, 52+255, 53+255, 54+255, 55+255, 56+255, 57+255, 58+255, 59+255, 60+255, 61+255, 62+255, 63+255, 64+255, 65+255, 66+255, 67+255, 68+255, 69+255, 70+255, 71+255, 72+255, 73+255, 74+255, 75+255, 76+255, 77+255, 78+255, 79+255, 80+255, 81+255, 82+255, 83+255, 84+255, 85+255, 86+255, 87+255, 88+255, 89+255, 90+255, 91+255, 92+255, 93+255, 94+255, 95+255, 96+255, 97+255, 98+255, 99+255, 100+255, 101+255, 102+255, 103+255, 104+255, 105+255, 106+255, 107+255, 108+255, 109+255, 110+255, 111+255, 112+255, 113+255, 114+255, 115+255, 116+255, 117+255, 118+255, 119+255, 120+255, 121+255, 122+255, 123+255, 124+255, 125+255, 126+255, 127+255, 128+255, 129+255, 130+255, 131+255, 132+255, 133+255, 134+255, 135+255, 136+255, 137+255, 138+255, 139+255, 140+255, 141+255, 142+255, 143+255, 144+255, 145+255, 146+255, 147+255, 148+255, 149+255, 150+255, 151+255, 152+255, 153+255, 154+255, 155+255, 156+255, 157+255, 158+255, 159+255, 160+255, 161+255, 162+255, 163+255, 164+255, 165+255, 166+255, 167+255, 168+255, 169+255, 170+255, 171+255, 172+255, 173+255, 174+255, 175+255, 176+255, 177+255, 178+255, 179+255, 180+255, 181+255, 182+255, 183+255, 184+255, 185+255, 186+255, 187+255, 188+255, 189+255, 190+255, 191+255, 192+255, 193+255, 194+255, 195+255, 196+255, 197+255, 198+255, 199+255, 200+255, 201+255, 202+255, 203+255, 204+255, 205+255, 206+255, 207+255, 208+255, 209+255, 210+255, 211+255, 212+255, 213+255, 214+255, 215+255, 216+255, 217+255, 218+255, 219+255, 220+255, 221+255, 222+255, 223+255, 224+255, 225+255, 226+255, 227+255, 228+255, 229+255, 230+255, 231+255, 232+255, 233+255, 234+255, 235+255, 236+255, 237+255, 238+255, 239+255, 240+255, 241+255, 242+255, 243+255, 244+255, 245+255, 246+255, 247+255, 248+255, 249+255, 250+255, 251+255, 252+255, 253+255, 254+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255, 255+255}; // Table for fast implementationi of clamping to the interval [0,255] const int clamp_table[768] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; // Table for fast implementation of squaring for numbers in the interval [-255, 255] const unsigned int square_table[511] = {65025, 64516, 64009, 63504, 63001, 62500, 62001, 61504, 61009, 60516, 60025, 59536, 59049, 58564, 58081, 57600, 57121, 56644, 56169, 55696, 55225, 54756, 54289, 53824, 53361, 52900, 52441, 51984, 51529, 51076, 50625, 50176, 49729, 49284, 48841, 48400, 47961, 47524, 47089, 46656, 46225, 45796, 45369, 44944, 44521, 44100, 43681, 43264, 42849, 42436, 42025, 41616, 41209, 40804, 40401, 40000, 39601, 39204, 38809, 38416, 38025, 37636, 37249, 36864, 36481, 36100, 35721, 35344, 34969, 34596, 34225, 33856, 33489, 33124, 32761, 32400, 32041, 31684, 31329, 30976, 30625, 30276, 29929, 29584, 29241, 28900, 28561, 28224, 27889, 27556, 27225, 26896, 26569, 26244, 25921, 25600, 25281, 24964, 24649, 24336, 24025, 23716, 23409, 23104, 22801, 22500, 22201, 21904, 21609, 21316, 21025, 20736, 20449, 20164, 19881, 19600, 19321, 19044, 18769, 18496, 18225, 17956, 17689, 17424, 17161, 16900, 16641, 16384, 16129, 15876, 15625, 15376, 15129, 14884, 14641, 14400, 14161, 13924, 13689, 13456, 13225, 12996, 12769, 12544, 12321, 12100, 11881, 11664, 11449, 11236, 11025, 10816, 10609, 10404, 10201, 10000, 9801, 9604, 9409, 9216, 9025, 8836, 8649, 8464, 8281, 8100, 7921, 7744, 7569, 7396, 7225, 7056, 6889, 6724, 6561, 6400, 6241, 6084, 5929, 5776, 5625, 5476, 5329, 5184, 5041, 4900, 4761, 4624, 4489, 4356, 4225, 4096, 3969, 3844, 3721, 3600, 3481, 3364, 3249, 3136, 3025, 2916, 2809, 2704, 2601, 2500, 2401, 2304, 2209, 2116, 2025, 1936, 1849, 1764, 1681, 1600, 1521, 1444, 1369, 1296, 1225, 1156, 1089, 1024, 961, 900, 841, 784, 729, 676, 625, 576, 529, 484, 441, 400, 361, 324, 289, 256, 225, 196, 169, 144, 121, 100, 81, 64, 49, 36, 25, 16, 9, 4, 1, 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209, 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364, 3481, 3600, 3721, 3844, 3969, 4096, 4225, 4356, 4489, 4624, 4761, 4900, 5041, 5184, 5329, 5476, 5625, 5776, 5929, 6084, 6241, 6400, 6561, 6724, 6889, 7056, 7225, 7396, 7569, 7744, 7921, 8100, 8281, 8464, 8649, 8836, 9025, 9216, 9409, 9604, 9801, 10000, 10201, 10404, 10609, 10816, 11025, 11236, 11449, 11664, 11881, 12100, 12321, 12544, 12769, 12996, 13225, 13456, 13689, 13924, 14161, 14400, 14641, 14884, 15129, 15376, 15625, 15876, 16129, 16384, 16641, 16900, 17161, 17424, 17689, 17956, 18225, 18496, 18769, 19044, 19321, 19600, 19881, 20164, 20449, 20736, 21025, 21316, 21609, 21904, 22201, 22500, 22801, 23104, 23409, 23716, 24025, 24336, 24649, 24964, 25281, 25600, 25921, 26244, 26569, 26896, 27225, 27556, 27889, 28224, 28561, 28900, 29241, 29584, 29929, 30276, 30625, 30976, 31329, 31684, 32041, 32400, 32761, 33124, 33489, 33856, 34225, 34596, 34969, 35344, 35721, 36100, 36481, 36864, 37249, 37636, 38025, 38416, 38809, 39204, 39601, 40000, 40401, 40804, 41209, 41616, 42025, 42436, 42849, 43264, 43681, 44100, 44521, 44944, 45369, 45796, 46225, 46656, 47089, 47524, 47961, 48400, 48841, 49284, 49729, 50176, 50625, 51076, 51529, 51984, 52441, 52900, 53361, 53824, 54289, 54756, 55225, 55696, 56169, 56644, 57121, 57600, 58081, 58564, 59049, 59536, 60025, 60516, 61009, 61504, 62001, 62500, 63001, 63504, 64009, 64516, 65025}; // Abbreviated variable names to make below tables smaller in source code size #define KR PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000 #define KG PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000 #define KB PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000 // Table for fast implementation of squaring for numbers in the interval [-255, 255] multiplied by the perceptual weight for red. const unsigned int square_table_percep_red[511] = { 65025*KR, 64516*KR, 64009*KR, 63504*KR, 63001*KR, 62500*KR, 62001*KR, 61504*KR, 61009*KR, 60516*KR, 60025*KR, 59536*KR, 59049*KR, 58564*KR, 58081*KR, 57600*KR, 57121*KR, 56644*KR, 56169*KR, 55696*KR, 55225*KR, 54756*KR, 54289*KR, 53824*KR, 53361*KR, 52900*KR, 52441*KR, 51984*KR, 51529*KR, 51076*KR, 50625*KR, 50176*KR, 49729*KR, 49284*KR, 48841*KR, 48400*KR, 47961*KR, 47524*KR, 47089*KR, 46656*KR, 46225*KR, 45796*KR, 45369*KR, 44944*KR, 44521*KR, 44100*KR, 43681*KR, 43264*KR, 42849*KR, 42436*KR, 42025*KR, 41616*KR, 41209*KR, 40804*KR, 40401*KR, 40000*KR, 39601*KR, 39204*KR, 38809*KR, 38416*KR, 38025*KR, 37636*KR, 37249*KR, 36864*KR, 36481*KR, 36100*KR, 35721*KR, 35344*KR, 34969*KR, 34596*KR, 34225*KR, 33856*KR, 33489*KR, 33124*KR, 32761*KR, 32400*KR, 32041*KR, 31684*KR, 31329*KR, 30976*KR, 30625*KR, 30276*KR, 29929*KR, 29584*KR, 29241*KR, 28900*KR, 28561*KR, 28224*KR, 27889*KR, 27556*KR, 27225*KR, 26896*KR, 26569*KR, 26244*KR, 25921*KR, 25600*KR, 25281*KR, 24964*KR, 24649*KR, 24336*KR, 24025*KR, 23716*KR, 23409*KR, 23104*KR, 22801*KR, 22500*KR, 22201*KR, 21904*KR, 21609*KR, 21316*KR, 21025*KR, 20736*KR, 20449*KR, 20164*KR, 19881*KR, 19600*KR, 19321*KR, 19044*KR, 18769*KR, 18496*KR, 18225*KR, 17956*KR, 17689*KR, 17424*KR, 17161*KR, 16900*KR, 16641*KR, 16384*KR, 16129*KR, 15876*KR, 15625*KR, 15376*KR, 15129*KR, 14884*KR, 14641*KR, 14400*KR, 14161*KR, 13924*KR, 13689*KR, 13456*KR, 13225*KR, 12996*KR, 12769*KR, 12544*KR, 12321*KR, 12100*KR, 11881*KR, 11664*KR, 11449*KR, 11236*KR, 11025*KR, 10816*KR, 10609*KR, 10404*KR, 10201*KR, 10000*KR, 9801*KR, 9604*KR, 9409*KR, 9216*KR, 9025*KR, 8836*KR, 8649*KR, 8464*KR, 8281*KR, 8100*KR, 7921*KR, 7744*KR, 7569*KR, 7396*KR, 7225*KR, 7056*KR, 6889*KR, 6724*KR, 6561*KR, 6400*KR, 6241*KR, 6084*KR, 5929*KR, 5776*KR, 5625*KR, 5476*KR, 5329*KR, 5184*KR, 5041*KR, 4900*KR, 4761*KR, 4624*KR, 4489*KR, 4356*KR, 4225*KR, 4096*KR, 3969*KR, 3844*KR, 3721*KR, 3600*KR, 3481*KR, 3364*KR, 3249*KR, 3136*KR, 3025*KR, 2916*KR, 2809*KR, 2704*KR, 2601*KR, 2500*KR, 2401*KR, 2304*KR, 2209*KR, 2116*KR, 2025*KR, 1936*KR, 1849*KR, 1764*KR, 1681*KR, 1600*KR, 1521*KR, 1444*KR, 1369*KR, 1296*KR, 1225*KR, 1156*KR, 1089*KR, 1024*KR, 961*KR, 900*KR, 841*KR, 784*KR, 729*KR, 676*KR, 625*KR, 576*KR, 529*KR, 484*KR, 441*KR, 400*KR, 361*KR, 324*KR, 289*KR, 256*KR, 225*KR, 196*KR, 169*KR, 144*KR, 121*KR, 100*KR, 81*KR, 64*KR, 49*KR, 36*KR, 25*KR, 16*KR, 9*KR, 4*KR, 1*KR, 0*KR, 1*KR, 4*KR, 9*KR, 16*KR, 25*KR, 36*KR, 49*KR, 64*KR, 81*KR, 100*KR, 121*KR, 144*KR, 169*KR, 196*KR, 225*KR, 256*KR, 289*KR, 324*KR, 361*KR, 400*KR, 441*KR, 484*KR, 529*KR, 576*KR, 625*KR, 676*KR, 729*KR, 784*KR, 841*KR, 900*KR, 961*KR, 1024*KR, 1089*KR, 1156*KR, 1225*KR, 1296*KR, 1369*KR, 1444*KR, 1521*KR, 1600*KR, 1681*KR, 1764*KR, 1849*KR, 1936*KR, 2025*KR, 2116*KR, 2209*KR, 2304*KR, 2401*KR, 2500*KR, 2601*KR, 2704*KR, 2809*KR, 2916*KR, 3025*KR, 3136*KR, 3249*KR, 3364*KR, 3481*KR, 3600*KR, 3721*KR, 3844*KR, 3969*KR, 4096*KR, 4225*KR, 4356*KR, 4489*KR, 4624*KR, 4761*KR, 4900*KR, 5041*KR, 5184*KR, 5329*KR, 5476*KR, 5625*KR, 5776*KR, 5929*KR, 6084*KR, 6241*KR, 6400*KR, 6561*KR, 6724*KR, 6889*KR, 7056*KR, 7225*KR, 7396*KR, 7569*KR, 7744*KR, 7921*KR, 8100*KR, 8281*KR, 8464*KR, 8649*KR, 8836*KR, 9025*KR, 9216*KR, 9409*KR, 9604*KR, 9801*KR, 10000*KR, 10201*KR, 10404*KR, 10609*KR, 10816*KR, 11025*KR, 11236*KR, 11449*KR, 11664*KR, 11881*KR, 12100*KR, 12321*KR, 12544*KR, 12769*KR, 12996*KR, 13225*KR, 13456*KR, 13689*KR, 13924*KR, 14161*KR, 14400*KR, 14641*KR, 14884*KR, 15129*KR, 15376*KR, 15625*KR, 15876*KR, 16129*KR, 16384*KR, 16641*KR, 16900*KR, 17161*KR, 17424*KR, 17689*KR, 17956*KR, 18225*KR, 18496*KR, 18769*KR, 19044*KR, 19321*KR, 19600*KR, 19881*KR, 20164*KR, 20449*KR, 20736*KR, 21025*KR, 21316*KR, 21609*KR, 21904*KR, 22201*KR, 22500*KR, 22801*KR, 23104*KR, 23409*KR, 23716*KR, 24025*KR, 24336*KR, 24649*KR, 24964*KR, 25281*KR, 25600*KR, 25921*KR, 26244*KR, 26569*KR, 26896*KR, 27225*KR, 27556*KR, 27889*KR, 28224*KR, 28561*KR, 28900*KR, 29241*KR, 29584*KR, 29929*KR, 30276*KR, 30625*KR, 30976*KR, 31329*KR, 31684*KR, 32041*KR, 32400*KR, 32761*KR, 33124*KR, 33489*KR, 33856*KR, 34225*KR, 34596*KR, 34969*KR, 35344*KR, 35721*KR, 36100*KR, 36481*KR, 36864*KR, 37249*KR, 37636*KR, 38025*KR, 38416*KR, 38809*KR, 39204*KR, 39601*KR, 40000*KR, 40401*KR, 40804*KR, 41209*KR, 41616*KR, 42025*KR, 42436*KR, 42849*KR, 43264*KR, 43681*KR, 44100*KR, 44521*KR, 44944*KR, 45369*KR, 45796*KR, 46225*KR, 46656*KR, 47089*KR, 47524*KR, 47961*KR, 48400*KR, 48841*KR, 49284*KR, 49729*KR, 50176*KR, 50625*KR, 51076*KR, 51529*KR, 51984*KR, 52441*KR, 52900*KR, 53361*KR, 53824*KR, 54289*KR, 54756*KR, 55225*KR, 55696*KR, 56169*KR, 56644*KR, 57121*KR, 57600*KR, 58081*KR, 58564*KR, 59049*KR, 59536*KR, 60025*KR, 60516*KR, 61009*KR, 61504*KR, 62001*KR, 62500*KR, 63001*KR, 63504*KR, 64009*KR, 64516*KR, 65025*KR}; // Table for fast implementation of squaring for numbers in the interval [-255, 255] multiplied by the perceptual weight for green. const unsigned int square_table_percep_green[511] = { 65025*KG, 64516*KG, 64009*KG, 63504*KG, 63001*KG, 62500*KG, 62001*KG, 61504*KG, 61009*KG, 60516*KG, 60025*KG, 59536*KG, 59049*KG, 58564*KG, 58081*KG, 57600*KG, 57121*KG, 56644*KG, 56169*KG, 55696*KG, 55225*KG, 54756*KG, 54289*KG, 53824*KG, 53361*KG, 52900*KG, 52441*KG, 51984*KG, 51529*KG, 51076*KG, 50625*KG, 50176*KG, 49729*KG, 49284*KG, 48841*KG, 48400*KG, 47961*KG, 47524*KG, 47089*KG, 46656*KG, 46225*KG, 45796*KG, 45369*KG, 44944*KG, 44521*KG, 44100*KG, 43681*KG, 43264*KG, 42849*KG, 42436*KG, 42025*KG, 41616*KG, 41209*KG, 40804*KG, 40401*KG, 40000*KG, 39601*KG, 39204*KG, 38809*KG, 38416*KG, 38025*KG, 37636*KG, 37249*KG, 36864*KG, 36481*KG, 36100*KG, 35721*KG, 35344*KG, 34969*KG, 34596*KG, 34225*KG, 33856*KG, 33489*KG, 33124*KG, 32761*KG, 32400*KG, 32041*KG, 31684*KG, 31329*KG, 30976*KG, 30625*KG, 30276*KG, 29929*KG, 29584*KG, 29241*KG, 28900*KG, 28561*KG, 28224*KG, 27889*KG, 27556*KG, 27225*KG, 26896*KG, 26569*KG, 26244*KG, 25921*KG, 25600*KG, 25281*KG, 24964*KG, 24649*KG, 24336*KG, 24025*KG, 23716*KG, 23409*KG, 23104*KG, 22801*KG, 22500*KG, 22201*KG, 21904*KG, 21609*KG, 21316*KG, 21025*KG, 20736*KG, 20449*KG, 20164*KG, 19881*KG, 19600*KG, 19321*KG, 19044*KG, 18769*KG, 18496*KG, 18225*KG, 17956*KG, 17689*KG, 17424*KG, 17161*KG, 16900*KG, 16641*KG, 16384*KG, 16129*KG, 15876*KG, 15625*KG, 15376*KG, 15129*KG, 14884*KG, 14641*KG, 14400*KG, 14161*KG, 13924*KG, 13689*KG, 13456*KG, 13225*KG, 12996*KG, 12769*KG, 12544*KG, 12321*KG, 12100*KG, 11881*KG, 11664*KG, 11449*KG, 11236*KG, 11025*KG, 10816*KG, 10609*KG, 10404*KG, 10201*KG, 10000*KG, 9801*KG, 9604*KG, 9409*KG, 9216*KG, 9025*KG, 8836*KG, 8649*KG, 8464*KG, 8281*KG, 8100*KG, 7921*KG, 7744*KG, 7569*KG, 7396*KG, 7225*KG, 7056*KG, 6889*KG, 6724*KG, 6561*KG, 6400*KG, 6241*KG, 6084*KG, 5929*KG, 5776*KG, 5625*KG, 5476*KG, 5329*KG, 5184*KG, 5041*KG, 4900*KG, 4761*KG, 4624*KG, 4489*KG, 4356*KG, 4225*KG, 4096*KG, 3969*KG, 3844*KG, 3721*KG, 3600*KG, 3481*KG, 3364*KG, 3249*KG, 3136*KG, 3025*KG, 2916*KG, 2809*KG, 2704*KG, 2601*KG, 2500*KG, 2401*KG, 2304*KG, 2209*KG, 2116*KG, 2025*KG, 1936*KG, 1849*KG, 1764*KG, 1681*KG, 1600*KG, 1521*KG, 1444*KG, 1369*KG, 1296*KG, 1225*KG, 1156*KG, 1089*KG, 1024*KG, 961*KG, 900*KG, 841*KG, 784*KG, 729*KG, 676*KG, 625*KG, 576*KG, 529*KG, 484*KG, 441*KG, 400*KG, 361*KG, 324*KG, 289*KG, 256*KG, 225*KG, 196*KG, 169*KG, 144*KG, 121*KG, 100*KG, 81*KG, 64*KG, 49*KG, 36*KG, 25*KG, 16*KG, 9*KG, 4*KG, 1*KG, 0*KG, 1*KG, 4*KG, 9*KG, 16*KG, 25*KG, 36*KG, 49*KG, 64*KG, 81*KG, 100*KG, 121*KG, 144*KG, 169*KG, 196*KG, 225*KG, 256*KG, 289*KG, 324*KG, 361*KG, 400*KG, 441*KG, 484*KG, 529*KG, 576*KG, 625*KG, 676*KG, 729*KG, 784*KG, 841*KG, 900*KG, 961*KG, 1024*KG, 1089*KG, 1156*KG, 1225*KG, 1296*KG, 1369*KG, 1444*KG, 1521*KG, 1600*KG, 1681*KG, 1764*KG, 1849*KG, 1936*KG, 2025*KG, 2116*KG, 2209*KG, 2304*KG, 2401*KG, 2500*KG, 2601*KG, 2704*KG, 2809*KG, 2916*KG, 3025*KG, 3136*KG, 3249*KG, 3364*KG, 3481*KG, 3600*KG, 3721*KG, 3844*KG, 3969*KG, 4096*KG, 4225*KG, 4356*KG, 4489*KG, 4624*KG, 4761*KG, 4900*KG, 5041*KG, 5184*KG, 5329*KG, 5476*KG, 5625*KG, 5776*KG, 5929*KG, 6084*KG, 6241*KG, 6400*KG, 6561*KG, 6724*KG, 6889*KG, 7056*KG, 7225*KG, 7396*KG, 7569*KG, 7744*KG, 7921*KG, 8100*KG, 8281*KG, 8464*KG, 8649*KG, 8836*KG, 9025*KG, 9216*KG, 9409*KG, 9604*KG, 9801*KG, 10000*KG, 10201*KG, 10404*KG, 10609*KG, 10816*KG, 11025*KG, 11236*KG, 11449*KG, 11664*KG, 11881*KG, 12100*KG, 12321*KG, 12544*KG, 12769*KG, 12996*KG, 13225*KG, 13456*KG, 13689*KG, 13924*KG, 14161*KG, 14400*KG, 14641*KG, 14884*KG, 15129*KG, 15376*KG, 15625*KG, 15876*KG, 16129*KG, 16384*KG, 16641*KG, 16900*KG, 17161*KG, 17424*KG, 17689*KG, 17956*KG, 18225*KG, 18496*KG, 18769*KG, 19044*KG, 19321*KG, 19600*KG, 19881*KG, 20164*KG, 20449*KG, 20736*KG, 21025*KG, 21316*KG, 21609*KG, 21904*KG, 22201*KG, 22500*KG, 22801*KG, 23104*KG, 23409*KG, 23716*KG, 24025*KG, 24336*KG, 24649*KG, 24964*KG, 25281*KG, 25600*KG, 25921*KG, 26244*KG, 26569*KG, 26896*KG, 27225*KG, 27556*KG, 27889*KG, 28224*KG, 28561*KG, 28900*KG, 29241*KG, 29584*KG, 29929*KG, 30276*KG, 30625*KG, 30976*KG, 31329*KG, 31684*KG, 32041*KG, 32400*KG, 32761*KG, 33124*KG, 33489*KG, 33856*KG, 34225*KG, 34596*KG, 34969*KG, 35344*KG, 35721*KG, 36100*KG, 36481*KG, 36864*KG, 37249*KG, 37636*KG, 38025*KG, 38416*KG, 38809*KG, 39204*KG, 39601*KG, 40000*KG, 40401*KG, 40804*KG, 41209*KG, 41616*KG, 42025*KG, 42436*KG, 42849*KG, 43264*KG, 43681*KG, 44100*KG, 44521*KG, 44944*KG, 45369*KG, 45796*KG, 46225*KG, 46656*KG, 47089*KG, 47524*KG, 47961*KG, 48400*KG, 48841*KG, 49284*KG, 49729*KG, 50176*KG, 50625*KG, 51076*KG, 51529*KG, 51984*KG, 52441*KG, 52900*KG, 53361*KG, 53824*KG, 54289*KG, 54756*KG, 55225*KG, 55696*KG, 56169*KG, 56644*KG, 57121*KG, 57600*KG, 58081*KG, 58564*KG, 59049*KG, 59536*KG, 60025*KG, 60516*KG, 61009*KG, 61504*KG, 62001*KG, 62500*KG, 63001*KG, 63504*KG, 64009*KG, 64516*KG, 65025*KG}; // Table for fast implementation of squaring for numbers in the interval [-255, 255] multiplied by the perceptual weight for blue. const unsigned int square_table_percep_blue[511] = { 65025*KB, 64516*KB, 64009*KB, 63504*KB, 63001*KB, 62500*KB, 62001*KB, 61504*KB, 61009*KB, 60516*KB, 60025*KB, 59536*KB, 59049*KB, 58564*KB, 58081*KB, 57600*KB, 57121*KB, 56644*KB, 56169*KB, 55696*KB, 55225*KB, 54756*KB, 54289*KB, 53824*KB, 53361*KB, 52900*KB, 52441*KB, 51984*KB, 51529*KB, 51076*KB, 50625*KB, 50176*KB, 49729*KB, 49284*KB, 48841*KB, 48400*KB, 47961*KB, 47524*KB, 47089*KB, 46656*KB, 46225*KB, 45796*KB, 45369*KB, 44944*KB, 44521*KB, 44100*KB, 43681*KB, 43264*KB, 42849*KB, 42436*KB, 42025*KB, 41616*KB, 41209*KB, 40804*KB, 40401*KB, 40000*KB, 39601*KB, 39204*KB, 38809*KB, 38416*KB, 38025*KB, 37636*KB, 37249*KB, 36864*KB, 36481*KB, 36100*KB, 35721*KB, 35344*KB, 34969*KB, 34596*KB, 34225*KB, 33856*KB, 33489*KB, 33124*KB, 32761*KB, 32400*KB, 32041*KB, 31684*KB, 31329*KB, 30976*KB, 30625*KB, 30276*KB, 29929*KB, 29584*KB, 29241*KB, 28900*KB, 28561*KB, 28224*KB, 27889*KB, 27556*KB, 27225*KB, 26896*KB, 26569*KB, 26244*KB, 25921*KB, 25600*KB, 25281*KB, 24964*KB, 24649*KB, 24336*KB, 24025*KB, 23716*KB, 23409*KB, 23104*KB, 22801*KB, 22500*KB, 22201*KB, 21904*KB, 21609*KB, 21316*KB, 21025*KB, 20736*KB, 20449*KB, 20164*KB, 19881*KB, 19600*KB, 19321*KB, 19044*KB, 18769*KB, 18496*KB, 18225*KB, 17956*KB, 17689*KB, 17424*KB, 17161*KB, 16900*KB, 16641*KB, 16384*KB, 16129*KB, 15876*KB, 15625*KB, 15376*KB, 15129*KB, 14884*KB, 14641*KB, 14400*KB, 14161*KB, 13924*KB, 13689*KB, 13456*KB, 13225*KB, 12996*KB, 12769*KB, 12544*KB, 12321*KB, 12100*KB, 11881*KB, 11664*KB, 11449*KB, 11236*KB, 11025*KB, 10816*KB, 10609*KB, 10404*KB, 10201*KB, 10000*KB, 9801*KB, 9604*KB, 9409*KB, 9216*KB, 9025*KB, 8836*KB, 8649*KB, 8464*KB, 8281*KB, 8100*KB, 7921*KB, 7744*KB, 7569*KB, 7396*KB, 7225*KB, 7056*KB, 6889*KB, 6724*KB, 6561*KB, 6400*KB, 6241*KB, 6084*KB, 5929*KB, 5776*KB, 5625*KB, 5476*KB, 5329*KB, 5184*KB, 5041*KB, 4900*KB, 4761*KB, 4624*KB, 4489*KB, 4356*KB, 4225*KB, 4096*KB, 3969*KB, 3844*KB, 3721*KB, 3600*KB, 3481*KB, 3364*KB, 3249*KB, 3136*KB, 3025*KB, 2916*KB, 2809*KB, 2704*KB, 2601*KB, 2500*KB, 2401*KB, 2304*KB, 2209*KB, 2116*KB, 2025*KB, 1936*KB, 1849*KB, 1764*KB, 1681*KB, 1600*KB, 1521*KB, 1444*KB, 1369*KB, 1296*KB, 1225*KB, 1156*KB, 1089*KB, 1024*KB, 961*KB, 900*KB, 841*KB, 784*KB, 729*KB, 676*KB, 625*KB, 576*KB, 529*KB, 484*KB, 441*KB, 400*KB, 361*KB, 324*KB, 289*KB, 256*KB, 225*KB, 196*KB, 169*KB, 144*KB, 121*KB, 100*KB, 81*KB, 64*KB, 49*KB, 36*KB, 25*KB, 16*KB, 9*KB, 4*KB, 1*KB, 0*KB, 1*KB, 4*KB, 9*KB, 16*KB, 25*KB, 36*KB, 49*KB, 64*KB, 81*KB, 100*KB, 121*KB, 144*KB, 169*KB, 196*KB, 225*KB, 256*KB, 289*KB, 324*KB, 361*KB, 400*KB, 441*KB, 484*KB, 529*KB, 576*KB, 625*KB, 676*KB, 729*KB, 784*KB, 841*KB, 900*KB, 961*KB, 1024*KB, 1089*KB, 1156*KB, 1225*KB, 1296*KB, 1369*KB, 1444*KB, 1521*KB, 1600*KB, 1681*KB, 1764*KB, 1849*KB, 1936*KB, 2025*KB, 2116*KB, 2209*KB, 2304*KB, 2401*KB, 2500*KB, 2601*KB, 2704*KB, 2809*KB, 2916*KB, 3025*KB, 3136*KB, 3249*KB, 3364*KB, 3481*KB, 3600*KB, 3721*KB, 3844*KB, 3969*KB, 4096*KB, 4225*KB, 4356*KB, 4489*KB, 4624*KB, 4761*KB, 4900*KB, 5041*KB, 5184*KB, 5329*KB, 5476*KB, 5625*KB, 5776*KB, 5929*KB, 6084*KB, 6241*KB, 6400*KB, 6561*KB, 6724*KB, 6889*KB, 7056*KB, 7225*KB, 7396*KB, 7569*KB, 7744*KB, 7921*KB, 8100*KB, 8281*KB, 8464*KB, 8649*KB, 8836*KB, 9025*KB, 9216*KB, 9409*KB, 9604*KB, 9801*KB, 10000*KB, 10201*KB, 10404*KB, 10609*KB, 10816*KB, 11025*KB, 11236*KB, 11449*KB, 11664*KB, 11881*KB, 12100*KB, 12321*KB, 12544*KB, 12769*KB, 12996*KB, 13225*KB, 13456*KB, 13689*KB, 13924*KB, 14161*KB, 14400*KB, 14641*KB, 14884*KB, 15129*KB, 15376*KB, 15625*KB, 15876*KB, 16129*KB, 16384*KB, 16641*KB, 16900*KB, 17161*KB, 17424*KB, 17689*KB, 17956*KB, 18225*KB, 18496*KB, 18769*KB, 19044*KB, 19321*KB, 19600*KB, 19881*KB, 20164*KB, 20449*KB, 20736*KB, 21025*KB, 21316*KB, 21609*KB, 21904*KB, 22201*KB, 22500*KB, 22801*KB, 23104*KB, 23409*KB, 23716*KB, 24025*KB, 24336*KB, 24649*KB, 24964*KB, 25281*KB, 25600*KB, 25921*KB, 26244*KB, 26569*KB, 26896*KB, 27225*KB, 27556*KB, 27889*KB, 28224*KB, 28561*KB, 28900*KB, 29241*KB, 29584*KB, 29929*KB, 30276*KB, 30625*KB, 30976*KB, 31329*KB, 31684*KB, 32041*KB, 32400*KB, 32761*KB, 33124*KB, 33489*KB, 33856*KB, 34225*KB, 34596*KB, 34969*KB, 35344*KB, 35721*KB, 36100*KB, 36481*KB, 36864*KB, 37249*KB, 37636*KB, 38025*KB, 38416*KB, 38809*KB, 39204*KB, 39601*KB, 40000*KB, 40401*KB, 40804*KB, 41209*KB, 41616*KB, 42025*KB, 42436*KB, 42849*KB, 43264*KB, 43681*KB, 44100*KB, 44521*KB, 44944*KB, 45369*KB, 45796*KB, 46225*KB, 46656*KB, 47089*KB, 47524*KB, 47961*KB, 48400*KB, 48841*KB, 49284*KB, 49729*KB, 50176*KB, 50625*KB, 51076*KB, 51529*KB, 51984*KB, 52441*KB, 52900*KB, 53361*KB, 53824*KB, 54289*KB, 54756*KB, 55225*KB, 55696*KB, 56169*KB, 56644*KB, 57121*KB, 57600*KB, 58081*KB, 58564*KB, 59049*KB, 59536*KB, 60025*KB, 60516*KB, 61009*KB, 61504*KB, 62001*KB, 62500*KB, 63001*KB, 63504*KB, 64009*KB, 64516*KB, 65025*KB}; // Find the best table to use for a 2x4 area by testing all. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. int tryalltables_3bittable2x4(uint8 *img,int width,int height,int startx,int starty,uint8 *avg_color, unsigned int &best_table,unsigned int &best_pixel_indices_MSB, unsigned int &best_pixel_indices_LSB) { int min_error = 3*255*255*16; int q; int err; unsigned int pixel_indices_MSB, pixel_indices_LSB; for(q=0;q<16;q+=2) // try all the 8 tables. { err=compressBlockWithTable2x4(img,width,height,startx,starty,avg_color,q,&pixel_indices_MSB, &pixel_indices_LSB); if(err> 1; } } return min_error; } // Find the best table to use for a 2x4 area by testing all. // Uses perceptual weighting. // Uses fixed point implementation where 1000 equals 1.0 // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int tryalltables_3bittable2x4percep1000(uint8 *img,int width,int height,int startx,int starty,uint8 *avg_color, unsigned int &best_table,unsigned int &best_pixel_indices_MSB, unsigned int &best_pixel_indices_LSB) { unsigned int min_error = MAXERR1000; int q; unsigned int err; unsigned int pixel_indices_MSB, pixel_indices_LSB; for(q=0;q<16;q+=2) // try all the 8 tables. { err=compressBlockWithTable2x4percep1000(img,width,height,startx,starty,avg_color,q,&pixel_indices_MSB, &pixel_indices_LSB); if(err> 1; } } return min_error; } // Find the best table to use for a 2x4 area by testing all. // Uses perceptual weighting. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. int tryalltables_3bittable2x4percep(uint8 *img,int width,int height,int startx,int starty,uint8 *avg_color, unsigned int &best_table,unsigned int &best_pixel_indices_MSB, unsigned int &best_pixel_indices_LSB) { float min_error = 3*255*255*16; int q; float err; unsigned int pixel_indices_MSB, pixel_indices_LSB; for(q=0;q<16;q+=2) // try all the 8 tables. { err=compressBlockWithTable2x4percep(img,width,height,startx,starty,avg_color,q,&pixel_indices_MSB, &pixel_indices_LSB); if(err> 1; } } return (int) min_error; } // Find the best table to use for a 4x2 area by testing all. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. int tryalltables_3bittable4x2(uint8 *img,int width,int height,int startx,int starty,uint8 *avg_color, unsigned int &best_table,unsigned int &best_pixel_indices_MSB, unsigned int &best_pixel_indices_LSB) { int min_error = 3*255*255*16; int q; int err; unsigned int pixel_indices_MSB, pixel_indices_LSB; for(q=0;q<16;q+=2) // try all the 8 tables. { err=compressBlockWithTable4x2(img,width,height,startx,starty,avg_color,q,&pixel_indices_MSB, &pixel_indices_LSB); if(err> 1; } } return min_error; } // Find the best table to use for a 4x2 area by testing all. // Uses perceptual weighting. // Uses fixed point implementation where 1000 equals 1.0 // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int tryalltables_3bittable4x2percep1000(uint8 *img,int width,int height,int startx,int starty,uint8 *avg_color, unsigned int &best_table,unsigned int &best_pixel_indices_MSB, unsigned int &best_pixel_indices_LSB) { unsigned int min_error = MAXERR1000; int q; unsigned int err; unsigned int pixel_indices_MSB, pixel_indices_LSB; for(q=0;q<16;q+=2) // try all the 8 tables. { err=compressBlockWithTable4x2percep1000(img,width,height,startx,starty,avg_color,q,&pixel_indices_MSB, &pixel_indices_LSB); if(err> 1; } } return min_error; } // Find the best table to use for a 4x2 area by testing all. // Uses perceptual weighting. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. int tryalltables_3bittable4x2percep(uint8 *img,int width,int height,int startx,int starty,uint8 *avg_color, unsigned int &best_table,unsigned int &best_pixel_indices_MSB, unsigned int &best_pixel_indices_LSB) { float min_error = 3*255*255*16; int q; float err; unsigned int pixel_indices_MSB, pixel_indices_LSB; for(q=0;q<16;q+=2) // try all the 8 tables. { err=compressBlockWithTable4x2percep(img,width,height,startx,starty,avg_color,q,&pixel_indices_MSB, &pixel_indices_LSB); if(err> 1; } } return (int) min_error; } // The below code quantizes a float RGB value to RGB444. // // The format often allows a pixel to completely compensate an intensity error of the base // color. Hence the closest RGB444 point may not be the best, and the code below uses // this fact to find a better RGB444 color as the base color. // // (See the presentation http://www.jacobstrom.com/publications/PACKMAN.ppt for more info.) // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void quantize444ColorCombined(float *avg_col_in, int *enc_color, uint8 *avg_color) { float dr, dg, db; float kr, kg, kb; float wR2, wG2, wB2; uint8 low_color[3]; uint8 high_color[3]; float min_error=255*255*8*3; float lowhightable[8]; unsigned int best_table=0; unsigned int best_index=0; int q; float kval = (float) (255.0/15.0); // These are the values that we want to have: float red_average, green_average, blue_average; int red_4bit_low, green_4bit_low, blue_4bit_low; int red_4bit_high, green_4bit_high, blue_4bit_high; // These are the values that we approximate with: int red_low, green_low, blue_low; int red_high, green_high, blue_high; red_average = avg_col_in[0]; green_average = avg_col_in[1]; blue_average = avg_col_in[2]; // Find the 5-bit reconstruction levels red_low, red_high // so that red_average is in interval [red_low, red_high]. // (The same with green and blue.) red_4bit_low = (int) (red_average/kval); green_4bit_low = (int) (green_average/kval); blue_4bit_low = (int) (blue_average/kval); red_4bit_high = CLAMP(0, red_4bit_low + 1, 15); green_4bit_high = CLAMP(0, green_4bit_low + 1, 15); blue_4bit_high = CLAMP(0, blue_4bit_low + 1, 15); red_low = (red_4bit_low << 4) | (red_4bit_low >> 0); green_low = (green_4bit_low << 4) | (green_4bit_low >> 0); blue_low = (blue_4bit_low << 4) | (blue_4bit_low >> 0); red_high = (red_4bit_high << 4) | (red_4bit_high >> 0); green_high = (green_4bit_high << 4) | (green_4bit_high >> 0); blue_high = (blue_4bit_high << 4) | (blue_4bit_high >> 0); kr = (float)red_high - (float)red_low; kg = (float)green_high - (float)green_low; kb = (float)blue_high - (float)blue_low; // Note that dr, dg, and db are all negative. dr = red_low - red_average; dg = green_low - green_average; db = blue_low - blue_average; // Use straight (nonperceptive) weights. wR2 = (float) 1.0; wG2 = (float) 1.0; wB2 = (float) 1.0; lowhightable[0] = wR2*wG2*SQUARE( (dr+ 0) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+ 0) ); lowhightable[1] = wR2*wG2*SQUARE( (dr+kr) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+kr) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+ 0) ); lowhightable[2] = wR2*wG2*SQUARE( (dr+ 0) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+kg) - (db+ 0) ); lowhightable[3] = wR2*wG2*SQUARE( (dr+ 0) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+kb) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+kb) ); lowhightable[4] = wR2*wG2*SQUARE( (dr+kr) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+kr) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+kg) - (db+ 0) ); lowhightable[5] = wR2*wG2*SQUARE( (dr+kr) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+kr) - (db+kb) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+kb) ); lowhightable[6] = wR2*wG2*SQUARE( (dr+ 0) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+kb) ) + wG2*wB2*SQUARE( (dg+kg) - (db+kb) ); lowhightable[7] = wR2*wG2*SQUARE( (dr+kr) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+kr) - (db+kb) ) + wG2*wB2*SQUARE( (dg+kg) - (db+kb) ); float min_value = lowhightable[0]; int min_index = 0; for(q = 1; q<8; q++) { if(lowhightable[q] < min_value) { min_value = lowhightable[q]; min_index = q; } } float drh = red_high-red_average; float dgh = green_high-green_average; float dbh = blue_high-blue_average; low_color[0] = red_4bit_low; low_color[1] = green_4bit_low; low_color[2] = blue_4bit_low; high_color[0] = red_4bit_high; high_color[1] = green_4bit_high; high_color[2] = blue_4bit_high; switch(min_index) { case 0: // Since the step size is always 17 in RGB444 format (15*17=255), // kr = kg = kb = 17, which means that case 0 and case 7 will // always have equal projected error. Choose the one that is // closer to the desired color. if(dr*dr + dg*dg + db*db > 3*8*8) { enc_color[0] = high_color[0]; enc_color[1] = high_color[1]; enc_color[2] = high_color[2]; } else { enc_color[0] = low_color[0]; enc_color[1] = low_color[1]; enc_color[2] = low_color[2]; } break; case 1: enc_color[0] = high_color[0]; enc_color[1] = low_color[1]; enc_color[2] = low_color[2]; break; case 2: enc_color[0] = low_color[0]; enc_color[1] = high_color[1]; enc_color[2] = low_color[2]; break; case 3: enc_color[0] = low_color[0]; enc_color[1] = low_color[1]; enc_color[2] = high_color[2]; break; case 4: enc_color[0] = high_color[0]; enc_color[1] = high_color[1]; enc_color[2] = low_color[2]; break; case 5: enc_color[0] = high_color[0]; enc_color[1] = low_color[1]; enc_color[2] = high_color[2]; break; case 6: enc_color[0] = low_color[0]; enc_color[1] = high_color[1]; enc_color[2] = high_color[2]; break; case 7: if(dr*dr + dg*dg + db*db > 3*8*8) { enc_color[0] = high_color[0]; enc_color[1] = high_color[1]; enc_color[2] = high_color[2]; } else { enc_color[0] = low_color[0]; enc_color[1] = low_color[1]; enc_color[2] = low_color[2]; } break; } // Expand 5-bit encoded color to 8-bit color avg_color[0] = (enc_color[0] << 3) | (enc_color[0] >> 2); avg_color[1] = (enc_color[1] << 3) | (enc_color[1] >> 2); avg_color[2] = (enc_color[2] << 3) | (enc_color[2] >> 2); } // The below code quantizes a float RGB value to RGB555. // // The format often allows a pixel to completely compensate an intensity error of the base // color. Hence the closest RGB555 point may not be the best, and the code below uses // this fact to find a better RGB555 color as the base color. // // (See the presentation http://www.jacobstrom.com/publications/PACKMAN.ppt for more info.) // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void quantize555ColorCombined(float *avg_col_in, int *enc_color, uint8 *avg_color) { float dr, dg, db; float kr, kg, kb; float wR2, wG2, wB2; uint8 low_color[3]; uint8 high_color[3]; float min_error=255*255*8*3; float lowhightable[8]; unsigned int best_table=0; unsigned int best_index=0; int q; float kval = (float) (255.0/31.0); // These are the values that we want to have: float red_average, green_average, blue_average; int red_5bit_low, green_5bit_low, blue_5bit_low; int red_5bit_high, green_5bit_high, blue_5bit_high; // These are the values that we approximate with: int red_low, green_low, blue_low; int red_high, green_high, blue_high; red_average = avg_col_in[0]; green_average = avg_col_in[1]; blue_average = avg_col_in[2]; // Find the 5-bit reconstruction levels red_low, red_high // so that red_average is in interval [red_low, red_high]. // (The same with green and blue.) red_5bit_low = (int) (red_average/kval); green_5bit_low = (int) (green_average/kval); blue_5bit_low = (int) (blue_average/kval); red_5bit_high = CLAMP(0, red_5bit_low + 1, 31); green_5bit_high = CLAMP(0, green_5bit_low + 1, 31); blue_5bit_high = CLAMP(0, blue_5bit_low + 1, 31); red_low = (red_5bit_low << 3) | (red_5bit_low >> 2); green_low = (green_5bit_low << 3) | (green_5bit_low >> 2); blue_low = (blue_5bit_low << 3) | (blue_5bit_low >> 2); red_high = (red_5bit_high << 3) | (red_5bit_high >> 2); green_high = (green_5bit_high << 3) | (green_5bit_high >> 2); blue_high = (blue_5bit_high << 3) | (blue_5bit_high >> 2); kr = (float)red_high - (float)red_low; kg = (float)green_high - (float)green_low; kb = (float)blue_high - (float)blue_low; // Note that dr, dg, and db are all negative. dr = red_low - red_average; dg = green_low - green_average; db = blue_low - blue_average; // Use straight (nonperceptive) weights. wR2 = (float) 1.0; wG2 = (float) 1.0; wB2 = (float) 1.0; lowhightable[0] = wR2*wG2*SQUARE( (dr+ 0) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+ 0) ); lowhightable[1] = wR2*wG2*SQUARE( (dr+kr) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+kr) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+ 0) ); lowhightable[2] = wR2*wG2*SQUARE( (dr+ 0) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+kg) - (db+ 0) ); lowhightable[3] = wR2*wG2*SQUARE( (dr+ 0) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+kb) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+kb) ); lowhightable[4] = wR2*wG2*SQUARE( (dr+kr) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+kr) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+kg) - (db+ 0) ); lowhightable[5] = wR2*wG2*SQUARE( (dr+kr) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+kr) - (db+kb) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+kb) ); lowhightable[6] = wR2*wG2*SQUARE( (dr+ 0) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+kb) ) + wG2*wB2*SQUARE( (dg+kg) - (db+kb) ); lowhightable[7] = wR2*wG2*SQUARE( (dr+kr) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+kr) - (db+kb) ) + wG2*wB2*SQUARE( (dg+kg) - (db+kb) ); float min_value = lowhightable[0]; int min_index = 0; for(q = 1; q<8; q++) { if(lowhightable[q] < min_value) { min_value = lowhightable[q]; min_index = q; } } float drh = red_high-red_average; float dgh = green_high-green_average; float dbh = blue_high-blue_average; low_color[0] = red_5bit_low; low_color[1] = green_5bit_low; low_color[2] = blue_5bit_low; high_color[0] = red_5bit_high; high_color[1] = green_5bit_high; high_color[2] = blue_5bit_high; switch(min_index) { case 0: enc_color[0] = low_color[0]; enc_color[1] = low_color[1]; enc_color[2] = low_color[2]; break; case 1: enc_color[0] = high_color[0]; enc_color[1] = low_color[1]; enc_color[2] = low_color[2]; break; case 2: enc_color[0] = low_color[0]; enc_color[1] = high_color[1]; enc_color[2] = low_color[2]; break; case 3: enc_color[0] = low_color[0]; enc_color[1] = low_color[1]; enc_color[2] = high_color[2]; break; case 4: enc_color[0] = high_color[0]; enc_color[1] = high_color[1]; enc_color[2] = low_color[2]; break; case 5: enc_color[0] = high_color[0]; enc_color[1] = low_color[1]; enc_color[2] = high_color[2]; break; case 6: enc_color[0] = low_color[0]; enc_color[1] = high_color[1]; enc_color[2] = high_color[2]; break; case 7: enc_color[0] = high_color[0]; enc_color[1] = high_color[1]; enc_color[2] = high_color[2]; break; } // Expand 5-bit encoded color to 8-bit color avg_color[0] = (enc_color[0] << 3) | (enc_color[0] >> 2); avg_color[1] = (enc_color[1] << 3) | (enc_color[1] >> 2); avg_color[2] = (enc_color[2] << 3) | (enc_color[2] >> 2); } // The below code quantizes a float RGB value to RGB444. // // The format often allows a pixel to completely compensate an intensity error of the base // color. Hence the closest RGB444 point may not be the best, and the code below uses // this fact to find a better RGB444 color as the base color. // // (See the presentation http://www.jacobstrom.com/publications/PACKMAN.ppt for more info.) // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void quantize444ColorCombinedPerceptual(float *avg_col_in, int *enc_color, uint8 *avg_color) { float dr, dg, db; float kr, kg, kb; float wR2, wG2, wB2; uint8 low_color[3]; uint8 high_color[3]; float min_error=255*255*8*3; float lowhightable[8]; unsigned int best_table=0; unsigned int best_index=0; int q; float kval = (float) (255.0/15.0); // These are the values that we want to have: float red_average, green_average, blue_average; int red_4bit_low, green_4bit_low, blue_4bit_low; int red_4bit_high, green_4bit_high, blue_4bit_high; // These are the values that we approximate with: int red_low, green_low, blue_low; int red_high, green_high, blue_high; red_average = avg_col_in[0]; green_average = avg_col_in[1]; blue_average = avg_col_in[2]; // Find the 5-bit reconstruction levels red_low, red_high // so that red_average is in interval [red_low, red_high]. // (The same with green and blue.) red_4bit_low = (int) (red_average/kval); green_4bit_low = (int) (green_average/kval); blue_4bit_low = (int) (blue_average/kval); red_4bit_high = CLAMP(0, red_4bit_low + 1, 15); green_4bit_high = CLAMP(0, green_4bit_low + 1, 15); blue_4bit_high = CLAMP(0, blue_4bit_low + 1, 15); red_low = (red_4bit_low << 4) | (red_4bit_low >> 0); green_low = (green_4bit_low << 4) | (green_4bit_low >> 0); blue_low = (blue_4bit_low << 4) | (blue_4bit_low >> 0); red_high = (red_4bit_high << 4) | (red_4bit_high >> 0); green_high = (green_4bit_high << 4) | (green_4bit_high >> 0); blue_high = (blue_4bit_high << 4) | (blue_4bit_high >> 0); low_color[0] = red_4bit_low; low_color[1] = green_4bit_low; low_color[2] = blue_4bit_low; high_color[0] = red_4bit_high; high_color[1] = green_4bit_high; high_color[2] = blue_4bit_high; kr = (float)red_high - (float)red_low; kg = (float)green_high - (float)green_low; kb = (float)blue_high- (float)blue_low; // Note that dr, dg, and db are all negative. dr = red_low - red_average; dg = green_low - green_average; db = blue_low - blue_average; // Perceptual weights to use wR2 = (float) PERCEPTUAL_WEIGHT_R_SQUARED; wG2 = (float) PERCEPTUAL_WEIGHT_G_SQUARED; wB2 = (float) PERCEPTUAL_WEIGHT_B_SQUARED; lowhightable[0] = wR2*wG2*SQUARE( (dr+ 0) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+ 0) ); lowhightable[1] = wR2*wG2*SQUARE( (dr+kr) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+kr) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+ 0) ); lowhightable[2] = wR2*wG2*SQUARE( (dr+ 0) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+kg) - (db+ 0) ); lowhightable[3] = wR2*wG2*SQUARE( (dr+ 0) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+kb) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+kb) ); lowhightable[4] = wR2*wG2*SQUARE( (dr+kr) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+kr) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+kg) - (db+ 0) ); lowhightable[5] = wR2*wG2*SQUARE( (dr+kr) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+kr) - (db+kb) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+kb) ); lowhightable[6] = wR2*wG2*SQUARE( (dr+ 0) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+kb) ) + wG2*wB2*SQUARE( (dg+kg) - (db+kb) ); lowhightable[7] = wR2*wG2*SQUARE( (dr+kr) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+kr) - (db+kb) ) + wG2*wB2*SQUARE( (dg+kg) - (db+kb) ); float min_value = lowhightable[0]; int min_index = 0; for(q = 1; q<8; q++) { if(lowhightable[q] < min_value) { min_value = lowhightable[q]; min_index = q; } } float drh = red_high-red_average; float dgh = green_high-green_average; float dbh = blue_high-blue_average; switch(min_index) { case 0: enc_color[0] = low_color[0]; enc_color[1] = low_color[1]; enc_color[2] = low_color[2]; break; case 1: enc_color[0] = high_color[0]; enc_color[1] = low_color[1]; enc_color[2] = low_color[2]; break; case 2: enc_color[0] = low_color[0]; enc_color[1] = high_color[1]; enc_color[2] = low_color[2]; break; case 3: enc_color[0] = low_color[0]; enc_color[1] = low_color[1]; enc_color[2] = high_color[2]; break; case 4: enc_color[0] = high_color[0]; enc_color[1] = high_color[1]; enc_color[2] = low_color[2]; break; case 5: enc_color[0] = high_color[0]; enc_color[1] = low_color[1]; enc_color[2] = high_color[2]; break; case 6: enc_color[0] = low_color[0]; enc_color[1] = high_color[1]; enc_color[2] = high_color[2]; break; case 7: enc_color[0] = high_color[0]; enc_color[1] = high_color[1]; enc_color[2] = high_color[2]; break; } // Expand encoded color to eight bits avg_color[0] = (enc_color[0] << 4) | enc_color[0]; avg_color[1] = (enc_color[1] << 4) | enc_color[1]; avg_color[2] = (enc_color[2] << 4) | enc_color[2]; } // The below code quantizes a float RGB value to RGB555. // // The format often allows a pixel to completely compensate an intensity error of the base // color. Hence the closest RGB555 point may not be the best, and the code below uses // this fact to find a better RGB555 color as the base color. // // (See the presentation http://www.jacobstrom.com/publications/PACKMAN.ppt for more info.) // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void quantize555ColorCombinedPerceptual(float *avg_col_in, int *enc_color, uint8 *avg_color) { float dr, dg, db; float kr, kg, kb; float wR2, wG2, wB2; uint8 low_color[3]; uint8 high_color[3]; float min_error=255*255*8*3; float lowhightable[8]; unsigned int best_table=0; unsigned int best_index=0; int q; float kval = (float) (255.0/31.0); // These are the values that we want to have: float red_average, green_average, blue_average; int red_5bit_low, green_5bit_low, blue_5bit_low; int red_5bit_high, green_5bit_high, blue_5bit_high; // These are the values that we approximate with: int red_low, green_low, blue_low; int red_high, green_high, blue_high; red_average = avg_col_in[0]; green_average = avg_col_in[1]; blue_average = avg_col_in[2]; // Find the 5-bit reconstruction levels red_low, red_high // so that red_average is in interval [red_low, red_high]. // (The same with green and blue.) red_5bit_low = (int) (red_average/kval); green_5bit_low = (int) (green_average/kval); blue_5bit_low = (int) (blue_average/kval); red_5bit_high = CLAMP(0, red_5bit_low + 1, 31); green_5bit_high = CLAMP(0, green_5bit_low + 1, 31); blue_5bit_high = CLAMP(0, blue_5bit_low + 1, 31); red_low = (red_5bit_low << 3) | (red_5bit_low >> 2); green_low = (green_5bit_low << 3) | (green_5bit_low >> 2); blue_low = (blue_5bit_low << 3) | (blue_5bit_low >> 2); red_high = (red_5bit_high << 3) | (red_5bit_high >> 2); green_high = (green_5bit_high << 3) | (green_5bit_high >> 2); blue_high = (blue_5bit_high << 3) | (blue_5bit_high >> 2); low_color[0] = red_5bit_low; low_color[1] = green_5bit_low; low_color[2] = blue_5bit_low; high_color[0] = red_5bit_high; high_color[1] = green_5bit_high; high_color[2] = blue_5bit_high; kr = (float)red_high - (float)red_low; kg = (float)green_high - (float)green_low; kb = (float)blue_high - (float)blue_low; // Note that dr, dg, and db are all negative. dr = red_low - red_average; dg = green_low - green_average; db = blue_low - blue_average; // Perceptual weights to use wR2 = (float) PERCEPTUAL_WEIGHT_R_SQUARED; wG2 = (float) PERCEPTUAL_WEIGHT_G_SQUARED; wB2 = (float) PERCEPTUAL_WEIGHT_B_SQUARED; lowhightable[0] = wR2*wG2*SQUARE( (dr+ 0) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+ 0) ); lowhightable[1] = wR2*wG2*SQUARE( (dr+kr) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+kr) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+ 0) ); lowhightable[2] = wR2*wG2*SQUARE( (dr+ 0) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+kg) - (db+ 0) ); lowhightable[3] = wR2*wG2*SQUARE( (dr+ 0) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+kb) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+kb) ); lowhightable[4] = wR2*wG2*SQUARE( (dr+kr) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+kr) - (db+ 0) ) + wG2*wB2*SQUARE( (dg+kg) - (db+ 0) ); lowhightable[5] = wR2*wG2*SQUARE( (dr+kr) - (dg+ 0) ) + wR2*wB2*SQUARE( (dr+kr) - (db+kb) ) + wG2*wB2*SQUARE( (dg+ 0) - (db+kb) ); lowhightable[6] = wR2*wG2*SQUARE( (dr+ 0) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+ 0) - (db+kb) ) + wG2*wB2*SQUARE( (dg+kg) - (db+kb) ); lowhightable[7] = wR2*wG2*SQUARE( (dr+kr) - (dg+kg) ) + wR2*wB2*SQUARE( (dr+kr) - (db+kb) ) + wG2*wB2*SQUARE( (dg+kg) - (db+kb) ); float min_value = lowhightable[0]; int min_index = 0; for(q = 1; q<8; q++) { if(lowhightable[q] < min_value) { min_value = lowhightable[q]; min_index = q; } } float drh = red_high-red_average; float dgh = green_high-green_average; float dbh = blue_high-blue_average; switch(min_index) { case 0: enc_color[0] = low_color[0]; enc_color[1] = low_color[1]; enc_color[2] = low_color[2]; break; case 1: enc_color[0] = high_color[0]; enc_color[1] = low_color[1]; enc_color[2] = low_color[2]; break; case 2: enc_color[0] = low_color[0]; enc_color[1] = high_color[1]; enc_color[2] = low_color[2]; break; case 3: enc_color[0] = low_color[0]; enc_color[1] = low_color[1]; enc_color[2] = high_color[2]; break; case 4: enc_color[0] = high_color[0]; enc_color[1] = high_color[1]; enc_color[2] = low_color[2]; break; case 5: enc_color[0] = high_color[0]; enc_color[1] = low_color[1]; enc_color[2] = high_color[2]; break; case 6: enc_color[0] = low_color[0]; enc_color[1] = high_color[1]; enc_color[2] = high_color[2]; break; case 7: enc_color[0] = high_color[0]; enc_color[1] = high_color[1]; enc_color[2] = high_color[2]; break; } // Expand 5-bit encoded color to 8-bit color avg_color[0] = (enc_color[0] << 3) | (enc_color[0] >> 2); avg_color[1] = (enc_color[1] << 3) | (enc_color[1] >> 2); avg_color[2] = (enc_color[2] << 3) | (enc_color[2] >> 2); } // Compresses the block using only the individual mode in ETC1/ETC2 using the average color as the base color. // Uses a perceptual error metric. // Uses fixed point arithmetics where 1000 equals 1.0 // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int compressBlockOnlyIndividualAveragePerceptual1000(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2, int *best_enc_color1, int*best_enc_color2, int &best_flip, unsigned int &best_err_upper, unsigned int &best_err_lower, unsigned int &best_err_left, unsigned int &best_err_right, int *best_color_upper, int *best_color_lower, int *best_color_left, int *best_color_right) { unsigned int compressed1_norm, compressed2_norm; unsigned int compressed1_flip, compressed2_flip; uint8 avg_color_quant1[3], avg_color_quant2[3]; float avg_color_float1[3],avg_color_float2[3]; int enc_color1[3], enc_color2[3]; unsigned int best_table_indices1=0, best_table_indices2=0; unsigned int best_table1=0, best_table2=0; int diffbit; unsigned int norm_err=0; unsigned int flip_err=0; unsigned int best_err; // First try normal blocks 2x4: computeAverageColor2x4noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor2x4noQuantFloat(img,width,height,startx+2,starty,avg_color_float2); enc_color1[0] = int( JAS_ROUND(15.0*avg_color_float1[0]/255.0) ); enc_color1[1] = int( JAS_ROUND(15.0*avg_color_float1[1]/255.0) ); enc_color1[2] = int( JAS_ROUND(15.0*avg_color_float1[2]/255.0) ); enc_color2[0] = int( JAS_ROUND(15.0*avg_color_float2[0]/255.0) ); enc_color2[1] = int( JAS_ROUND(15.0*avg_color_float2[1]/255.0) ); enc_color2[2] = int( JAS_ROUND(15.0*avg_color_float2[2]/255.0) ); diffbit = 0; avg_color_quant1[0] = enc_color1[0] << 4 | (enc_color1[0] ); avg_color_quant1[1] = enc_color1[1] << 4 | (enc_color1[1] ); avg_color_quant1[2] = enc_color1[2] << 4 | (enc_color1[2] ); avg_color_quant2[0] = enc_color2[0] << 4 | (enc_color2[0] ); avg_color_quant2[1] = enc_color2[1] << 4 | (enc_color2[1] ); avg_color_quant2[2] = enc_color2[2] << 4 | (enc_color2[2] ); // Pack bits into the first word. // ETC1_RGB8_OES: // // a) bit layout in bits 63 through 32 if diffbit = 0 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // b) bit layout in bits 63 through 32 if diffbit = 1 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |diff|flip| // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // c) bit layout in bits 31 through 0 (in both cases) // // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 // -------------------------------------------------------------------------------------------------- // | most significant pixel index bits | least significant pixel index bits | // | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | // -------------------------------------------------------------------------------------------------- compressed1_norm = 0; PUTBITSHIGH( compressed1_norm, diffbit, 1, 33); PUTBITSHIGH( compressed1_norm, enc_color1[0], 4, 63); PUTBITSHIGH( compressed1_norm, enc_color1[1], 4, 55); PUTBITSHIGH( compressed1_norm, enc_color1[2], 4, 47); PUTBITSHIGH( compressed1_norm, enc_color2[0], 4, 59); PUTBITSHIGH( compressed1_norm, enc_color2[1], 4, 51); PUTBITSHIGH( compressed1_norm, enc_color2[1], 4, 43); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; best_enc_color1[0] = enc_color1[0]; best_enc_color1[1] = enc_color1[1]; best_enc_color1[2] = enc_color1[2]; best_enc_color2[0] = enc_color2[0]; best_enc_color2[1] = enc_color2[1]; best_enc_color2[2] = enc_color2[2]; best_color_left[0] = enc_color1[0]; best_color_left[1] = enc_color1[1]; best_color_left[2] = enc_color1[2]; best_color_right[0] = enc_color2[0]; best_color_right[1] = enc_color2[1]; best_color_right[2] = enc_color2[2]; norm_err = 0; // left part of block best_err_left = tryalltables_3bittable2x4percep1000(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); norm_err = best_err_left; // right part of block best_err_right = tryalltables_3bittable2x4percep1000(img,width,height,startx+2,starty,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); norm_err += best_err_right; PUTBITSHIGH( compressed1_norm, best_table1, 3, 39); PUTBITSHIGH( compressed1_norm, best_table2, 3, 36); PUTBITSHIGH( compressed1_norm, 0, 1, 32); compressed2_norm = 0; PUTBITS( compressed2_norm, (best_pixel_indices1_MSB ), 8, 23); PUTBITS( compressed2_norm, (best_pixel_indices2_MSB ), 8, 31); PUTBITS( compressed2_norm, (best_pixel_indices1_LSB ), 8, 7); PUTBITS( compressed2_norm, (best_pixel_indices2_LSB ), 8, 15); // Now try flipped blocks 4x2: computeAverageColor4x2noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor4x2noQuantFloat(img,width,height,startx,starty+2,avg_color_float2); // First test if avg_color1 is similar enough to avg_color2 so that // we can use differential coding of colors. enc_color1[0] = int( JAS_ROUND(15.0*avg_color_float1[0]/255.0) ); enc_color1[1] = int( JAS_ROUND(15.0*avg_color_float1[1]/255.0) ); enc_color1[2] = int( JAS_ROUND(15.0*avg_color_float1[2]/255.0) ); enc_color2[0] = int( JAS_ROUND(15.0*avg_color_float2[0]/255.0) ); enc_color2[1] = int( JAS_ROUND(15.0*avg_color_float2[1]/255.0) ); enc_color2[2] = int( JAS_ROUND(15.0*avg_color_float2[2]/255.0) ); best_color_upper[0] = enc_color1[0]; best_color_upper[1] = enc_color1[1]; best_color_upper[2] = enc_color1[2]; best_color_lower[0] = enc_color2[0]; best_color_lower[1] = enc_color2[1]; best_color_lower[2] = enc_color2[2]; diffbit = 0; avg_color_quant1[0] = enc_color1[0] << 4 | (enc_color1[0] ); avg_color_quant1[1] = enc_color1[1] << 4 | (enc_color1[1] ); avg_color_quant1[2] = enc_color1[2] << 4 | (enc_color1[2] ); avg_color_quant2[0] = enc_color2[0] << 4 | (enc_color2[0] ); avg_color_quant2[1] = enc_color2[1] << 4 | (enc_color2[1] ); avg_color_quant2[2] = enc_color2[2] << 4 | (enc_color2[2] ); // Pack bits into the first word. compressed1_flip = 0; PUTBITSHIGH( compressed1_flip, diffbit, 1, 33); PUTBITSHIGH( compressed1_flip, enc_color1[0], 4, 63); PUTBITSHIGH( compressed1_flip, enc_color1[1], 4, 55); PUTBITSHIGH( compressed1_flip, enc_color1[2], 4, 47); PUTBITSHIGH( compressed1_flip, enc_color2[0], 4, 49); PUTBITSHIGH( compressed1_flip, enc_color2[1], 4, 51); PUTBITSHIGH( compressed1_flip, enc_color2[2], 4, 43); // upper part of block best_err_upper = tryalltables_3bittable4x2percep1000(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); flip_err = best_err_upper; // lower part of block best_err_lower = tryalltables_3bittable4x2percep1000(img,width,height,startx,starty+2,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); flip_err += best_err_lower; PUTBITSHIGH( compressed1_flip, best_table1, 3, 39); PUTBITSHIGH( compressed1_flip, best_table2, 3, 36); PUTBITSHIGH( compressed1_flip, 1, 1, 32); best_pixel_indices1_MSB |= (best_pixel_indices2_MSB << 2); best_pixel_indices1_LSB |= (best_pixel_indices2_LSB << 2); compressed2_flip = ((best_pixel_indices1_MSB & 0xffff) << 16) | (best_pixel_indices1_LSB & 0xffff); // Now lets see which is the best table to use. Only 8 tables are possible. if(norm_err <= flip_err) { compressed1 = compressed1_norm | 0; compressed2 = compressed2_norm; best_err = norm_err; best_flip = 0; } else { compressed1 = compressed1_flip | 1; compressed2 = compressed2_flip; best_err = flip_err; best_enc_color1[0] = enc_color1[0]; best_enc_color1[1] = enc_color1[1]; best_enc_color1[2] = enc_color1[2]; best_enc_color2[0] = enc_color2[0]; best_enc_color2[1] = enc_color2[1]; best_enc_color2[2] = enc_color2[2]; best_flip = 1; } return best_err; } // Compresses the block using only the individual mode in ETC1/ETC2 using the average color as the base color. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. int compressBlockOnlyIndividualAverage(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2, int *best_enc_color1, int*best_enc_color2, int &best_flip, unsigned int &best_err_upper, unsigned int &best_err_lower, unsigned int &best_err_left, unsigned int &best_err_right, int *best_color_upper, int *best_color_lower, int *best_color_left, int *best_color_right) { unsigned int compressed1_norm, compressed2_norm; unsigned int compressed1_flip, compressed2_flip; uint8 avg_color_quant1[3], avg_color_quant2[3]; float avg_color_float1[3],avg_color_float2[3]; int enc_color1[3], enc_color2[3]; int min_error=255*255*8*3; unsigned int best_table_indices1=0, best_table_indices2=0; unsigned int best_table1=0, best_table2=0; int diffbit; int norm_err=0; int flip_err=0; int best_err; // First try normal blocks 2x4: computeAverageColor2x4noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor2x4noQuantFloat(img,width,height,startx+2,starty,avg_color_float2); enc_color1[0] = int( JAS_ROUND(15.0*avg_color_float1[0]/255.0) ); enc_color1[1] = int( JAS_ROUND(15.0*avg_color_float1[1]/255.0) ); enc_color1[2] = int( JAS_ROUND(15.0*avg_color_float1[2]/255.0) ); enc_color2[0] = int( JAS_ROUND(15.0*avg_color_float2[0]/255.0) ); enc_color2[1] = int( JAS_ROUND(15.0*avg_color_float2[1]/255.0) ); enc_color2[2] = int( JAS_ROUND(15.0*avg_color_float2[2]/255.0) ); diffbit = 0; avg_color_quant1[0] = enc_color1[0] << 4 | (enc_color1[0] ); avg_color_quant1[1] = enc_color1[1] << 4 | (enc_color1[1] ); avg_color_quant1[2] = enc_color1[2] << 4 | (enc_color1[2] ); avg_color_quant2[0] = enc_color2[0] << 4 | (enc_color2[0] ); avg_color_quant2[1] = enc_color2[1] << 4 | (enc_color2[1] ); avg_color_quant2[2] = enc_color2[2] << 4 | (enc_color2[2] ); // Pack bits into the first word. // ETC1_RGB8_OES: // // a) bit layout in bits 63 through 32 if diffbit = 0 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // b) bit layout in bits 63 through 32 if diffbit = 1 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |diff|flip| // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // c) bit layout in bits 31 through 0 (in both cases) // // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 // -------------------------------------------------------------------------------------------------- // | most significant pixel index bits | least significant pixel index bits | // | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | // -------------------------------------------------------------------------------------------------- compressed1_norm = 0; PUTBITSHIGH( compressed1_norm, diffbit, 1, 33); PUTBITSHIGH( compressed1_norm, enc_color1[0], 4, 63); PUTBITSHIGH( compressed1_norm, enc_color1[1], 4, 55); PUTBITSHIGH( compressed1_norm, enc_color1[2], 4, 47); PUTBITSHIGH( compressed1_norm, enc_color2[0], 4, 59); PUTBITSHIGH( compressed1_norm, enc_color2[1], 4, 51); PUTBITSHIGH( compressed1_norm, enc_color2[1], 4, 43); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; best_enc_color1[0] = enc_color1[0]; best_enc_color1[1] = enc_color1[1]; best_enc_color1[2] = enc_color1[2]; best_enc_color2[0] = enc_color2[0]; best_enc_color2[1] = enc_color2[1]; best_enc_color2[2] = enc_color2[2]; best_color_left[0] = enc_color1[0]; best_color_left[1] = enc_color1[1]; best_color_left[2] = enc_color1[2]; best_color_right[0] = enc_color2[0]; best_color_right[1] = enc_color2[1]; best_color_right[2] = enc_color2[2]; norm_err = 0; // left part of block best_err_left = tryalltables_3bittable2x4(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); norm_err = best_err_left; // right part of block best_err_right = tryalltables_3bittable2x4(img,width,height,startx+2,starty,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); norm_err += best_err_right; PUTBITSHIGH( compressed1_norm, best_table1, 3, 39); PUTBITSHIGH( compressed1_norm, best_table2, 3, 36); PUTBITSHIGH( compressed1_norm, 0, 1, 32); compressed2_norm = 0; PUTBITS( compressed2_norm, (best_pixel_indices1_MSB ), 8, 23); PUTBITS( compressed2_norm, (best_pixel_indices2_MSB ), 8, 31); PUTBITS( compressed2_norm, (best_pixel_indices1_LSB ), 8, 7); PUTBITS( compressed2_norm, (best_pixel_indices2_LSB ), 8, 15); // Now try flipped blocks 4x2: computeAverageColor4x2noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor4x2noQuantFloat(img,width,height,startx,starty+2,avg_color_float2); // First test if avg_color1 is similar enough to avg_color2 so that // we can use differential coding of colors. enc_color1[0] = int( JAS_ROUND(15.0*avg_color_float1[0]/255.0) ); enc_color1[1] = int( JAS_ROUND(15.0*avg_color_float1[1]/255.0) ); enc_color1[2] = int( JAS_ROUND(15.0*avg_color_float1[2]/255.0) ); enc_color2[0] = int( JAS_ROUND(15.0*avg_color_float2[0]/255.0) ); enc_color2[1] = int( JAS_ROUND(15.0*avg_color_float2[1]/255.0) ); enc_color2[2] = int( JAS_ROUND(15.0*avg_color_float2[2]/255.0) ); best_color_upper[0] = enc_color1[0]; best_color_upper[1] = enc_color1[1]; best_color_upper[2] = enc_color1[2]; best_color_lower[0] = enc_color2[0]; best_color_lower[1] = enc_color2[1]; best_color_lower[2] = enc_color2[2]; diffbit = 0; avg_color_quant1[0] = enc_color1[0] << 4 | (enc_color1[0] ); avg_color_quant1[1] = enc_color1[1] << 4 | (enc_color1[1] ); avg_color_quant1[2] = enc_color1[2] << 4 | (enc_color1[2] ); avg_color_quant2[0] = enc_color2[0] << 4 | (enc_color2[0] ); avg_color_quant2[1] = enc_color2[1] << 4 | (enc_color2[1] ); avg_color_quant2[2] = enc_color2[2] << 4 | (enc_color2[2] ); // Pack bits into the first word. compressed1_flip = 0; PUTBITSHIGH( compressed1_flip, diffbit, 1, 33); PUTBITSHIGH( compressed1_flip, enc_color1[0], 4, 63); PUTBITSHIGH( compressed1_flip, enc_color1[1], 4, 55); PUTBITSHIGH( compressed1_flip, enc_color1[2], 4, 47); PUTBITSHIGH( compressed1_flip, enc_color2[0], 4, 49); PUTBITSHIGH( compressed1_flip, enc_color2[1], 4, 51); PUTBITSHIGH( compressed1_flip, enc_color2[2], 4, 43); // upper part of block best_err_upper = tryalltables_3bittable4x2(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); flip_err = best_err_upper; // lower part of block best_err_lower = tryalltables_3bittable4x2(img,width,height,startx,starty+2,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); flip_err += best_err_lower; PUTBITSHIGH( compressed1_flip, best_table1, 3, 39); PUTBITSHIGH( compressed1_flip, best_table2, 3, 36); PUTBITSHIGH( compressed1_flip, 1, 1, 32); best_pixel_indices1_MSB |= (best_pixel_indices2_MSB << 2); best_pixel_indices1_LSB |= (best_pixel_indices2_LSB << 2); compressed2_flip = ((best_pixel_indices1_MSB & 0xffff) << 16) | (best_pixel_indices1_LSB & 0xffff); // Now lets see which is the best table to use. Only 8 tables are possible. if(norm_err <= flip_err) { compressed1 = compressed1_norm | 0; compressed2 = compressed2_norm; best_err = norm_err; best_flip = 0; } else { compressed1 = compressed1_flip | 1; compressed2 = compressed2_flip; best_err = flip_err; best_enc_color1[0] = enc_color1[0]; best_enc_color1[1] = enc_color1[1]; best_enc_color1[2] = enc_color1[2]; best_enc_color2[0] = enc_color2[0]; best_enc_color2[1] = enc_color2[1]; best_enc_color2[2] = enc_color2[2]; best_flip = 1; } return best_err; } // Compresses the block using either the individual or differential mode in ETC1/ETC2 // Uses the average color as the base color in each half-block. // Tries both flipped and unflipped. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressBlockDiffFlipAverage(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { unsigned int compressed1_norm, compressed2_norm; unsigned int compressed1_flip, compressed2_flip; uint8 avg_color_quant1[3], avg_color_quant2[3]; float avg_color_float1[3],avg_color_float2[3]; int enc_color1[3], enc_color2[3], diff[3]; int min_error=255*255*8*3; unsigned int best_table_indices1=0, best_table_indices2=0; unsigned int best_table1=0, best_table2=0; int diffbit; int norm_err=0; int flip_err=0; // First try normal blocks 2x4: computeAverageColor2x4noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor2x4noQuantFloat(img,width,height,startx+2,starty,avg_color_float2); // First test if avg_color1 is similar enough to avg_color2 so that // we can use differential coding of colors. float eps; enc_color1[0] = int( JAS_ROUND(31.0*avg_color_float1[0]/255.0) ); enc_color1[1] = int( JAS_ROUND(31.0*avg_color_float1[1]/255.0) ); enc_color1[2] = int( JAS_ROUND(31.0*avg_color_float1[2]/255.0) ); enc_color2[0] = int( JAS_ROUND(31.0*avg_color_float2[0]/255.0) ); enc_color2[1] = int( JAS_ROUND(31.0*avg_color_float2[1]/255.0) ); enc_color2[2] = int( JAS_ROUND(31.0*avg_color_float2[2]/255.0) ); diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; if( (diff[0] >= -4) && (diff[0] <= 3) && (diff[1] >= -4) && (diff[1] <= 3) && (diff[2] >= -4) && (diff[2] <= 3) ) { diffbit = 1; // The difference to be coded: diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; avg_color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); avg_color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); avg_color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); avg_color_quant2[0] = enc_color2[0] << 3 | (enc_color2[0] >> 2); avg_color_quant2[1] = enc_color2[1] << 3 | (enc_color2[1] >> 2); avg_color_quant2[2] = enc_color2[2] << 3 | (enc_color2[2] >> 2); // Pack bits into the first word. // ETC1_RGB8_OES: // // a) bit layout in bits 63 through 32 if diffbit = 0 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // b) bit layout in bits 63 through 32 if diffbit = 1 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |diff|flip| // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // c) bit layout in bits 31 through 0 (in both cases) // // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 // -------------------------------------------------------------------------------------------------- // | most significant pixel index bits | least significant pixel index bits | // | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | // -------------------------------------------------------------------------------------------------- compressed1_norm = 0; PUTBITSHIGH( compressed1_norm, diffbit, 1, 33); PUTBITSHIGH( compressed1_norm, enc_color1[0], 5, 63); PUTBITSHIGH( compressed1_norm, enc_color1[1], 5, 55); PUTBITSHIGH( compressed1_norm, enc_color1[2], 5, 47); PUTBITSHIGH( compressed1_norm, diff[0], 3, 58); PUTBITSHIGH( compressed1_norm, diff[1], 3, 50); PUTBITSHIGH( compressed1_norm, diff[2], 3, 42); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; norm_err = 0; // left part of block norm_err = tryalltables_3bittable2x4(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // right part of block norm_err += tryalltables_3bittable2x4(img,width,height,startx+2,starty,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_norm, best_table1, 3, 39); PUTBITSHIGH( compressed1_norm, best_table2, 3, 36); PUTBITSHIGH( compressed1_norm, 0, 1, 32); compressed2_norm = 0; PUTBITS( compressed2_norm, (best_pixel_indices1_MSB ), 8, 23); PUTBITS( compressed2_norm, (best_pixel_indices2_MSB ), 8, 31); PUTBITS( compressed2_norm, (best_pixel_indices1_LSB ), 8, 7); PUTBITS( compressed2_norm, (best_pixel_indices2_LSB ), 8, 15); } else { diffbit = 0; // The difference is bigger than what fits in 555 plus delta-333, so we will have // to deal with 444 444. eps = (float) 0.0001; enc_color1[0] = int( ((float) avg_color_float1[0] / (17.0)) +0.5 + eps); enc_color1[1] = int( ((float) avg_color_float1[1] / (17.0)) +0.5 + eps); enc_color1[2] = int( ((float) avg_color_float1[2] / (17.0)) +0.5 + eps); enc_color2[0] = int( ((float) avg_color_float2[0] / (17.0)) +0.5 + eps); enc_color2[1] = int( ((float) avg_color_float2[1] / (17.0)) +0.5 + eps); enc_color2[2] = int( ((float) avg_color_float2[2] / (17.0)) +0.5 + eps); avg_color_quant1[0] = enc_color1[0] << 4 | enc_color1[0]; avg_color_quant1[1] = enc_color1[1] << 4 | enc_color1[1]; avg_color_quant1[2] = enc_color1[2] << 4 | enc_color1[2]; avg_color_quant2[0] = enc_color2[0] << 4 | enc_color2[0]; avg_color_quant2[1] = enc_color2[1] << 4 | enc_color2[1]; avg_color_quant2[2] = enc_color2[2] << 4 | enc_color2[2]; // Pack bits into the first word. // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- compressed1_norm = 0; PUTBITSHIGH( compressed1_norm, diffbit, 1, 33); PUTBITSHIGH( compressed1_norm, enc_color1[0], 4, 63); PUTBITSHIGH( compressed1_norm, enc_color1[1], 4, 55); PUTBITSHIGH( compressed1_norm, enc_color1[2], 4, 47); PUTBITSHIGH( compressed1_norm, enc_color2[0], 4, 59); PUTBITSHIGH( compressed1_norm, enc_color2[1], 4, 51); PUTBITSHIGH( compressed1_norm, enc_color2[2], 4, 43); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; // left part of block norm_err = tryalltables_3bittable2x4(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // right part of block norm_err += tryalltables_3bittable2x4(img,width,height,startx+2,starty,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_norm, best_table1, 3, 39); PUTBITSHIGH( compressed1_norm, best_table2, 3, 36); PUTBITSHIGH( compressed1_norm, 0, 1, 32); compressed2_norm = 0; PUTBITS( compressed2_norm, (best_pixel_indices1_MSB ), 8, 23); PUTBITS( compressed2_norm, (best_pixel_indices2_MSB ), 8, 31); PUTBITS( compressed2_norm, (best_pixel_indices1_LSB ), 8, 7); PUTBITS( compressed2_norm, (best_pixel_indices2_LSB ), 8, 15); } // Now try flipped blocks 4x2: computeAverageColor4x2noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor4x2noQuantFloat(img,width,height,startx,starty+2,avg_color_float2); // First test if avg_color1 is similar enough to avg_color2 so that // we can use differential coding of colors. enc_color1[0] = int( JAS_ROUND(31.0*avg_color_float1[0]/255.0) ); enc_color1[1] = int( JAS_ROUND(31.0*avg_color_float1[1]/255.0) ); enc_color1[2] = int( JAS_ROUND(31.0*avg_color_float1[2]/255.0) ); enc_color2[0] = int( JAS_ROUND(31.0*avg_color_float2[0]/255.0) ); enc_color2[1] = int( JAS_ROUND(31.0*avg_color_float2[1]/255.0) ); enc_color2[2] = int( JAS_ROUND(31.0*avg_color_float2[2]/255.0) ); diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; if( (diff[0] >= -4) && (diff[0] <= 3) && (diff[1] >= -4) && (diff[1] <= 3) && (diff[2] >= -4) && (diff[2] <= 3) ) { diffbit = 1; // The difference to be coded: diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; avg_color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); avg_color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); avg_color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); avg_color_quant2[0] = enc_color2[0] << 3 | (enc_color2[0] >> 2); avg_color_quant2[1] = enc_color2[1] << 3 | (enc_color2[1] >> 2); avg_color_quant2[2] = enc_color2[2] << 3 | (enc_color2[2] >> 2); // Pack bits into the first word. compressed1_flip = 0; PUTBITSHIGH( compressed1_flip, diffbit, 1, 33); PUTBITSHIGH( compressed1_flip, enc_color1[0], 5, 63); PUTBITSHIGH( compressed1_flip, enc_color1[1], 5, 55); PUTBITSHIGH( compressed1_flip, enc_color1[2], 5, 47); PUTBITSHIGH( compressed1_flip, diff[0], 3, 58); PUTBITSHIGH( compressed1_flip, diff[1], 3, 50); PUTBITSHIGH( compressed1_flip, diff[2], 3, 42); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; // upper part of block flip_err = tryalltables_3bittable4x2(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // lower part of block flip_err += tryalltables_3bittable4x2(img,width,height,startx,starty+2,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_flip, best_table1, 3, 39); PUTBITSHIGH( compressed1_flip, best_table2, 3, 36); PUTBITSHIGH( compressed1_flip, 1, 1, 32); best_pixel_indices1_MSB |= (best_pixel_indices2_MSB << 2); best_pixel_indices1_LSB |= (best_pixel_indices2_LSB << 2); compressed2_flip = ((best_pixel_indices1_MSB & 0xffff) << 16) | (best_pixel_indices1_LSB & 0xffff); } else { diffbit = 0; // The difference is bigger than what fits in 555 plus delta-333, so we will have // to deal with 444 444. eps = (float) 0.0001; enc_color1[0] = int( ((float) avg_color_float1[0] / (17.0)) +0.5 + eps); enc_color1[1] = int( ((float) avg_color_float1[1] / (17.0)) +0.5 + eps); enc_color1[2] = int( ((float) avg_color_float1[2] / (17.0)) +0.5 + eps); enc_color2[0] = int( ((float) avg_color_float2[0] / (17.0)) +0.5 + eps); enc_color2[1] = int( ((float) avg_color_float2[1] / (17.0)) +0.5 + eps); enc_color2[2] = int( ((float) avg_color_float2[2] / (17.0)) +0.5 + eps); avg_color_quant1[0] = enc_color1[0] << 4 | enc_color1[0]; avg_color_quant1[1] = enc_color1[1] << 4 | enc_color1[1]; avg_color_quant1[2] = enc_color1[2] << 4 | enc_color1[2]; avg_color_quant2[0] = enc_color2[0] << 4 | enc_color2[0]; avg_color_quant2[1] = enc_color2[1] << 4 | enc_color2[1]; avg_color_quant2[2] = enc_color2[2] << 4 | enc_color2[2]; // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // Pack bits into the first word. compressed1_flip = 0; PUTBITSHIGH( compressed1_flip, diffbit, 1, 33); PUTBITSHIGH( compressed1_flip, enc_color1[0], 4, 63); PUTBITSHIGH( compressed1_flip, enc_color1[1], 4, 55); PUTBITSHIGH( compressed1_flip, enc_color1[2], 4, 47); PUTBITSHIGH( compressed1_flip, enc_color2[0], 4, 59); PUTBITSHIGH( compressed1_flip, enc_color2[1], 4, 51); PUTBITSHIGH( compressed1_flip, enc_color2[2], 4, 43); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; // upper part of block flip_err = tryalltables_3bittable4x2(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // lower part of block flip_err += tryalltables_3bittable4x2(img,width,height,startx,starty+2,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_flip, best_table1, 3, 39); PUTBITSHIGH( compressed1_flip, best_table2, 3, 36); PUTBITSHIGH( compressed1_flip, 1, 1, 32); best_pixel_indices1_MSB |= (best_pixel_indices2_MSB << 2); best_pixel_indices1_LSB |= (best_pixel_indices2_LSB << 2); compressed2_flip = ((best_pixel_indices1_MSB & 0xffff) << 16) | (best_pixel_indices1_LSB & 0xffff); } // Now lets see which is the best table to use. Only 8 tables are possible. if(norm_err <= flip_err) { compressed1 = compressed1_norm | 0; compressed2 = compressed2_norm; } else { compressed1 = compressed1_flip | 1; compressed2 = compressed2_flip; } } // Compresses the block using only the differential mode in ETC1/ETC2 // Uses the average color as the base color in each half-block. // If average colors are too different, use the average color of the entire block in both half-blocks. // Tries both flipped and unflipped. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. int compressBlockOnlyDiffFlipAverage(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2, int *best_enc_color1, int*best_enc_color2, int &best_flip) { unsigned int compressed1_norm, compressed2_norm; unsigned int compressed1_flip, compressed2_flip; uint8 avg_color_quant1[3], avg_color_quant2[3]; float avg_color_float1[3],avg_color_float2[3]; int enc_color1[3], enc_color2[3], diff[3]; int min_error=255*255*8*3; unsigned int best_table_indices1=0, best_table_indices2=0; unsigned int best_table1=0, best_table2=0; int diffbit; int norm_err=0; int flip_err=0; int best_err; // First try normal blocks 2x4: computeAverageColor2x4noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor2x4noQuantFloat(img,width,height,startx+2,starty,avg_color_float2); // First test if avg_color1 is similar enough to avg_color2 so that // we can use differential coding of colors. enc_color1[0] = int( JAS_ROUND(31.0*avg_color_float1[0]/255.0) ); enc_color1[1] = int( JAS_ROUND(31.0*avg_color_float1[1]/255.0) ); enc_color1[2] = int( JAS_ROUND(31.0*avg_color_float1[2]/255.0) ); enc_color2[0] = int( JAS_ROUND(31.0*avg_color_float2[0]/255.0) ); enc_color2[1] = int( JAS_ROUND(31.0*avg_color_float2[1]/255.0) ); enc_color2[2] = int( JAS_ROUND(31.0*avg_color_float2[2]/255.0) ); diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; if( !((diff[0] >= -4) && (diff[0] <= 3) && (diff[1] >= -4) && (diff[1] <= 3) && (diff[2] >= -4) && (diff[2] <= 3)) ) { // The colors are too different. Use the same color in both blocks. enc_color1[0] = int( JAS_ROUND(31.0*((avg_color_float1[0]+avg_color_float2[0])/2.0)/255.0) ); enc_color1[1] = int( JAS_ROUND(31.0*((avg_color_float1[1]+avg_color_float2[1])/2.0)/255.0) ); enc_color1[2] = int( JAS_ROUND(31.0*((avg_color_float1[2]+avg_color_float2[2])/2.0)/255.0) ); enc_color2[0] = enc_color1[0]; enc_color2[1] = enc_color1[1]; enc_color2[2] = enc_color1[2]; diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; } diffbit = 1; // The difference to be coded: diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; avg_color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); avg_color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); avg_color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); avg_color_quant2[0] = enc_color2[0] << 3 | (enc_color2[0] >> 2); avg_color_quant2[1] = enc_color2[1] << 3 | (enc_color2[1] >> 2); avg_color_quant2[2] = enc_color2[2] << 3 | (enc_color2[2] >> 2); // Pack bits into the first word. // ETC1_RGB8_OES: // // a) bit layout in bits 63 through 32 if diffbit = 0 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // b) bit layout in bits 63 through 32 if diffbit = 1 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |diff|flip| // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // c) bit layout in bits 31 through 0 (in both cases) // // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 // -------------------------------------------------------------------------------------------------- // | most significant pixel index bits | least significant pixel index bits | // | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | // -------------------------------------------------------------------------------------------------- compressed1_norm = 0; PUTBITSHIGH( compressed1_norm, diffbit, 1, 33); PUTBITSHIGH( compressed1_norm, enc_color1[0], 5, 63); PUTBITSHIGH( compressed1_norm, enc_color1[1], 5, 55); PUTBITSHIGH( compressed1_norm, enc_color1[2], 5, 47); PUTBITSHIGH( compressed1_norm, diff[0], 3, 58); PUTBITSHIGH( compressed1_norm, diff[1], 3, 50); PUTBITSHIGH( compressed1_norm, diff[2], 3, 42); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; best_enc_color1[0] = enc_color1[0]; best_enc_color1[1] = enc_color1[1]; best_enc_color1[2] = enc_color1[2]; best_enc_color2[0] = enc_color2[0]; best_enc_color2[1] = enc_color2[1]; best_enc_color2[2] = enc_color2[2]; norm_err = 0; // left part of block norm_err = tryalltables_3bittable2x4(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // right part of block norm_err += tryalltables_3bittable2x4(img,width,height,startx+2,starty,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_norm, best_table1, 3, 39); PUTBITSHIGH( compressed1_norm, best_table2, 3, 36); PUTBITSHIGH( compressed1_norm, 0, 1, 32); compressed2_norm = 0; PUTBITS( compressed2_norm, (best_pixel_indices1_MSB ), 8, 23); PUTBITS( compressed2_norm, (best_pixel_indices2_MSB ), 8, 31); PUTBITS( compressed2_norm, (best_pixel_indices1_LSB ), 8, 7); PUTBITS( compressed2_norm, (best_pixel_indices2_LSB ), 8, 15); // Now try flipped blocks 4x2: computeAverageColor4x2noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor4x2noQuantFloat(img,width,height,startx,starty+2,avg_color_float2); // First test if avg_color1 is similar enough to avg_color2 so that // we can use differential coding of colors. enc_color1[0] = int( JAS_ROUND(31.0*avg_color_float1[0]/255.0) ); enc_color1[1] = int( JAS_ROUND(31.0*avg_color_float1[1]/255.0) ); enc_color1[2] = int( JAS_ROUND(31.0*avg_color_float1[2]/255.0) ); enc_color2[0] = int( JAS_ROUND(31.0*avg_color_float2[0]/255.0) ); enc_color2[1] = int( JAS_ROUND(31.0*avg_color_float2[1]/255.0) ); enc_color2[2] = int( JAS_ROUND(31.0*avg_color_float2[2]/255.0) ); diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; if( !((diff[0] >= -4) && (diff[0] <= 3) && (diff[1] >= -4) && (diff[1] <= 3) && (diff[2] >= -4) && (diff[2] <= 3)) ) { // The colors are too different. Use the same color in both blocks. enc_color1[0] = int( JAS_ROUND(31.0*((avg_color_float1[0]+avg_color_float2[0])/2.0)/255.0) ); enc_color1[1] = int( JAS_ROUND(31.0*((avg_color_float1[1]+avg_color_float2[1])/2.0)/255.0) ); enc_color1[2] = int( JAS_ROUND(31.0*((avg_color_float1[2]+avg_color_float2[2])/2.0)/255.0) ); enc_color2[0] = enc_color1[0]; enc_color2[1] = enc_color1[1]; enc_color2[2] = enc_color1[2]; diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; } diffbit = 1; // The difference to be coded: diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; avg_color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); avg_color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); avg_color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); avg_color_quant2[0] = enc_color2[0] << 3 | (enc_color2[0] >> 2); avg_color_quant2[1] = enc_color2[1] << 3 | (enc_color2[1] >> 2); avg_color_quant2[2] = enc_color2[2] << 3 | (enc_color2[2] >> 2); // Pack bits into the first word. compressed1_flip = 0; PUTBITSHIGH( compressed1_flip, diffbit, 1, 33); PUTBITSHIGH( compressed1_flip, enc_color1[0], 5, 63); PUTBITSHIGH( compressed1_flip, enc_color1[1], 5, 55); PUTBITSHIGH( compressed1_flip, enc_color1[2], 5, 47); PUTBITSHIGH( compressed1_flip, diff[0], 3, 58); PUTBITSHIGH( compressed1_flip, diff[1], 3, 50); PUTBITSHIGH( compressed1_flip, diff[2], 3, 42); // upper part of block flip_err = tryalltables_3bittable4x2(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // lower part of block flip_err += tryalltables_3bittable4x2(img,width,height,startx,starty+2,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_flip, best_table1, 3, 39); PUTBITSHIGH( compressed1_flip, best_table2, 3, 36); PUTBITSHIGH( compressed1_flip, 1, 1, 32); best_pixel_indices1_MSB |= (best_pixel_indices2_MSB << 2); best_pixel_indices1_LSB |= (best_pixel_indices2_LSB << 2); compressed2_flip = ((best_pixel_indices1_MSB & 0xffff) << 16) | (best_pixel_indices1_LSB & 0xffff); // Now lets see which is the best table to use. Only 8 tables are possible. if(norm_err <= flip_err) { compressed1 = compressed1_norm | 0; compressed2 = compressed2_norm; best_err = norm_err; best_flip = 0; } else { compressed1 = compressed1_flip | 1; compressed2 = compressed2_flip; best_err = flip_err; best_enc_color1[0] = enc_color1[0]; best_enc_color1[1] = enc_color1[1]; best_enc_color1[2] = enc_color1[2]; best_enc_color2[0] = enc_color2[0]; best_enc_color2[1] = enc_color2[1]; best_enc_color2[2] = enc_color2[2]; best_flip = 1; } return best_err; } // Compresses the block using only the differential mode in ETC1/ETC2 // Uses the average color as the base color in each half-block. // If average colors are too different, use the average color of the entire block in both half-blocks. // Tries both flipped and unflipped. // Uses fixed point arithmetics where 1000 represents 1.0. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int compressBlockOnlyDiffFlipAveragePerceptual1000(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { unsigned int compressed1_norm, compressed2_norm; unsigned int compressed1_flip, compressed2_flip; uint8 avg_color_quant1[3], avg_color_quant2[3]; float avg_color_float1[3],avg_color_float2[3]; int enc_color1[3], enc_color2[3], diff[3]; unsigned int min_error=MAXERR1000; unsigned int best_table_indices1=0, best_table_indices2=0; unsigned int best_table1=0, best_table2=0; int diffbit; int norm_err=0; int flip_err=0; // First try normal blocks 2x4: computeAverageColor2x4noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor2x4noQuantFloat(img,width,height,startx+2,starty,avg_color_float2); // First test if avg_color1 is similar enough to avg_color2 so that // we can use differential coding of colors. enc_color1[0] = int( JAS_ROUND(31.0*avg_color_float1[0]/255.0) ); enc_color1[1] = int( JAS_ROUND(31.0*avg_color_float1[1]/255.0) ); enc_color1[2] = int( JAS_ROUND(31.0*avg_color_float1[2]/255.0) ); enc_color2[0] = int( JAS_ROUND(31.0*avg_color_float2[0]/255.0) ); enc_color2[1] = int( JAS_ROUND(31.0*avg_color_float2[1]/255.0) ); enc_color2[2] = int( JAS_ROUND(31.0*avg_color_float2[2]/255.0) ); diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; if( !((diff[0] >= -4) && (diff[0] <= 3) && (diff[1] >= -4) && (diff[1] <= 3) && (diff[2] >= -4) && (diff[2] <= 3)) ) { enc_color1[0] = (enc_color1[0] + enc_color2[0]) >> 1; enc_color1[1] = (enc_color1[1] + enc_color2[1]) >> 1; enc_color1[2] = (enc_color1[2] + enc_color2[2]) >> 1; enc_color2[0] = enc_color1[0]; enc_color2[1] = enc_color1[1]; enc_color2[2] = enc_color1[2]; } { diffbit = 1; // The difference to be coded: diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; avg_color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); avg_color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); avg_color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); avg_color_quant2[0] = enc_color2[0] << 3 | (enc_color2[0] >> 2); avg_color_quant2[1] = enc_color2[1] << 3 | (enc_color2[1] >> 2); avg_color_quant2[2] = enc_color2[2] << 3 | (enc_color2[2] >> 2); // Pack bits into the first word. // ETC1_RGB8_OES: // // a) bit layout in bits 63 through 32 if diffbit = 0 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // b) bit layout in bits 63 through 32 if diffbit = 1 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |diff|flip| // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // c) bit layout in bits 31 through 0 (in both cases) // // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 // -------------------------------------------------------------------------------------------------- // | most significant pixel index bits | least significant pixel index bits | // | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | // -------------------------------------------------------------------------------------------------- compressed1_norm = 0; PUTBITSHIGH( compressed1_norm, diffbit, 1, 33); PUTBITSHIGH( compressed1_norm, enc_color1[0], 5, 63); PUTBITSHIGH( compressed1_norm, enc_color1[1], 5, 55); PUTBITSHIGH( compressed1_norm, enc_color1[2], 5, 47); PUTBITSHIGH( compressed1_norm, diff[0], 3, 58); PUTBITSHIGH( compressed1_norm, diff[1], 3, 50); PUTBITSHIGH( compressed1_norm, diff[2], 3, 42); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; norm_err = 0; // left part of block norm_err = tryalltables_3bittable2x4percep1000(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // right part of block norm_err += tryalltables_3bittable2x4percep1000(img,width,height,startx+2,starty,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_norm, best_table1, 3, 39); PUTBITSHIGH( compressed1_norm, best_table2, 3, 36); PUTBITSHIGH( compressed1_norm, 0, 1, 32); compressed2_norm = 0; PUTBITS( compressed2_norm, (best_pixel_indices1_MSB ), 8, 23); PUTBITS( compressed2_norm, (best_pixel_indices2_MSB ), 8, 31); PUTBITS( compressed2_norm, (best_pixel_indices1_LSB ), 8, 7); PUTBITS( compressed2_norm, (best_pixel_indices2_LSB ), 8, 15); } // Now try flipped blocks 4x2: computeAverageColor4x2noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor4x2noQuantFloat(img,width,height,startx,starty+2,avg_color_float2); // First test if avg_color1 is similar enough to avg_color2 so that // we can use differential coding of colors. enc_color1[0] = int( JAS_ROUND(31.0*avg_color_float1[0]/255.0) ); enc_color1[1] = int( JAS_ROUND(31.0*avg_color_float1[1]/255.0) ); enc_color1[2] = int( JAS_ROUND(31.0*avg_color_float1[2]/255.0) ); enc_color2[0] = int( JAS_ROUND(31.0*avg_color_float2[0]/255.0) ); enc_color2[1] = int( JAS_ROUND(31.0*avg_color_float2[1]/255.0) ); enc_color2[2] = int( JAS_ROUND(31.0*avg_color_float2[2]/255.0) ); diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; if( !((diff[0] >= -4) && (diff[0] <= 3) && (diff[1] >= -4) && (diff[1] <= 3) && (diff[2] >= -4) && (diff[2] <= 3)) ) { enc_color1[0] = (enc_color1[0] + enc_color2[0]) >> 1; enc_color1[1] = (enc_color1[1] + enc_color2[1]) >> 1; enc_color1[2] = (enc_color1[2] + enc_color2[2]) >> 1; enc_color2[0] = enc_color1[0]; enc_color2[1] = enc_color1[1]; enc_color2[2] = enc_color1[2]; } { diffbit = 1; // The difference to be coded: diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; avg_color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); avg_color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); avg_color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); avg_color_quant2[0] = enc_color2[0] << 3 | (enc_color2[0] >> 2); avg_color_quant2[1] = enc_color2[1] << 3 | (enc_color2[1] >> 2); avg_color_quant2[2] = enc_color2[2] << 3 | (enc_color2[2] >> 2); // Pack bits into the first word. compressed1_flip = 0; PUTBITSHIGH( compressed1_flip, diffbit, 1, 33); PUTBITSHIGH( compressed1_flip, enc_color1[0], 5, 63); PUTBITSHIGH( compressed1_flip, enc_color1[1], 5, 55); PUTBITSHIGH( compressed1_flip, enc_color1[2], 5, 47); PUTBITSHIGH( compressed1_flip, diff[0], 3, 58); PUTBITSHIGH( compressed1_flip, diff[1], 3, 50); PUTBITSHIGH( compressed1_flip, diff[2], 3, 42); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; // upper part of block flip_err = tryalltables_3bittable4x2percep1000(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // lower part of block flip_err += tryalltables_3bittable4x2percep1000(img,width,height,startx,starty+2,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_flip, best_table1, 3, 39); PUTBITSHIGH( compressed1_flip, best_table2, 3, 36); PUTBITSHIGH( compressed1_flip, 1, 1, 32); best_pixel_indices1_MSB |= (best_pixel_indices2_MSB << 2); best_pixel_indices1_LSB |= (best_pixel_indices2_LSB << 2); compressed2_flip = ((best_pixel_indices1_MSB & 0xffff) << 16) | (best_pixel_indices1_LSB & 0xffff); } unsigned int best_err; if(norm_err <= flip_err) { compressed1 = compressed1_norm | 0; compressed2 = compressed2_norm; best_err = norm_err; } else { compressed1 = compressed1_flip | 1; compressed2 = compressed2_flip; best_err = flip_err; } return best_err; } // Compresses the block using both the individual and the differential mode in ETC1/ETC2 // Uses the average color as the base color in each half-block. // Uses a perceptual error metric. // Tries both flipped and unflipped. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double compressBlockDiffFlipAveragePerceptual(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { unsigned int compressed1_norm, compressed2_norm; unsigned int compressed1_flip, compressed2_flip; uint8 avg_color_quant1[3], avg_color_quant2[3]; float avg_color_float1[3],avg_color_float2[3]; int enc_color1[3], enc_color2[3], diff[3]; int min_error=255*255*8*3; unsigned int best_table_indices1=0, best_table_indices2=0; unsigned int best_table1=0, best_table2=0; int diffbit; int norm_err=0; int flip_err=0; // First try normal blocks 2x4: computeAverageColor2x4noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor2x4noQuantFloat(img,width,height,startx+2,starty,avg_color_float2); // First test if avg_color1 is similar enough to avg_color2 so that // we can use differential coding of colors. float eps; enc_color1[0] = int( JAS_ROUND(31.0*avg_color_float1[0]/255.0) ); enc_color1[1] = int( JAS_ROUND(31.0*avg_color_float1[1]/255.0) ); enc_color1[2] = int( JAS_ROUND(31.0*avg_color_float1[2]/255.0) ); enc_color2[0] = int( JAS_ROUND(31.0*avg_color_float2[0]/255.0) ); enc_color2[1] = int( JAS_ROUND(31.0*avg_color_float2[1]/255.0) ); enc_color2[2] = int( JAS_ROUND(31.0*avg_color_float2[2]/255.0) ); diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; if( (diff[0] >= -4) && (diff[0] <= 3) && (diff[1] >= -4) && (diff[1] <= 3) && (diff[2] >= -4) && (diff[2] <= 3) ) { diffbit = 1; // The difference to be coded: diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; avg_color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); avg_color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); avg_color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); avg_color_quant2[0] = enc_color2[0] << 3 | (enc_color2[0] >> 2); avg_color_quant2[1] = enc_color2[1] << 3 | (enc_color2[1] >> 2); avg_color_quant2[2] = enc_color2[2] << 3 | (enc_color2[2] >> 2); // Pack bits into the first word. // ETC1_RGB8_OES: // // a) bit layout in bits 63 through 32 if diffbit = 0 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // b) bit layout in bits 63 through 32 if diffbit = 1 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |diff|flip| // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // c) bit layout in bits 31 through 0 (in both cases) // // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 // -------------------------------------------------------------------------------------------------- // | most significant pixel index bits | least significant pixel index bits | // | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | // -------------------------------------------------------------------------------------------------- compressed1_norm = 0; PUTBITSHIGH( compressed1_norm, diffbit, 1, 33); PUTBITSHIGH( compressed1_norm, enc_color1[0], 5, 63); PUTBITSHIGH( compressed1_norm, enc_color1[1], 5, 55); PUTBITSHIGH( compressed1_norm, enc_color1[2], 5, 47); PUTBITSHIGH( compressed1_norm, diff[0], 3, 58); PUTBITSHIGH( compressed1_norm, diff[1], 3, 50); PUTBITSHIGH( compressed1_norm, diff[2], 3, 42); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; norm_err = 0; // left part of block norm_err = tryalltables_3bittable2x4percep(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // right part of block norm_err += tryalltables_3bittable2x4percep(img,width,height,startx+2,starty,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_norm, best_table1, 3, 39); PUTBITSHIGH( compressed1_norm, best_table2, 3, 36); PUTBITSHIGH( compressed1_norm, 0, 1, 32); compressed2_norm = 0; PUTBITS( compressed2_norm, (best_pixel_indices1_MSB ), 8, 23); PUTBITS( compressed2_norm, (best_pixel_indices2_MSB ), 8, 31); PUTBITS( compressed2_norm, (best_pixel_indices1_LSB ), 8, 7); PUTBITS( compressed2_norm, (best_pixel_indices2_LSB ), 8, 15); } else { diffbit = 0; // The difference is bigger than what fits in 555 plus delta-333, so we will have // to deal with 444 444. eps = (float) 0.0001; enc_color1[0] = int( ((float) avg_color_float1[0] / (17.0)) +0.5 + eps); enc_color1[1] = int( ((float) avg_color_float1[1] / (17.0)) +0.5 + eps); enc_color1[2] = int( ((float) avg_color_float1[2] / (17.0)) +0.5 + eps); enc_color2[0] = int( ((float) avg_color_float2[0] / (17.0)) +0.5 + eps); enc_color2[1] = int( ((float) avg_color_float2[1] / (17.0)) +0.5 + eps); enc_color2[2] = int( ((float) avg_color_float2[2] / (17.0)) +0.5 + eps); avg_color_quant1[0] = enc_color1[0] << 4 | enc_color1[0]; avg_color_quant1[1] = enc_color1[1] << 4 | enc_color1[1]; avg_color_quant1[2] = enc_color1[2] << 4 | enc_color1[2]; avg_color_quant2[0] = enc_color2[0] << 4 | enc_color2[0]; avg_color_quant2[1] = enc_color2[1] << 4 | enc_color2[1]; avg_color_quant2[2] = enc_color2[2] << 4 | enc_color2[2]; // Pack bits into the first word. // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- compressed1_norm = 0; PUTBITSHIGH( compressed1_norm, diffbit, 1, 33); PUTBITSHIGH( compressed1_norm, enc_color1[0], 4, 63); PUTBITSHIGH( compressed1_norm, enc_color1[1], 4, 55); PUTBITSHIGH( compressed1_norm, enc_color1[2], 4, 47); PUTBITSHIGH( compressed1_norm, enc_color2[0], 4, 59); PUTBITSHIGH( compressed1_norm, enc_color2[1], 4, 51); PUTBITSHIGH( compressed1_norm, enc_color2[2], 4, 43); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; // left part of block norm_err = tryalltables_3bittable2x4percep(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // right part of block norm_err += tryalltables_3bittable2x4percep(img,width,height,startx+2,starty,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_norm, best_table1, 3, 39); PUTBITSHIGH( compressed1_norm, best_table2, 3, 36); PUTBITSHIGH( compressed1_norm, 0, 1, 32); compressed2_norm = 0; PUTBITS( compressed2_norm, (best_pixel_indices1_MSB ), 8, 23); PUTBITS( compressed2_norm, (best_pixel_indices2_MSB ), 8, 31); PUTBITS( compressed2_norm, (best_pixel_indices1_LSB ), 8, 7); PUTBITS( compressed2_norm, (best_pixel_indices2_LSB ), 8, 15); } // Now try flipped blocks 4x2: computeAverageColor4x2noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor4x2noQuantFloat(img,width,height,startx,starty+2,avg_color_float2); // First test if avg_color1 is similar enough to avg_color2 so that // we can use differential coding of colors. enc_color1[0] = int( JAS_ROUND(31.0*avg_color_float1[0]/255.0) ); enc_color1[1] = int( JAS_ROUND(31.0*avg_color_float1[1]/255.0) ); enc_color1[2] = int( JAS_ROUND(31.0*avg_color_float1[2]/255.0) ); enc_color2[0] = int( JAS_ROUND(31.0*avg_color_float2[0]/255.0) ); enc_color2[1] = int( JAS_ROUND(31.0*avg_color_float2[1]/255.0) ); enc_color2[2] = int( JAS_ROUND(31.0*avg_color_float2[2]/255.0) ); diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; if( (diff[0] >= -4) && (diff[0] <= 3) && (diff[1] >= -4) && (diff[1] <= 3) && (diff[2] >= -4) && (diff[2] <= 3) ) { diffbit = 1; // The difference to be coded: diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; avg_color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); avg_color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); avg_color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); avg_color_quant2[0] = enc_color2[0] << 3 | (enc_color2[0] >> 2); avg_color_quant2[1] = enc_color2[1] << 3 | (enc_color2[1] >> 2); avg_color_quant2[2] = enc_color2[2] << 3 | (enc_color2[2] >> 2); // Pack bits into the first word. compressed1_flip = 0; PUTBITSHIGH( compressed1_flip, diffbit, 1, 33); PUTBITSHIGH( compressed1_flip, enc_color1[0], 5, 63); PUTBITSHIGH( compressed1_flip, enc_color1[1], 5, 55); PUTBITSHIGH( compressed1_flip, enc_color1[2], 5, 47); PUTBITSHIGH( compressed1_flip, diff[0], 3, 58); PUTBITSHIGH( compressed1_flip, diff[1], 3, 50); PUTBITSHIGH( compressed1_flip, diff[2], 3, 42); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; // upper part of block flip_err = tryalltables_3bittable4x2percep(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // lower part of block flip_err += tryalltables_3bittable4x2percep(img,width,height,startx,starty+2,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_flip, best_table1, 3, 39); PUTBITSHIGH( compressed1_flip, best_table2, 3, 36); PUTBITSHIGH( compressed1_flip, 1, 1, 32); best_pixel_indices1_MSB |= (best_pixel_indices2_MSB << 2); best_pixel_indices1_LSB |= (best_pixel_indices2_LSB << 2); compressed2_flip = ((best_pixel_indices1_MSB & 0xffff) << 16) | (best_pixel_indices1_LSB & 0xffff); } else { diffbit = 0; // The difference is bigger than what fits in 555 plus delta-333, so we will have // to deal with 444 444. eps = (float) 0.0001; enc_color1[0] = int( ((float) avg_color_float1[0] / (17.0)) +0.5 + eps); enc_color1[1] = int( ((float) avg_color_float1[1] / (17.0)) +0.5 + eps); enc_color1[2] = int( ((float) avg_color_float1[2] / (17.0)) +0.5 + eps); enc_color2[0] = int( ((float) avg_color_float2[0] / (17.0)) +0.5 + eps); enc_color2[1] = int( ((float) avg_color_float2[1] / (17.0)) +0.5 + eps); enc_color2[2] = int( ((float) avg_color_float2[2] / (17.0)) +0.5 + eps); avg_color_quant1[0] = enc_color1[0] << 4 | enc_color1[0]; avg_color_quant1[1] = enc_color1[1] << 4 | enc_color1[1]; avg_color_quant1[2] = enc_color1[2] << 4 | enc_color1[2]; avg_color_quant2[0] = enc_color2[0] << 4 | enc_color2[0]; avg_color_quant2[1] = enc_color2[1] << 4 | enc_color2[1]; avg_color_quant2[2] = enc_color2[2] << 4 | enc_color2[2]; // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // Pack bits into the first word. compressed1_flip = 0; PUTBITSHIGH( compressed1_flip, diffbit, 1, 33); PUTBITSHIGH( compressed1_flip, enc_color1[0], 4, 63); PUTBITSHIGH( compressed1_flip, enc_color1[1], 4, 55); PUTBITSHIGH( compressed1_flip, enc_color1[2], 4, 47); PUTBITSHIGH( compressed1_flip, enc_color2[0], 4, 59); PUTBITSHIGH( compressed1_flip, enc_color2[1], 4, 51); PUTBITSHIGH( compressed1_flip, enc_color2[2], 4, 43); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; // upper part of block flip_err = tryalltables_3bittable4x2percep(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // lower part of block flip_err += tryalltables_3bittable4x2percep(img,width,height,startx,starty+2,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_flip, best_table1, 3, 39); PUTBITSHIGH( compressed1_flip, best_table2, 3, 36); PUTBITSHIGH( compressed1_flip, 1, 1, 32); best_pixel_indices1_MSB |= (best_pixel_indices2_MSB << 2); best_pixel_indices1_LSB |= (best_pixel_indices2_LSB << 2); compressed2_flip = ((best_pixel_indices1_MSB & 0xffff) << 16) | (best_pixel_indices1_LSB & 0xffff); } // Now lets see which is the best table to use. Only 8 tables are possible. double best_err; if(norm_err <= flip_err) { compressed1 = compressed1_norm | 0; compressed2 = compressed2_norm; best_err = norm_err; } else { compressed1 = compressed1_flip | 1; compressed2 = compressed2_flip; best_err = flip_err; } return best_err; } // This is our structure for matrix data struct dMatrix { int width; // The number of coloumns in the matrix int height; // The number of rows in the matrix double *data; // The matrix data in row order }; // Multiplies two matrices // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. dMatrix *multiplyMatrices( dMatrix *Amat, dMatrix *Bmat) { int xx,yy, q; dMatrix *resmatrix; if(Amat->width != Bmat->height) { printf("Cannot multiply matrices -- dimensions do not agree.\n"); exit(1); } // Allocate space for result resmatrix = (dMatrix*) malloc(sizeof(dMatrix)); resmatrix->width = Bmat->width; resmatrix->height = Amat->height; resmatrix->data = (double*) malloc(sizeof(double)*(resmatrix->width)*(resmatrix->height)); for(yy = 0; yyheight; yy++) for(xx = 0; xxwidth; xx++) for(q=0, resmatrix->data[yy*resmatrix->width+xx] = 0.0; qwidth; q++) resmatrix->data[yy*resmatrix->width+xx] += Amat->data[yy*Amat->width + q] * Bmat->data[q*Bmat->width+xx]; return(resmatrix); } // Transposes a matrix // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void transposeMatrix( dMatrix *mat) { int xx, yy, zz; double *temp; int newwidth, newheight; temp = (double*) malloc (sizeof(double)*(mat->width)*(mat->height)); for(zz = 0; zz<((mat->width)*(mat->height)); zz++) temp[zz] = mat->data[zz]; newwidth = mat->height; newheight= mat->width; for(yy = 0; yydata[yy*newwidth+xx] = temp[xx*(mat->width)+yy]; mat->height = newheight; mat->width = newwidth; free(temp); } // In the planar mode in ETC2, the block can be partitioned as follows: // // O A A A H // B D1 D3 C3 // B D2 C2 D5 // B C1 D4 D6 // V // Here A-pixels, B-pixels and C-pixels only depend on two values. For instance, B-pixels only depend on O and V. // This can be used to quickly rule out combinations of colors. // Here we calculate the minimum error for the block if we know the red component for O and V. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcBBBred(uint8 *block, int colorO, int colorV) { colorO = (colorO << 2) | (colorO >> 4); colorV = (colorV << 2) | (colorV >> 4); unsigned int error = 0; // Now first column: B B B /* unroll loop for( yy=0; (yy<4) && (error <= best_error_sofar); yy++)*/ { error = error + square_table[(block[4*4 + 0] - clamp_table[ ((((colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*2 + 0] - clamp_table[ (((((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*3 + 0] - clamp_table[ (((3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; } return error; } // Calculating the minimum error for the block if we know the red component for H and V. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcCCCred(uint8 *block, int colorH, int colorV) { colorH = (colorH << 2) | (colorH >> 4); colorV = (colorV << 2) | (colorV >> 4); unsigned int error=0; error = error + square_table[(block[4*4*3 + 4 + 0] - clamp_table[ (((colorH + 3*colorV)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*2 + 4*2 + 0] - clamp_table[ (((2*colorH + 2*colorV)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4 + 4*3 + 0] - clamp_table[ (((3*colorH + colorV)+2)>>2) + 255])+255]; return error; } // Calculating the minimum error for the block if we know the red component for O and H. // Uses perceptual error metric. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcLowestPossibleRedOHperceptual(uint8 *block, int colorO, int colorH, unsigned int best_error_sofar) { colorO = (colorO << 2) | (colorO >> 4); colorH = (colorH << 2) | (colorH >> 4); unsigned int error; error = square_table_percep_red[(block[0] - colorO) + 255]; error = error + square_table_percep_red[(block[4] - clamp_table[ ((( (colorH-colorO) + 4*colorO)+2)>>2) + 255])+255]; if(error <= best_error_sofar) { error = error + square_table_percep_red[(block[4*2] - clamp_table[ ((( ((colorH-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table_percep_red[(block[4*3] - clamp_table[ ((( 3*(colorH-colorO) + 4*colorO)+2)>>2) + 255])+255]; } return error; } // Calculating the minimum error for the block (in planar mode) if we know the red component for O and H. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcLowestPossibleRedOH(uint8 *block, int colorO, int colorH, unsigned int best_error_sofar) { colorO = (colorO << 2) | (colorO >> 4); colorH = (colorH << 2) | (colorH >> 4); unsigned int error; error = square_table[(block[0] - colorO) + 255]; error = error + square_table[(block[4] - clamp_table[ ((( (colorH-colorO) + 4*colorO)+2)>>2) + 255])+255]; if(error <= best_error_sofar) { error = error + square_table[(block[4*2] - clamp_table[ ((( ((colorH-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*3] - clamp_table[ ((( 3*(colorH-colorO) + 4*colorO)+2)>>2) + 255])+255]; } return error; } // Calculating the minimum error for the block (in planar mode) if we know the red component for O and H and V. // Uses perceptual error metric. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcErrorPlanarOnlyRedPerceptual(uint8 *block, int colorO, int colorH, int colorV, unsigned int lowest_possible_error, unsigned int BBBvalue, unsigned int CCCvalue, unsigned int best_error_sofar) { colorO = (colorO << 2) | (colorO >> 4); colorH = (colorH << 2) | (colorH >> 4); colorV = (colorV << 2) | (colorV >> 4); unsigned int error; // The block can be partitioned into: O A A A // B D1 D3 C3 // B D2 C2 D5 // B C1 D4 D6 int xpart_times_4; // The first part: O A A A. It equals lowest_possible_error previously calculated. // lowest_possible_error is OAAA, BBBvalue is BBB and CCCvalue is C1C2C3. error = lowest_possible_error + BBBvalue + CCCvalue; // The remaining pixels to cover are D1 through D6. if(error <= best_error_sofar) { // Second column: D1 D2 but not C1 xpart_times_4 = (colorH-colorO); error = error + square_table_percep_red[(block[4*4 + 4 + 0] - clamp_table[ (((xpart_times_4 + (colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table_percep_red[(block[4*4*2 + 4 + 0] - clamp_table[ (((xpart_times_4 + ((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; // Third column: D3 notC2 D4 xpart_times_4 = (colorH-colorO) << 1; error = error + square_table_percep_red[(block[4*4 + 4*2 + 0] - clamp_table[ (((xpart_times_4 + (colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; if(error <= best_error_sofar) { error = error + square_table_percep_red[(block[4*4*3 + 4*2 + 0] - clamp_table[ (((xpart_times_4 + 3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; // Forth column: notC3 D5 D6 xpart_times_4 = 3*(colorH-colorO); error = error + square_table_percep_red[(block[4*4*2 + 4*3 + 0] - clamp_table[ (((xpart_times_4 + ((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table_percep_red[(block[4*4*3 + 4*3 + 0] - clamp_table[ (((xpart_times_4 + 3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; } } return error; } // Calculating the minimum error for the block (in planar mode) if we know the red component for O and H and V. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcErrorPlanarOnlyRed(uint8 *block, int colorO, int colorH, int colorV, unsigned int lowest_possible_error, unsigned int BBBvalue, unsigned int CCCvalue, unsigned int best_error_sofar) { colorO = (colorO << 2) | (colorO >> 4); colorH = (colorH << 2) | (colorH >> 4); colorV = (colorV << 2) | (colorV >> 4); unsigned int error; // The block can be partitioned into: O A A A // B D1 D3 C3 // B D2 C2 D5 // B C1 D4 D6 int xpart_times_4; // The first part: O A A A. It equals lowest_possible_error previously calculated. // lowest_possible_error is OAAA, BBBvalue is BBB and CCCvalue is C1C2C3. error = lowest_possible_error + BBBvalue + CCCvalue; // The remaining pixels to cover are D1 through D6. if(error <= best_error_sofar) { // Second column: D1 D2 but not C1 xpart_times_4 = (colorH-colorO); error = error + square_table[(block[4*4 + 4 + 0] - clamp_table[ (((xpart_times_4 + (colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*2 + 4 + 0] - clamp_table[ (((xpart_times_4 + ((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; // Third column: D3 notC2 D4 xpart_times_4 = (colorH-colorO) << 1; error = error + square_table[(block[4*4 + 4*2 + 0] - clamp_table[ (((xpart_times_4 + (colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; if(error <= best_error_sofar) { error = error + square_table[(block[4*4*3 + 4*2 + 0] - clamp_table[ (((xpart_times_4 + 3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; // Forth column: notC3 D5 D6 xpart_times_4 = 3*(colorH-colorO); error = error + square_table[(block[4*4*2 + 4*3 + 0] - clamp_table[ (((xpart_times_4 + ((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*3 + 4*3 + 0] - clamp_table[ (((xpart_times_4 + 3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; } } return error; } // Calculating the minimum error for the block (in planar mode) if we know the red component for O and H. // Uses perceptual error metrics. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcLowestPossibleGreenOHperceptual(uint8 *block, int colorO, int colorH, unsigned int best_error_sofar) { colorO = (colorO << 1) | (colorO >> 6); colorH = (colorH << 1) | (colorH >> 6); unsigned int error; error = square_table_percep_green[(block[1] - colorO) + 255]; error = error + square_table_percep_green[(block[4 + 1] - clamp_table[ ((( (colorH-colorO) + 4*colorO)+2)>>2) + 255])+255]; if(error <= best_error_sofar) { error = error + square_table_percep_green[(block[4*2 + 1] - clamp_table[ ((( ((colorH-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table_percep_green[(block[4*3 + 1] - clamp_table[ ((( 3*(colorH-colorO) + 4*colorO)+2)>>2) + 255])+255]; } return error; } // Calculating the minimum error for the block (in planar mode) if we know the red component for O and H. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcLowestPossibleGreenOH(uint8 *block, int colorO, int colorH, unsigned int best_error_sofar) { colorO = (colorO << 1) | (colorO >> 6); colorH = (colorH << 1) | (colorH >> 6); unsigned int error; error = square_table[(block[1] - colorO) + 255]; error = error + square_table[(block[4 + 1] - clamp_table[ ((( (colorH-colorO) + 4*colorO)+2)>>2) + 255])+255]; if(error <= best_error_sofar) { error = error + square_table[(block[4*2 + 1] - clamp_table[ ((( ((colorH-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*3 + 1] - clamp_table[ ((( 3*(colorH-colorO) + 4*colorO)+2)>>2) + 255])+255]; } return error; } // Calculating the minimum error for the block (in planar mode) if we know the green component for O and V. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcBBBgreen(uint8 *block, int colorO, int colorV) { colorO = (colorO << 1) | (colorO >> 6); colorV = (colorV << 1) | (colorV >> 6); unsigned int error = 0; // Now first column: B B B /* unroll loop for( yy=0; (yy<4) && (error <= best_error_sofar); yy++)*/ { error = error + square_table[(block[4*4 + 1] - clamp_table[ ((((colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*2 + 1] - clamp_table[ (((((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*3 + 1] - clamp_table[ (((3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; } return error; } // Calculating the minimum error for the block (in planar mode) if we know the green component for H and V. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcCCCgreen(uint8 *block, int colorH, int colorV) { colorH = (colorH << 1) | (colorH >> 6); colorV = (colorV << 1) | (colorV >> 6); unsigned int error=0; error = error + square_table[(block[4*4*3 + 4 + 1] - clamp_table[ (((colorH + 3*colorV)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*2 + 4*2 + 1] - clamp_table[ (((2*colorH + 2*colorV)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4 + 4*3 + 1] - clamp_table[ (((3*colorH + colorV)+2)>>2) + 255])+255]; return error; } // Calculating the minimum error for the block (in planar mode) if we know the green component for H V and O. // Uses perceptual error metric. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcErrorPlanarOnlyGreenPerceptual(uint8 *block, int colorO, int colorH, int colorV, unsigned int lowest_possible_error, unsigned int BBBvalue, unsigned int CCCvalue, unsigned int best_error_sofar) { colorO = (colorO << 1) | (colorO >> 6); colorH = (colorH << 1) | (colorH >> 6); colorV = (colorV << 1) | (colorV >> 6); unsigned int error; // The block can be partitioned into: O A A A // B D1 D3 C3 // B D2 C2 D5 // B C1 D4 D6 int xpart_times_4; // The first part: O A A A. It equals lowest_possible_error previously calculated. // lowest_possible_error is OAAA, BBBvalue is BBB and CCCvalue is C1C2C3. error = lowest_possible_error + BBBvalue + CCCvalue; // The remaining pixels to cover are D1 through D6. if(error <= best_error_sofar) { // Second column: D1 D2 but not C1 xpart_times_4 = (colorH-colorO); error = error + square_table_percep_green[(block[4*4 + 4 + 1] - clamp_table[ (((xpart_times_4 + (colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table_percep_green[(block[4*4*2 + 4 + 1] - clamp_table[ (((xpart_times_4 + ((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; // Third column: D3 notC2 D4 xpart_times_4 = (colorH-colorO) << 1; error = error + square_table_percep_green[(block[4*4 + 4*2 + 1] - clamp_table[ (((xpart_times_4 + (colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; if(error <= best_error_sofar) { error = error + square_table_percep_green[(block[4*4*3 + 4*2 + 1] - clamp_table[ (((xpart_times_4 + 3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; // Forth column: notC3 D5 D6 xpart_times_4 = 3*(colorH-colorO); error = error + square_table_percep_green[(block[4*4*2 + 4*3 + 1] - clamp_table[ (((xpart_times_4 + ((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table_percep_green[(block[4*4*3 + 4*3 + 1] - clamp_table[ (((xpart_times_4 + 3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; } } return error; } // Calculating the minimum error for the block (in planar mode) if we know the green component for H V and O. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcErrorPlanarOnlyGreen(uint8 *block, int colorO, int colorH, int colorV, unsigned int lowest_possible_error, unsigned int BBBvalue, unsigned int CCCvalue, unsigned int best_error_sofar) { colorO = (colorO << 1) | (colorO >> 6); colorH = (colorH << 1) | (colorH >> 6); colorV = (colorV << 1) | (colorV >> 6); unsigned int error; // The block can be partitioned into: O A A A // B D1 D3 C3 // B D2 C2 D5 // B C1 D4 D6 int xpart_times_4; // The first part: O A A A. It equals lowest_possible_error previously calculated. // lowest_possible_error is OAAA, BBBvalue is BBB and CCCvalue is C1C2C3. error = lowest_possible_error + BBBvalue + CCCvalue; // The remaining pixels to cover are D1 through D6. if(error <= best_error_sofar) { // Second column: D1 D2 but not C1 xpart_times_4 = (colorH-colorO); error = error + square_table[(block[4*4 + 4 + 1] - clamp_table[ (((xpart_times_4 + (colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*2 + 4 + 1] - clamp_table[ (((xpart_times_4 + ((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; // Third column: D3 notC2 D4 xpart_times_4 = (colorH-colorO) << 1; error = error + square_table[(block[4*4 + 4*2 + 1] - clamp_table[ (((xpart_times_4 + (colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; if(error <= best_error_sofar) { error = error + square_table[(block[4*4*3 + 4*2 + 1] - clamp_table[ (((xpart_times_4 + 3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; // Forth column: notC3 D5 D6 xpart_times_4 = 3*(colorH-colorO); error = error + square_table[(block[4*4*2 + 4*3 + 1] - clamp_table[ (((xpart_times_4 + ((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*3 + 4*3 + 1] - clamp_table[ (((xpart_times_4 + 3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; } } return error; } // Calculating the minimum error for the block (in planar mode) if we know the blue component for O and V. // Uses perceptual error metric. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcBBBbluePerceptual(uint8 *block, int colorO, int colorV) { colorO = (colorO << 2) | (colorO >> 4); colorV = (colorV << 2) | (colorV >> 4); unsigned int error = 0; // Now first column: B B B /* unroll loop for( yy=0; (yy<4) && (error <= best_error_sofar); yy++)*/ { error = error + square_table_percep_blue[(block[4*4 + 2] - clamp_table[ ((((colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table_percep_blue[(block[4*4*2 + 2] - clamp_table[ (((((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table_percep_blue[(block[4*4*3 + 2] - clamp_table[ (((3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; } return error; } // Calculating the minimum error for the block (in planar mode) if we know the blue component for O and V. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcBBBblue(uint8 *block, int colorO, int colorV) { colorO = (colorO << 2) | (colorO >> 4); colorV = (colorV << 2) | (colorV >> 4); unsigned int error = 0; // Now first column: B B B /* unroll loop for( yy=0; (yy<4) && (error <= best_error_sofar); yy++)*/ { error = error + square_table[(block[4*4 + 2] - clamp_table[ ((((colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*2 + 2] - clamp_table[ (((((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*3 + 2] - clamp_table[ (((3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; } return error; } // Calculating the minimum error for the block (in planar mode) if we know the blue component for H and V. // Uses perceptual error metric. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcCCCbluePerceptual(uint8 *block, int colorH, int colorV) { colorH = (colorH << 2) | (colorH >> 4); colorV = (colorV << 2) | (colorV >> 4); unsigned int error=0; error = error + square_table_percep_blue[(block[4*4*3 + 4 + 2] - clamp_table[ (((colorH + 3*colorV)+2)>>2) + 255])+255]; error = error + square_table_percep_blue[(block[4*4*2 + 4*2 + 2] - clamp_table[ (((2*colorH + 2*colorV)+2)>>2) + 255])+255]; error = error + square_table_percep_blue[(block[4*4 + 4*3 + 2] - clamp_table[ (((3*colorH + colorV)+2)>>2) + 255])+255]; return error; } // Calculating the minimum error for the block (in planar mode) if we know the blue component for O and V. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcCCCblue(uint8 *block, int colorH, int colorV) { colorH = (colorH << 2) | (colorH >> 4); colorV = (colorV << 2) | (colorV >> 4); unsigned int error=0; error = error + square_table[(block[4*4*3 + 4 + 2] - clamp_table[ (((colorH + 3*colorV)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*2 + 4*2 + 2] - clamp_table[ (((2*colorH + 2*colorV)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4 + 4*3 + 2] - clamp_table[ (((3*colorH + colorV)+2)>>2) + 255])+255]; return error; } // Calculating the minimum error for the block (in planar mode) if we know the blue component for O and H. // Uses perceptual error metric. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcLowestPossibleBlueOHperceptual(uint8 *block, int colorO, int colorH, unsigned int best_error_sofar) { colorO = (colorO << 2) | (colorO >> 4); colorH = (colorH << 2) | (colorH >> 4); unsigned int error; error = square_table_percep_blue[(block[2] - colorO) + 255]; error = error + square_table_percep_blue[(block[4+2] - clamp_table[ ((( (colorH-colorO) + 4*colorO)+2)>>2) + 255])+255]; if(error <= best_error_sofar) { error = error + square_table_percep_blue[(block[4*2+2] - clamp_table[ ((( ((colorH-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table_percep_blue[(block[4*3+2] - clamp_table[ ((( 3*(colorH-colorO) + 4*colorO)+2)>>2) + 255])+255]; } return error; } // Calculating the minimum error for the block (in planar mode) if we know the blue component for O and H. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcLowestPossibleBlueOH(uint8 *block, int colorO, int colorH, unsigned int best_error_sofar) { colorO = (colorO << 2) | (colorO >> 4); colorH = (colorH << 2) | (colorH >> 4); unsigned int error; error = square_table[(block[2] - colorO) + 255]; error = error + square_table[(block[4+2] - clamp_table[ ((( (colorH-colorO) + 4*colorO)+2)>>2) + 255])+255]; if(error <= best_error_sofar) { error = error + square_table[(block[4*2+2] - clamp_table[ ((( ((colorH-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*3+2] - clamp_table[ ((( 3*(colorH-colorO) + 4*colorO)+2)>>2) + 255])+255]; } return error; } // Calculating the minimum error for the block (in planar mode) if we know the blue component for O, V and H. // Uses perceptual error metric. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcErrorPlanarOnlyBluePerceptual(uint8 *block, int colorO, int colorH, int colorV, unsigned int lowest_possible_error, unsigned int BBBvalue, unsigned int CCCvalue, unsigned int best_error_sofar) { colorO = (colorO << 2) | (colorO >> 4); colorH = (colorH << 2) | (colorH >> 4); colorV = (colorV << 2) | (colorV >> 4); unsigned int error; // The block can be partitioned into: O A A A // B D1 D3 C3 // B D2 C2 D5 // B C1 D4 D6 int xpart_times_4; // The first part: O A A A. It equals lowest_possible_error previously calculated. // lowest_possible_error is OAAA, BBBvalue is BBB and CCCvalue is C1C2C3. error = lowest_possible_error + BBBvalue + CCCvalue; // The remaining pixels to cover are D1 through D6. if(error <= best_error_sofar) { // Second column: D1 D2 but not C1 xpart_times_4 = (colorH-colorO); error = error + square_table_percep_blue[(block[4*4 + 4 + 2] - clamp_table[ (((xpart_times_4 + (colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table_percep_blue[(block[4*4*2 + 4 + 2] - clamp_table[ (((xpart_times_4 + ((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; // Third column: D3 notC2 D4 xpart_times_4 = (colorH-colorO) << 1; error = error + square_table_percep_blue[(block[4*4 + 4*2 + 2] - clamp_table[ (((xpart_times_4 + (colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; if(error <= best_error_sofar) { error = error + square_table_percep_blue[(block[4*4*3 + 4*2 + 2] - clamp_table[ (((xpart_times_4 + 3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; // Forth column: notC3 D5 D6 xpart_times_4 = 3*(colorH-colorO); error = error + square_table_percep_blue[(block[4*4*2 + 4*3 + 2] - clamp_table[ (((xpart_times_4 + ((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table_percep_blue[(block[4*4*3 + 4*3 + 2] - clamp_table[ (((xpart_times_4 + 3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; } } return error; } // Calculating the minimum error for the block (in planar mode) if we know the blue component for O, V and H. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calcErrorPlanarOnlyBlue(uint8 *block, int colorO, int colorH, int colorV, unsigned int lowest_possible_error, unsigned int BBBvalue, unsigned int CCCvalue, unsigned int best_error_sofar) { colorO = (colorO << 2) | (colorO >> 4); colorH = (colorH << 2) | (colorH >> 4); colorV = (colorV << 2) | (colorV >> 4); unsigned int error; // The block can be partitioned into: O A A A // B D1 D3 C3 // B D2 C2 D5 // B C1 D4 D6 int xpart_times_4; // The first part: O A A A. It equals lowest_possible_error previously calculated. // lowest_possible_error is OAAA, BBBvalue is BBB and CCCvalue is C1C2C3. error = lowest_possible_error + BBBvalue + CCCvalue; // The remaining pixels to cover are D1 through D6. if(error <= best_error_sofar) { // Second column: D1 D2 but not C1 xpart_times_4 = (colorH-colorO); error = error + square_table[(block[4*4 + 4 + 2] - clamp_table[ (((xpart_times_4 + (colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*2 + 4 + 2] - clamp_table[ (((xpart_times_4 + ((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; // Third column: D3 notC2 D4 xpart_times_4 = (colorH-colorO) << 1; error = error + square_table[(block[4*4 + 4*2 + 2] - clamp_table[ (((xpart_times_4 + (colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; if(error <= best_error_sofar) { error = error + square_table[(block[4*4*3 + 4*2 + 2] - clamp_table[ (((xpart_times_4 + 3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; // Forth column: notC3 D5 D6 xpart_times_4 = 3*(colorH-colorO); error = error + square_table[(block[4*4*2 + 4*3 + 2] - clamp_table[ (((xpart_times_4 + ((colorV-colorO)<<1) + 4*colorO)+2)>>2) + 255])+255]; error = error + square_table[(block[4*4*3 + 4*3 + 2] - clamp_table[ (((xpart_times_4 + 3*(colorV-colorO) + 4*colorO)+2)>>2) + 255])+255]; } } return error; } // This function uses least squares in order to determine the best values of the plane. // This is close to optimal, but not quite, due to nonlinearities in the expantion from 6 and 7 bits to 8, and // in the clamping to a number between 0 and the maximum. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressBlockPlanar57(uint8 *img, int width,int height,int startx,int starty, unsigned int &compressed57_1, unsigned int &compressed57_2) { // Use least squares to find the solution with the smallest error. // That is, find the vector x so that |Ax-b|^2 is minimized, where // x = [Ro Rr Rv]'; // A = [1 3/4 2/4 1/4 3/4 2/4 1/4 0 2/4 1/4 0 -1/4 1/4 0 -1/4 -2/4 ; // 0 1/4 2/4 3/4 0 1/4 2/4 3/4 0 1/4 2/4 3/4 0 1/4 2/4 3/4 ; // 0 0 0 0 1/4 1/4 1/4 1/4 2/4 2/4 2/4 2/4; 3/4 3/4 3/4 3/4]'; // b = [r11 r12 r13 r14 r21 r22 r23 r24 r31 r32 r33 r34 r41 r42 r43 r44]; // // That is, find solution x = inv(A' * A) * A' * b // = C * A' * b; // C is always the same, so we have calculated it off-line here. // = C * D int xx,yy, cc; double coeffsA[48]= { 1.00, 0.00, 0.00, 0.75, 0.25, 0.00, 0.50, 0.50, 0.00, 0.25, 0.75, 0.00, 0.75, 0.00, 0.25, 0.50, 0.25, 0.25, 0.25, 0.50, 0.25, 0.00, 0.75, 0.25, 0.50, 0.00, 0.50, 0.25, 0.25, 0.50, 0.00, 0.50, 0.50, -0.25, 0.75, 0.50, 0.25, 0.00, 0.75, 0.00, 0.25, 0.75, -0.25, 0.50, 0.75, -0.50, 0.75, 0.75}; double coeffsC[9] = {0.2875, -0.0125, -0.0125, -0.0125, 0.4875, -0.3125, -0.0125, -0.3125, 0.4875}; double colorO[3], colorH[3], colorV[3]; uint8 colorO8[3], colorH8[3], colorV8[3]; dMatrix *D_matrix; dMatrix *x_vector; dMatrix A_matrix; A_matrix.width = 3; A_matrix.height = 16; A_matrix.data = coeffsA; dMatrix C_matrix; C_matrix.width = 3; C_matrix.height = 3; C_matrix.data = coeffsC; dMatrix b_vector; b_vector.width = 1; b_vector.height = 16; b_vector.data = (double*) malloc(sizeof(double)*b_vector.width*b_vector.height); transposeMatrix(&A_matrix); // Red component // Load color data into vector b: for(cc = 0, yy = 0; yy<4; yy++) for(xx = 0; xx<4; xx++) b_vector.data[cc++] = img[3*width*(starty+yy) + 3*(startx+xx) + 0]; D_matrix = multiplyMatrices(&A_matrix, &b_vector); x_vector = multiplyMatrices(&C_matrix, D_matrix); colorO[0] = CLAMP(0.0, x_vector->data[0], 255.0); colorH[0] = CLAMP(0.0, x_vector->data[1], 255.0); colorV[0] = CLAMP(0.0, x_vector->data[2], 255.0); free(D_matrix->data); free(D_matrix); free(x_vector->data); free(x_vector); // Green component // Load color data into vector b: for(cc = 0, yy = 0; yy<4; yy++) for(xx = 0; xx<4; xx++) b_vector.data[cc++] = img[3*width*(starty+yy) + 3*(startx+xx) + 1]; D_matrix = multiplyMatrices(&A_matrix, &b_vector); x_vector = multiplyMatrices(&C_matrix, D_matrix); colorO[1] = CLAMP(0.0, x_vector->data[0], 255.0); colorH[1] = CLAMP(0.0, x_vector->data[1], 255.0); colorV[1] = CLAMP(0.0, x_vector->data[2], 255.0); free(D_matrix->data); free(D_matrix); free(x_vector->data); free(x_vector); // Blue component // Load color data into vector b: for(cc = 0, yy = 0; yy<4; yy++) for(xx = 0; xx<4; xx++) b_vector.data[cc++] = img[3*width*(starty+yy) + 3*(startx+xx) + 2]; D_matrix = multiplyMatrices(&A_matrix, &b_vector); x_vector = multiplyMatrices(&C_matrix, D_matrix); colorO[2] = CLAMP(0.0, x_vector->data[0], 255.0); colorH[2] = CLAMP(0.0, x_vector->data[1], 255.0); colorV[2] = CLAMP(0.0, x_vector->data[2], 255.0); free(D_matrix->data); free(D_matrix); free(x_vector->data); free(x_vector); // Quantize to 6 bits double D = 255*(1.0/((1<<6)-1.0) ); colorO8[0] = JAS_ROUND((1.0*colorO[0])/D); colorO8[2] = JAS_ROUND((1.0*colorO[2])/D); colorH8[0] = JAS_ROUND((1.0*colorH[0])/D); colorH8[2] = JAS_ROUND((1.0*colorH[2])/D); colorV8[0] = JAS_ROUND((1.0*colorV[0])/D); colorV8[2] = JAS_ROUND((1.0*colorV[2])/D); // Quantize to 7 bits D = 255*(1.0/((1<<7)-1.0) ); colorO8[1] = JAS_ROUND((1.0*colorO[1])/D); colorH8[1] = JAS_ROUND((1.0*colorH[1])/D); colorV8[1] = JAS_ROUND((1.0*colorV[1])/D); // Pack bits in 57 bits // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // ------------------------------------------------------------------------------------------------ // | R0 | G0 | B0 | RH | GH | // ------------------------------------------------------------------------------------------------ // // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 // ------------------------------------------------------------------------------------------------ // | BH | RV | GV | BV | not used | // ------------------------------------------------------------------------------------------------ compressed57_1 = 0; compressed57_2 = 0; PUTBITSHIGH( compressed57_1, colorO8[0], 6, 63); PUTBITSHIGH( compressed57_1, colorO8[1], 7, 57); PUTBITSHIGH( compressed57_1, colorO8[2], 6, 50); PUTBITSHIGH( compressed57_1, colorH8[0], 6, 44); PUTBITSHIGH( compressed57_1, colorH8[1], 7, 38); PUTBITS( compressed57_2, colorH8[2], 6, 31); PUTBITS( compressed57_2, colorV8[0], 6, 25); PUTBITS( compressed57_2, colorV8[1], 7, 19); PUTBITS( compressed57_2, colorV8[2], 6, 12); } // During search it is not convenient to store the bits the way they are stored in the // file format. Hence, after search, it is converted to this format. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void stuff57bits(unsigned int planar57_word1, unsigned int planar57_word2, unsigned int &planar_word1, unsigned int &planar_word2) { // Put bits in twotimer configuration for 57 bits (red and green dont overflow, green does) // // Go from this bit layout: // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // ----------------------------------------------------------------------------------------------- // |R0 |G01G02 |B01B02 ;B03 |RH1 |RH2|GH | // ----------------------------------------------------------------------------------------------- // // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 // ----------------------------------------------------------------------------------------------- // |BH |RV |GV |BV | not used | // ----------------------------------------------------------------------------------------------- // // To this: // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // ------------------------------------------------------------------------------------------------ // |//|R0 |G01|/|G02 |B01|/ // //|B02 |//|B03 |RH1 |df|RH2| // ------------------------------------------------------------------------------------------------ // // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 // ----------------------------------------------------------------------------------------------- // |GH |BH |RV |GV |BV | // ----------------------------------------------------------------------------------------------- // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |diff|flip| // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- uint8 RO, GO1, GO2, BO1, BO2, BO3, RH1, RH2, GH, BH, RV, GV, BV; uint8 bit, a, b, c, d, bits; RO = GETBITSHIGH( planar57_word1, 6, 63); GO1= GETBITSHIGH( planar57_word1, 1, 57); GO2= GETBITSHIGH( planar57_word1, 6, 56); BO1= GETBITSHIGH( planar57_word1, 1, 50); BO2= GETBITSHIGH( planar57_word1, 2, 49); BO3= GETBITSHIGH( planar57_word1, 3, 47); RH1= GETBITSHIGH( planar57_word1, 5, 44); RH2= GETBITSHIGH( planar57_word1, 1, 39); GH = GETBITSHIGH( planar57_word1, 7, 38); BH = GETBITS( planar57_word2, 6, 31); RV = GETBITS( planar57_word2, 6, 25); GV = GETBITS( planar57_word2, 7, 19); BV = GETBITS( planar57_word2, 6, 12); planar_word1 = 0; planar_word2 = 0; PUTBITSHIGH( planar_word1, RO, 6, 62); PUTBITSHIGH( planar_word1, GO1, 1, 56); PUTBITSHIGH( planar_word1, GO2, 6, 54); PUTBITSHIGH( planar_word1, BO1, 1, 48); PUTBITSHIGH( planar_word1, BO2, 2, 44); PUTBITSHIGH( planar_word1, BO3, 3, 41); PUTBITSHIGH( planar_word1, RH1, 5, 38); PUTBITSHIGH( planar_word1, RH2, 1, 32); PUTBITS( planar_word2, GH, 7, 31); PUTBITS( planar_word2, BH, 6, 24); PUTBITS( planar_word2, RV, 6, 18); PUTBITS( planar_word2, GV, 7, 12); PUTBITS( planar_word2, BV, 6, 5); // Make sure that red does not overflow: bit = GETBITSHIGH( planar_word1, 1, 62); PUTBITSHIGH( planar_word1, !bit, 1, 63); // Make sure that green does not overflow: bit = GETBITSHIGH( planar_word1, 1, 54); PUTBITSHIGH( planar_word1, !bit, 1, 55); // Make sure that blue overflows: a = GETBITSHIGH( planar_word1, 1, 44); b = GETBITSHIGH( planar_word1, 1, 43); c = GETBITSHIGH( planar_word1, 1, 41); d = GETBITSHIGH( planar_word1, 1, 40); // The following bit abcd bit sequences should be padded with ones: 0111, 1010, 1011, 1101, 1110, 1111 // The following logical expression checks for the presence of any of those: bit = (a & c) | (!a & b & c & d) | (a & b & !c & d); bits = 0xf*bit; PUTBITSHIGH( planar_word1, bits, 3, 47); PUTBITSHIGH( planar_word1, !bit, 1, 42); // Set diffbit PUTBITSHIGH( planar_word1, 1, 1, 33); } // During search it is not convenient to store the bits the way they are stored in the // file format. Hence, after search, it is converted to this format. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void stuff58bits(unsigned int thumbH58_word1, unsigned int thumbH58_word2, unsigned int &thumbH_word1, unsigned int &thumbH_word2) { // Put bits in twotimer configuration for 58 (red doesn't overflow, green does) // // Go from this bit layout: // // // |63 62 61 60 59 58|57 56 55 54|53 52 51 50|49 48 47 46|45 44 43 42|41 40 39 38|37 36 35 34|33 32| // |-------empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|d2 d1| // // |31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| // |---------------------------------------index bits----------------------------------------------| // // To this: // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // ----------------------------------------------------------------------------------------------- // |//|R0 |G0 |// // //|G0|B0|//|B0b |R1 |G1 |B0 |d2|df|d1| // ----------------------------------------------------------------------------------------------- // // |31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| // |---------------------------------------index bits----------------------------------------------| // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // ----------------------------------------------------------------------------------------------- // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |df|fp| // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bt|bt| // ----------------------------------------------------------------------------------------------- // // // Thus, what we are really doing is going from this bit layout: // // // |63 62 61 60 59 58|57 56 55 54 53 52 51|50 49|48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33|32 | // |-------empty-----|part0---------------|part1|part2------------------------------------------|part3| // // To this: // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------| // |//|part0 |// // //|part1|//|part2 |df|part3| // --------------------------------------------------------------------------------------------------| unsigned int part0, part1, part2, part3; uint8 bit, a, b, c, d, bits; // move parts part0 = GETBITSHIGH( thumbH58_word1, 7, 57); part1 = GETBITSHIGH( thumbH58_word1, 2, 50); part2 = GETBITSHIGH( thumbH58_word1,16, 48); part3 = GETBITSHIGH( thumbH58_word1, 1, 32); thumbH_word1 = 0; PUTBITSHIGH( thumbH_word1, part0, 7, 62); PUTBITSHIGH( thumbH_word1, part1, 2, 52); PUTBITSHIGH( thumbH_word1, part2, 16, 49); PUTBITSHIGH( thumbH_word1, part3, 1, 32); // Make sure that red does not overflow: bit = GETBITSHIGH( thumbH_word1, 1, 62); PUTBITSHIGH( thumbH_word1, !bit, 1, 63); // Make sure that green overflows: a = GETBITSHIGH( thumbH_word1, 1, 52); b = GETBITSHIGH( thumbH_word1, 1, 51); c = GETBITSHIGH( thumbH_word1, 1, 49); d = GETBITSHIGH( thumbH_word1, 1, 48); // The following bit abcd bit sequences should be padded with ones: 0111, 1010, 1011, 1101, 1110, 1111 // The following logical expression checks for the presence of any of those: bit = (a & c) | (!a & b & c & d) | (a & b & !c & d); bits = 0xf*bit; PUTBITSHIGH( thumbH_word1, bits, 3, 55); PUTBITSHIGH( thumbH_word1, !bit, 1, 50); // Set diffbit PUTBITSHIGH( thumbH_word1, 1, 1, 33); thumbH_word2 = thumbH58_word2; } // copy of above, but diffbit is 0 // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void stuff58bitsDiffFalse(unsigned int thumbH58_word1, unsigned int thumbH58_word2, unsigned int &thumbH_word1, unsigned int &thumbH_word2) { unsigned int part0, part1, part2, part3; uint8 bit, a, b, c, d, bits; // move parts part0 = GETBITSHIGH( thumbH58_word1, 7, 57); part1 = GETBITSHIGH( thumbH58_word1, 2, 50); part2 = GETBITSHIGH( thumbH58_word1,16, 48); part3 = GETBITSHIGH( thumbH58_word1, 1, 32); thumbH_word1 = 0; PUTBITSHIGH( thumbH_word1, part0, 7, 62); PUTBITSHIGH( thumbH_word1, part1, 2, 52); PUTBITSHIGH( thumbH_word1, part2, 16, 49); PUTBITSHIGH( thumbH_word1, part3, 1, 32); // Make sure that red does not overflow: bit = GETBITSHIGH( thumbH_word1, 1, 62); PUTBITSHIGH( thumbH_word1, !bit, 1, 63); // Make sure that green overflows: a = GETBITSHIGH( thumbH_word1, 1, 52); b = GETBITSHIGH( thumbH_word1, 1, 51); c = GETBITSHIGH( thumbH_word1, 1, 49); d = GETBITSHIGH( thumbH_word1, 1, 48); // The following bit abcd bit sequences should be padded with ones: 0111, 1010, 1011, 1101, 1110, 1111 // The following logical expression checks for the presence of any of those: bit = (a & c) | (!a & b & c & d) | (a & b & !c & d); bits = 0xf*bit; PUTBITSHIGH( thumbH_word1, bits, 3, 55); PUTBITSHIGH( thumbH_word1, !bit, 1, 50); // Set diffbit PUTBITSHIGH( thumbH_word1, 0, 1, 33); thumbH_word2 = thumbH58_word2; } // During search it is not convenient to store the bits the way they are stored in the // file format. Hence, after search, it is converted to this format. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void stuff59bits(unsigned int thumbT59_word1, unsigned int thumbT59_word2, unsigned int &thumbT_word1, unsigned int &thumbT_word2) { // Put bits in twotimer configuration for 59 (red overflows) // // Go from this bit layout: // // |63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 40 39|38 37 36 35|34 33 32| // |----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|--dist--| // // |31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| // |----------------------------------------index bits---------------------------------------------| // // // To this: // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // ----------------------------------------------------------------------------------------------- // |// // //|R0a |//|R0b |G0 |B0 |R1 |G1 |B1 |da |df|db| // ----------------------------------------------------------------------------------------------- // // |31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| // |----------------------------------------index bits---------------------------------------------| // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // ----------------------------------------------------------------------------------------------- // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |df|fp| // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bt|bt| // ------------------------------------------------------------------------------------------------ uint8 R0a; uint8 bit, a, b, c, d, bits; R0a = GETBITSHIGH( thumbT59_word1, 2, 58); // Fix middle part thumbT_word1 = thumbT59_word1 << 1; // Fix R0a (top two bits of R0) PUTBITSHIGH( thumbT_word1, R0a, 2, 60); // Fix db (lowest bit of d) PUTBITSHIGH( thumbT_word1, thumbT59_word1, 1, 32); // // Make sure that red overflows: a = GETBITSHIGH( thumbT_word1, 1, 60); b = GETBITSHIGH( thumbT_word1, 1, 59); c = GETBITSHIGH( thumbT_word1, 1, 57); d = GETBITSHIGH( thumbT_word1, 1, 56); // The following bit abcd bit sequences should be padded with ones: 0111, 1010, 1011, 1101, 1110, 1111 // The following logical expression checks for the presence of any of those: bit = (a & c) | (!a & b & c & d) | (a & b & !c & d); bits = 0xf*bit; PUTBITSHIGH( thumbT_word1, bits, 3, 63); PUTBITSHIGH( thumbT_word1, !bit, 1, 58); // Set diffbit PUTBITSHIGH( thumbT_word1, 1, 1, 33); thumbT_word2 = thumbT59_word2; } // Decompress the planar mode and calculate the error per component compared to original image. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void decompressBlockPlanar57errorPerComponent(unsigned int compressed57_1, unsigned int compressed57_2, uint8 *img,int width,int height,int startx,int starty, uint8 *srcimg, unsigned int &error_red, unsigned int &error_green, unsigned int &error_blue) { uint8 colorO[3], colorH[3], colorV[3]; colorO[0] = GETBITSHIGH( compressed57_1, 6, 63); colorO[1] = GETBITSHIGH( compressed57_1, 7, 57); colorO[2] = GETBITSHIGH( compressed57_1, 6, 50); colorH[0] = GETBITSHIGH( compressed57_1, 6, 44); colorH[1] = GETBITSHIGH( compressed57_1, 7, 38); colorH[2] = GETBITS( compressed57_2, 6, 31); colorV[0] = GETBITS( compressed57_2, 6, 25); colorV[1] = GETBITS( compressed57_2, 7, 19); colorV[2] = GETBITS( compressed57_2, 6, 12); colorO[0] = (colorO[0] << 2) | (colorO[0] >> 4); colorO[1] = (colorO[1] << 1) | (colorO[1] >> 6); colorO[2] = (colorO[2] << 2) | (colorO[2] >> 4); colorH[0] = (colorH[0] << 2) | (colorH[0] >> 4); colorH[1] = (colorH[1] << 1) | (colorH[1] >> 6); colorH[2] = (colorH[2] << 2) | (colorH[2] >> 4); colorV[0] = (colorV[0] << 2) | (colorV[0] >> 4); colorV[1] = (colorV[1] << 1) | (colorV[1] >> 6); colorV[2] = (colorV[2] << 2) | (colorV[2] >> 4); int xx, yy; for( xx=0; xx<4; xx++) { for( yy=0; yy<4; yy++) { img[3*width*(starty+yy) + 3*(startx+xx) + 0] = (int)CLAMP(0, JAS_ROUND((xx*(colorH[0]-colorO[0])/4.0 + yy*(colorV[0]-colorO[0])/4.0 + colorO[0])), 255); img[3*width*(starty+yy) + 3*(startx+xx) + 1] = (int)CLAMP(0, JAS_ROUND((xx*(colorH[1]-colorO[1])/4.0 + yy*(colorV[1]-colorO[1])/4.0 + colorO[1])), 255); img[3*width*(starty+yy) + 3*(startx+xx) + 2] = (int)CLAMP(0, JAS_ROUND((xx*(colorH[2]-colorO[2])/4.0 + yy*(colorV[2]-colorO[2])/4.0 + colorO[2])), 255); } } error_red = 0; error_green= 0; error_blue = 0; for( xx=0; xx<4; xx++) { for( yy=0; yy<4; yy++) { error_red = error_red + SQUARE(srcimg[3*width*(starty+yy) + 3*(startx+xx) + 0] - img[3*width*(starty+yy) + 3*(startx+xx) + 0]); error_green = error_green + SQUARE(srcimg[3*width*(starty+yy) + 3*(startx+xx) + 1] - img[3*width*(starty+yy) + 3*(startx+xx) + 1]); error_blue = error_blue + SQUARE(srcimg[3*width*(starty+yy) + 3*(startx+xx) + 2] - img[3*width*(starty+yy) + 3*(startx+xx) + 2]); } } } // Compress using both individual and differential mode in ETC1/ETC2 using combined color // quantization. Both flip modes are tried. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressBlockDiffFlipCombined(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { unsigned int compressed1_norm, compressed2_norm; unsigned int compressed1_flip, compressed2_flip; uint8 avg_color_quant1[3], avg_color_quant2[3]; float avg_color_float1[3],avg_color_float2[3]; int enc_color1[3], enc_color2[3], diff[3]; int min_error=255*255*8*3; unsigned int best_table_indices1=0, best_table_indices2=0; unsigned int best_table1=0, best_table2=0; int diffbit; int norm_err=0; int flip_err=0; // First try normal blocks 2x4: computeAverageColor2x4noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor2x4noQuantFloat(img,width,height,startx+2,starty,avg_color_float2); // First test if avg_color1 is similar enough to avg_color2 so that // we can use differential coding of colors. float eps; uint8 dummy[3]; quantize555ColorCombined(avg_color_float1, enc_color1, dummy); quantize555ColorCombined(avg_color_float2, enc_color2, dummy); diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; if( (diff[0] >= -4) && (diff[0] <= 3) && (diff[1] >= -4) && (diff[1] <= 3) && (diff[2] >= -4) && (diff[2] <= 3) ) { diffbit = 1; // The difference to be coded: diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; avg_color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); avg_color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); avg_color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); avg_color_quant2[0] = enc_color2[0] << 3 | (enc_color2[0] >> 2); avg_color_quant2[1] = enc_color2[1] << 3 | (enc_color2[1] >> 2); avg_color_quant2[2] = enc_color2[2] << 3 | (enc_color2[2] >> 2); // Pack bits into the first word. // ETC1_RGB8_OES: // // a) bit layout in bits 63 through 32 if diffbit = 0 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // b) bit layout in bits 63 through 32 if diffbit = 1 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |diff|flip| // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // c) bit layout in bits 31 through 0 (in both cases) // // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 // -------------------------------------------------------------------------------------------------- // | most significant pixel index bits | least significant pixel index bits | // | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | // -------------------------------------------------------------------------------------------------- compressed1_norm = 0; PUTBITSHIGH( compressed1_norm, diffbit, 1, 33); PUTBITSHIGH( compressed1_norm, enc_color1[0], 5, 63); PUTBITSHIGH( compressed1_norm, enc_color1[1], 5, 55); PUTBITSHIGH( compressed1_norm, enc_color1[2], 5, 47); PUTBITSHIGH( compressed1_norm, diff[0], 3, 58); PUTBITSHIGH( compressed1_norm, diff[1], 3, 50); PUTBITSHIGH( compressed1_norm, diff[2], 3, 42); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; norm_err = 0; // left part of block norm_err = tryalltables_3bittable2x4(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // right part of block norm_err += tryalltables_3bittable2x4(img,width,height,startx+2,starty,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_norm, best_table1, 3, 39); PUTBITSHIGH( compressed1_norm, best_table2, 3, 36); PUTBITSHIGH( compressed1_norm, 0, 1, 32); compressed2_norm = 0; PUTBITS( compressed2_norm, (best_pixel_indices1_MSB ), 8, 23); PUTBITS( compressed2_norm, (best_pixel_indices2_MSB ), 8, 31); PUTBITS( compressed2_norm, (best_pixel_indices1_LSB ), 8, 7); PUTBITS( compressed2_norm, (best_pixel_indices2_LSB ), 8, 15); } else { diffbit = 0; // The difference is bigger than what fits in 555 plus delta-333, so we will have // to deal with 444 444. eps = (float) 0.0001; uint8 dummy[3]; quantize444ColorCombined(avg_color_float1, enc_color1, dummy); quantize444ColorCombined(avg_color_float2, enc_color2, dummy); avg_color_quant1[0] = enc_color1[0] << 4 | enc_color1[0]; avg_color_quant1[1] = enc_color1[1] << 4 | enc_color1[1]; avg_color_quant1[2] = enc_color1[2] << 4 | enc_color1[2]; avg_color_quant2[0] = enc_color2[0] << 4 | enc_color2[0]; avg_color_quant2[1] = enc_color2[1] << 4 | enc_color2[1]; avg_color_quant2[2] = enc_color2[2] << 4 | enc_color2[2]; // Pack bits into the first word. // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- compressed1_norm = 0; PUTBITSHIGH( compressed1_norm, diffbit, 1, 33); PUTBITSHIGH( compressed1_norm, enc_color1[0], 4, 63); PUTBITSHIGH( compressed1_norm, enc_color1[1], 4, 55); PUTBITSHIGH( compressed1_norm, enc_color1[2], 4, 47); PUTBITSHIGH( compressed1_norm, enc_color2[0], 4, 59); PUTBITSHIGH( compressed1_norm, enc_color2[1], 4, 51); PUTBITSHIGH( compressed1_norm, enc_color2[2], 4, 43); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; // left part of block norm_err = tryalltables_3bittable2x4(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // right part of block norm_err += tryalltables_3bittable2x4(img,width,height,startx+2,starty,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_norm, best_table1, 3, 39); PUTBITSHIGH( compressed1_norm, best_table2, 3, 36); PUTBITSHIGH( compressed1_norm, 0, 1, 32); compressed2_norm = 0; PUTBITS( compressed2_norm, (best_pixel_indices1_MSB ), 8, 23); PUTBITS( compressed2_norm, (best_pixel_indices2_MSB ), 8, 31); PUTBITS( compressed2_norm, (best_pixel_indices1_LSB ), 8, 7); PUTBITS( compressed2_norm, (best_pixel_indices2_LSB ), 8, 15); } // Now try flipped blocks 4x2: computeAverageColor4x2noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor4x2noQuantFloat(img,width,height,startx,starty+2,avg_color_float2); // First test if avg_color1 is similar enough to avg_color2 so that // we can use differential coding of colors. quantize555ColorCombined(avg_color_float1, enc_color1, dummy); quantize555ColorCombined(avg_color_float2, enc_color2, dummy); diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; if( (diff[0] >= -4) && (diff[0] <= 3) && (diff[1] >= -4) && (diff[1] <= 3) && (diff[2] >= -4) && (diff[2] <= 3) ) { diffbit = 1; // The difference to be coded: diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; avg_color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); avg_color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); avg_color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); avg_color_quant2[0] = enc_color2[0] << 3 | (enc_color2[0] >> 2); avg_color_quant2[1] = enc_color2[1] << 3 | (enc_color2[1] >> 2); avg_color_quant2[2] = enc_color2[2] << 3 | (enc_color2[2] >> 2); // Pack bits into the first word. compressed1_flip = 0; PUTBITSHIGH( compressed1_flip, diffbit, 1, 33); PUTBITSHIGH( compressed1_flip, enc_color1[0], 5, 63); PUTBITSHIGH( compressed1_flip, enc_color1[1], 5, 55); PUTBITSHIGH( compressed1_flip, enc_color1[2], 5, 47); PUTBITSHIGH( compressed1_flip, diff[0], 3, 58); PUTBITSHIGH( compressed1_flip, diff[1], 3, 50); PUTBITSHIGH( compressed1_flip, diff[2], 3, 42); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; // upper part of block flip_err = tryalltables_3bittable4x2(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // lower part of block flip_err += tryalltables_3bittable4x2(img,width,height,startx,starty+2,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_flip, best_table1, 3, 39); PUTBITSHIGH( compressed1_flip, best_table2, 3, 36); PUTBITSHIGH( compressed1_flip, 1, 1, 32); best_pixel_indices1_MSB |= (best_pixel_indices2_MSB << 2); best_pixel_indices1_LSB |= (best_pixel_indices2_LSB << 2); compressed2_flip = ((best_pixel_indices1_MSB & 0xffff) << 16) | (best_pixel_indices1_LSB & 0xffff); } else { diffbit = 0; // The difference is bigger than what fits in 555 plus delta-333, so we will have // to deal with 444 444. eps = (float) 0.0001; uint8 dummy[3]; quantize444ColorCombined(avg_color_float1, enc_color1, dummy); quantize444ColorCombined(avg_color_float2, enc_color2, dummy); avg_color_quant1[0] = enc_color1[0] << 4 | enc_color1[0]; avg_color_quant1[1] = enc_color1[1] << 4 | enc_color1[1]; avg_color_quant1[2] = enc_color1[2] << 4 | enc_color1[2]; avg_color_quant2[0] = enc_color2[0] << 4 | enc_color2[0]; avg_color_quant2[1] = enc_color2[1] << 4 | enc_color2[1]; avg_color_quant2[2] = enc_color2[2] << 4 | enc_color2[2]; // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // Pack bits into the first word. compressed1_flip = 0; PUTBITSHIGH( compressed1_flip, diffbit, 1, 33); PUTBITSHIGH( compressed1_flip, enc_color1[0], 4, 63); PUTBITSHIGH( compressed1_flip, enc_color1[1], 4, 55); PUTBITSHIGH( compressed1_flip, enc_color1[2], 4, 47); PUTBITSHIGH( compressed1_flip, enc_color2[0], 4, 59); PUTBITSHIGH( compressed1_flip, enc_color2[1], 4, 51); PUTBITSHIGH( compressed1_flip, enc_color2[2], 4, 43); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; // upper part of block flip_err = tryalltables_3bittable4x2(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // lower part of block flip_err += tryalltables_3bittable4x2(img,width,height,startx,starty+2,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_flip, best_table1, 3, 39); PUTBITSHIGH( compressed1_flip, best_table2, 3, 36); PUTBITSHIGH( compressed1_flip, 1, 1, 32); best_pixel_indices1_MSB |= (best_pixel_indices2_MSB << 2); best_pixel_indices1_LSB |= (best_pixel_indices2_LSB << 2); compressed2_flip = ((best_pixel_indices1_MSB & 0xffff) << 16) | (best_pixel_indices1_LSB & 0xffff); } // Now lets see which is the best table to use. Only 8 tables are possible. if(norm_err <= flip_err) { compressed1 = compressed1_norm | 0; compressed2 = compressed2_norm; } else { compressed1 = compressed1_flip | 1; compressed2 = compressed2_flip; } } // Calculation of the two block colors using the LBG-algorithm // The following method scales down the intensity, since this can be compensated for anyway by both the H and T mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void computeColorLBGHalfIntensityFast(uint8 *img,int width,int startx,int starty, uint8 (LBG_colors)[2][3]) { uint8 block_mask[4][4]; // reset rand so that we get predictable output per block srand(10000); //LBG-algorithm double D = 0, oldD, bestD = MAXIMUM_ERROR, eps = 0.0000000001; double error_a, error_b; int number_of_iterations = 10; double t_color[2][3]; double original_colors[4][4][3]; double current_colors[2][3]; double best_colors[2][3]; double max_v[3]; double min_v[3]; int x,y,i; double red, green, blue; bool continue_seeding; int maximum_number_of_seedings = 10; int seeding; bool continue_iterate; max_v[R] = -512.0; max_v[G] = -512.0; max_v[B] = -512.0; min_v[R] = 512.0; min_v[G] = 512.0; min_v[B] = 512.0; // resolve trainingdata for (y = 0; y < BLOCKHEIGHT; ++y) { for (x = 0; x < BLOCKWIDTH; ++x) { red = img[3*((starty+y)*width+startx+x)+R]; green = img[3*((starty+y)*width+startx+x)+G]; blue = img[3*((starty+y)*width+startx+x)+B]; // Use qrs representation instead of rgb // qrs = Q * rgb where Q = [a a a ; b -b 0 ; c c -2c]; a = 1/sqrt(3), b= 1/sqrt(2), c = 1/sqrt(6); // rgb = inv(Q)*qrs = Q' * qrs where ' denotes transpose. // The q variable holds intensity. r and s hold chrominance. // q = [0, sqrt(3)*255], r = [-255/sqrt(2), 255/sqrt(2)], s = [-2*255/sqrt(6), 2*255/sqrt(6)]; // // The LGB algorithm will only act on the r and s variables and not on q. // original_colors[x][y][R] = (1.0/sqrt(1.0*3))*red + (1.0/sqrt(1.0*3))*green + (1.0/sqrt(1.0*3))*blue; original_colors[x][y][G] = (1.0/sqrt(1.0*2))*red - (1.0/sqrt(1.0*2))*green; original_colors[x][y][B] = (1.0/sqrt(1.0*6))*red + (1.0/sqrt(1.0*6))*green - (2.0/sqrt(1.0*6))*blue; // find max if (original_colors[x][y][R] > max_v[R]) max_v[R] = original_colors[x][y][R]; if (original_colors[x][y][G] > max_v[G]) max_v[G] = original_colors[x][y][G]; if (original_colors[x][y][B] > max_v[B]) max_v[B] = original_colors[x][y][B]; // find min if (original_colors[x][y][R] < min_v[R]) min_v[R] = original_colors[x][y][R]; if (original_colors[x][y][G] < min_v[G]) min_v[G] = original_colors[x][y][G]; if (original_colors[x][y][B] < min_v[B]) min_v[B] = original_colors[x][y][B]; } } D = 512*512*3*16.0; bestD = 512*512*3*16.0; continue_seeding = true; // loop seeds for (seeding = 0; (seeding < maximum_number_of_seedings) && continue_seeding; seeding++) { // hopefully we will not need more seedings: continue_seeding = false; // calculate seeds for (uint8 s = 0; s < 2; ++s) { for (uint8 c = 0; c < 3; ++c) { current_colors[s][c] = double((double(rand())/RAND_MAX)*(max_v[c]-min_v[c])) + min_v[c]; } } // divide into two quantization sets and calculate distortion continue_iterate = true; for(i = 0; (i < number_of_iterations) && continue_iterate; i++) { oldD = D; D = 0; int n = 0; for (y = 0; y < BLOCKHEIGHT; ++y) { for (int x = 0; x < BLOCKWIDTH; ++x) { error_a = 0.5*SQUARE(original_colors[x][y][R] - current_colors[0][R]) + SQUARE(original_colors[x][y][G] - current_colors[0][G]) + SQUARE(original_colors[x][y][B] - current_colors[0][B]); error_b = 0.5*SQUARE(original_colors[x][y][R] - current_colors[1][R]) + SQUARE(original_colors[x][y][G] - current_colors[1][G]) + SQUARE(original_colors[x][y][B] - current_colors[1][B]); if (error_a < error_b) { block_mask[x][y] = 0; D += error_a; ++n; } else { block_mask[x][y] = 1; D += error_b; } } } // compare with old distortion if (D == 0) { // Perfect score -- we dont need to go further iterations. continue_iterate = false; continue_seeding = false; } if (D == oldD) { // Same score as last round -- no need to go for further iterations. continue_iterate = false; continue_seeding = false; } if (D < bestD) { bestD = D; for(uint8 s = 0; s < 2; ++s) { for(uint8 c = 0; c < 3; ++c) { best_colors[s][c] = current_colors[s][c]; } } } if (n == 0 || n == BLOCKWIDTH*BLOCKHEIGHT) { // All colors end up in the same voroni region. We need to reseed. continue_iterate = false; continue_seeding = true; } else { // Calculate new reconstruction points using the centroids // Find new construction values from average t_color[0][R] = 0; t_color[0][G] = 0; t_color[0][B] = 0; t_color[1][R] = 0; t_color[1][G] = 0; t_color[1][B] = 0; for (y = 0; y < BLOCKHEIGHT; ++y) { for (int x = 0; x < BLOCKWIDTH; ++x) { // use dummy value for q-parameter t_color[block_mask[x][y]][R] += original_colors[x][y][R]; t_color[block_mask[x][y]][G] += original_colors[x][y][G]; t_color[block_mask[x][y]][B] += original_colors[x][y][B]; } } current_colors[0][R] = t_color[0][R] / n; current_colors[1][R] = t_color[1][R] / (BLOCKWIDTH*BLOCKHEIGHT - n); current_colors[0][G] = t_color[0][G] / n; current_colors[1][G] = t_color[1][G] / (BLOCKWIDTH*BLOCKHEIGHT - n); current_colors[0][B] = t_color[0][B] / n; current_colors[1][B] = t_color[1][B] / (BLOCKWIDTH*BLOCKHEIGHT - n); } } } for(x=0;x<2;x++) { double qq, rr, ss; qq = best_colors[x][0]; rr = best_colors[x][1]; ss = best_colors[x][2]; current_colors[x][0] = CLAMP(0, (1.0/sqrt(1.0*3))*qq + (1.0/sqrt(1.0*2))*rr + (1.0/sqrt(1.0*6))*ss, 255); current_colors[x][1] = CLAMP(0, (1.0/sqrt(1.0*3))*qq - (1.0/sqrt(1.0*2))*rr + (1.0/sqrt(1.0*6))*ss, 255); current_colors[x][2] = CLAMP(0, (1.0/sqrt(1.0*3))*qq + (0.0 )*rr - (2.0/sqrt(1.0*6))*ss, 255); } for(x=0;x<2;x++) for(y=0;y<3;y++) LBG_colors[x][y] = JAS_ROUND(current_colors[x][y]); } // Calculation of the two block colors using the LBG-algorithm // The following method scales down the intensity, since this can be compensated for anyway by both the H and T mode. // Faster version // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void computeColorLBGNotIntensityFast(uint8 *img,int width,int startx,int starty, uint8 (LBG_colors)[2][3]) { uint8 block_mask[4][4]; // reset rand so that we get predictable output per block srand(10000); //LBG-algorithm double D = 0, oldD, bestD = MAXIMUM_ERROR, eps = 0.0000000001; double error_a, error_b; int number_of_iterations = 10; double t_color[2][3]; double original_colors[4][4][3]; double current_colors[2][3]; double best_colors[2][3]; double max_v[3]; double min_v[3]; int x,y,i; double red, green, blue; bool continue_seeding; int maximum_number_of_seedings = 10; int seeding; bool continue_iterate; max_v[R] = -512.0; max_v[G] = -512.0; max_v[B] = -512.0; min_v[R] = 512.0; min_v[G] = 512.0; min_v[B] = 512.0; // resolve trainingdata for (y = 0; y < BLOCKHEIGHT; ++y) { for (x = 0; x < BLOCKWIDTH; ++x) { red = img[3*((starty+y)*width+startx+x)+R]; green = img[3*((starty+y)*width+startx+x)+G]; blue = img[3*((starty+y)*width+startx+x)+B]; // Use qrs representation instead of rgb // qrs = Q * rgb where Q = [a a a ; b -b 0 ; c c -2c]; a = 1/sqrt(1.0*3), b= 1/sqrt(1.0*2), c = 1/sqrt(1.0*6); // rgb = inv(Q)*qrs = Q' * qrs where ' denotes transpose. // The q variable holds intensity. r and s hold chrominance. // q = [0, sqrt(1.0*3)*255], r = [-255/sqrt(1.0*2), 255/sqrt(1.0*2)], s = [-2*255/sqrt(1.0*6), 2*255/sqrt(1.0*6)]; // // The LGB algorithm will only act on the r and s variables and not on q. // original_colors[x][y][R] = (1.0/sqrt(1.0*3))*red + (1.0/sqrt(1.0*3))*green + (1.0/sqrt(1.0*3))*blue; original_colors[x][y][G] = (1.0/sqrt(1.0*2))*red - (1.0/sqrt(1.0*2))*green; original_colors[x][y][B] = (1.0/sqrt(1.0*6))*red + (1.0/sqrt(1.0*6))*green - (2.0/sqrt(1.0*6))*blue; // find max if (original_colors[x][y][R] > max_v[R]) max_v[R] = original_colors[x][y][R]; if (original_colors[x][y][G] > max_v[G]) max_v[G] = original_colors[x][y][G]; if (original_colors[x][y][B] > max_v[B]) max_v[B] = original_colors[x][y][B]; // find min if (original_colors[x][y][R] < min_v[R]) min_v[R] = original_colors[x][y][R]; if (original_colors[x][y][G] < min_v[G]) min_v[G] = original_colors[x][y][G]; if (original_colors[x][y][B] < min_v[B]) min_v[B] = original_colors[x][y][B]; } } D = 512*512*3*16.0; bestD = 512*512*3*16.0; continue_seeding = true; // loop seeds for (seeding = 0; (seeding < maximum_number_of_seedings) && continue_seeding; seeding++) { // hopefully we will not need more seedings: continue_seeding = false; // calculate seeds for (uint8 s = 0; s < 2; ++s) { for (uint8 c = 0; c < 3; ++c) { current_colors[s][c] = double((double(rand())/RAND_MAX)*(max_v[c]-min_v[c])) + min_v[c]; } } // divide into two quantization sets and calculate distortion continue_iterate = true; for(i = 0; (i < number_of_iterations) && continue_iterate; i++) { oldD = D; D = 0; int n = 0; for (y = 0; y < BLOCKHEIGHT; ++y) { for (int x = 0; x < BLOCKWIDTH; ++x) { error_a = 0.0*SQUARE(original_colors[x][y][R] - current_colors[0][R]) + SQUARE(original_colors[x][y][G] - current_colors[0][G]) + SQUARE(original_colors[x][y][B] - current_colors[0][B]); error_b = 0.0*SQUARE(original_colors[x][y][R] - current_colors[1][R]) + SQUARE(original_colors[x][y][G] - current_colors[1][G]) + SQUARE(original_colors[x][y][B] - current_colors[1][B]); if (error_a < error_b) { block_mask[x][y] = 0; D += error_a; ++n; } else { block_mask[x][y] = 1; D += error_b; } } } // compare with old distortion if (D == 0) { // Perfect score -- we dont need to go further iterations. continue_iterate = false; continue_seeding = false; } if (D == oldD) { // Same score as last round -- no need to go for further iterations. continue_iterate = false; continue_seeding = false; } if (D < bestD) { bestD = D; for(uint8 s = 0; s < 2; ++s) { for(uint8 c = 0; c < 3; ++c) { best_colors[s][c] = current_colors[s][c]; } } } if (n == 0 || n == BLOCKWIDTH*BLOCKHEIGHT) { // All colors end up in the same voroni region. We need to reseed. continue_iterate = false; continue_seeding = true; } else { // Calculate new reconstruction points using the centroids // Find new construction values from average t_color[0][R] = 0; t_color[0][G] = 0; t_color[0][B] = 0; t_color[1][R] = 0; t_color[1][G] = 0; t_color[1][B] = 0; for (y = 0; y < BLOCKHEIGHT; ++y) { for (int x = 0; x < BLOCKWIDTH; ++x) { // use dummy value for q-parameter t_color[block_mask[x][y]][R] += original_colors[x][y][R]; t_color[block_mask[x][y]][G] += original_colors[x][y][G]; t_color[block_mask[x][y]][B] += original_colors[x][y][B]; } } current_colors[0][R] = t_color[0][R] / n; current_colors[1][R] = t_color[1][R] / (BLOCKWIDTH*BLOCKHEIGHT - n); current_colors[0][G] = t_color[0][G] / n; current_colors[1][G] = t_color[1][G] / (BLOCKWIDTH*BLOCKHEIGHT - n); current_colors[0][B] = t_color[0][B] / n; current_colors[1][B] = t_color[1][B] / (BLOCKWIDTH*BLOCKHEIGHT - n); } } } for(x=0;x<2;x++) { double qq, rr, ss; qq = best_colors[x][0]; rr = best_colors[x][1]; ss = best_colors[x][2]; current_colors[x][0] = CLAMP(0, (1.0/sqrt(1.0*3))*qq + (1.0/sqrt(1.0*2))*rr + (1.0/sqrt(1.0*6))*ss, 255); current_colors[x][1] = CLAMP(0, (1.0/sqrt(1.0*3))*qq - (1.0/sqrt(1.0*2))*rr + (1.0/sqrt(1.0*6))*ss, 255); current_colors[x][2] = CLAMP(0, (1.0/sqrt(1.0*3))*qq + (0.0 )*rr - (2.0/sqrt(1.0*6))*ss, 255); } for(x=0;x<2;x++) for(y=0;y<3;y++) LBG_colors[x][y] = JAS_ROUND(current_colors[x][y]); } // Calculation of the two block colors using the LBG-algorithm // The following method completely ignores the intensity, since this can be compensated for anyway by both the H and T mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void computeColorLBGNotIntensity(uint8 *img,int width,int startx,int starty, uint8 (LBG_colors)[2][3]) { uint8 block_mask[4][4]; // reset rand so that we get predictable output per block srand(10000); //LBG-algorithm double D = 0, oldD, bestD = MAXIMUM_ERROR, eps = 0.0000000001; double error_a, error_b; int number_of_iterations = 10; double t_color[2][3]; double original_colors[4][4][3]; double current_colors[2][3]; double best_colors[2][3]; double max_v[3]; double min_v[3]; int x,y,i; double red, green, blue; bool continue_seeding; int maximum_number_of_seedings = 10; int seeding; bool continue_iterate; max_v[R] = -512.0; max_v[G] = -512.0; max_v[B] = -512.0; min_v[R] = 512.0; min_v[G] = 512.0; min_v[B] = 512.0; // resolve trainingdata for (y = 0; y < BLOCKHEIGHT; ++y) { for (x = 0; x < BLOCKWIDTH; ++x) { red = img[3*((starty+y)*width+startx+x)+R]; green = img[3*((starty+y)*width+startx+x)+G]; blue = img[3*((starty+y)*width+startx+x)+B]; // Use qrs representation instead of rgb // qrs = Q * rgb where Q = [a a a ; b -b 0 ; c c -2c]; a = 1/sqrt(1.0*3), b= 1/sqrt(1.0*2), c = 1/sqrt(1.0*6); // rgb = inv(Q)*qrs = Q' * qrs where ' denotes transpose. // The q variable holds intensity. r and s hold chrominance. // q = [0, sqrt(1.0*3)*255], r = [-255/sqrt(1.0*2), 255/sqrt(1.0*2)], s = [-2*255/sqrt(1.0*6), 2*255/sqrt(1.0*6)]; // // The LGB algorithm will only act on the r and s variables and not on q. // original_colors[x][y][R] = (1.0/sqrt(1.0*3))*red + (1.0/sqrt(1.0*3))*green + (1.0/sqrt(1.0*3))*blue; original_colors[x][y][G] = (1.0/sqrt(1.0*2))*red - (1.0/sqrt(1.0*2))*green; original_colors[x][y][B] = (1.0/sqrt(1.0*6))*red + (1.0/sqrt(1.0*6))*green - (2.0/sqrt(1.0*6))*blue; // find max if (original_colors[x][y][R] > max_v[R]) max_v[R] = original_colors[x][y][R]; if (original_colors[x][y][G] > max_v[G]) max_v[G] = original_colors[x][y][G]; if (original_colors[x][y][B] > max_v[B]) max_v[B] = original_colors[x][y][B]; // find min if (original_colors[x][y][R] < min_v[R]) min_v[R] = original_colors[x][y][R]; if (original_colors[x][y][G] < min_v[G]) min_v[G] = original_colors[x][y][G]; if (original_colors[x][y][B] < min_v[B]) min_v[B] = original_colors[x][y][B]; } } D = 512*512*3*16.0; bestD = 512*512*3*16.0; continue_seeding = true; // loop seeds for (seeding = 0; (seeding < maximum_number_of_seedings) && continue_seeding; seeding++) { // hopefully we will not need more seedings: continue_seeding = false; // calculate seeds for (uint8 s = 0; s < 2; ++s) { for (uint8 c = 0; c < 3; ++c) { current_colors[s][c] = double((double(rand())/RAND_MAX)*(max_v[c]-min_v[c])) + min_v[c]; } } // divide into two quantization sets and calculate distortion continue_iterate = true; for(i = 0; (i < number_of_iterations) && continue_iterate; i++) { oldD = D; D = 0; int n = 0; for (y = 0; y < BLOCKHEIGHT; ++y) { for (int x = 0; x < BLOCKWIDTH; ++x) { error_a = 0.0*SQUARE(original_colors[x][y][R] - current_colors[0][R]) + SQUARE(original_colors[x][y][G] - current_colors[0][G]) + SQUARE(original_colors[x][y][B] - current_colors[0][B]); error_b = 0.0*SQUARE(original_colors[x][y][R] - current_colors[1][R]) + SQUARE(original_colors[x][y][G] - current_colors[1][G]) + SQUARE(original_colors[x][y][B] - current_colors[1][B]); if (error_a < error_b) { block_mask[x][y] = 0; D += error_a; ++n; } else { block_mask[x][y] = 1; D += error_b; } } } // compare with old distortion if (D == 0) { // Perfect score -- we dont need to go further iterations. continue_iterate = false; continue_seeding = false; } if (D == oldD) { // Same score as last round -- no need to go for further iterations. continue_iterate = false; continue_seeding = true; } if (D < bestD) { bestD = D; for(uint8 s = 0; s < 2; ++s) { for(uint8 c = 0; c < 3; ++c) { best_colors[s][c] = current_colors[s][c]; } } } if (n == 0 || n == BLOCKWIDTH*BLOCKHEIGHT) { // All colors end up in the same voroni region. We need to reseed. continue_iterate = false; continue_seeding = true; } else { // Calculate new reconstruction points using the centroids // Find new construction values from average t_color[0][R] = 0; t_color[0][G] = 0; t_color[0][B] = 0; t_color[1][R] = 0; t_color[1][G] = 0; t_color[1][B] = 0; for (y = 0; y < BLOCKHEIGHT; ++y) { for (int x = 0; x < BLOCKWIDTH; ++x) { // use dummy value for q-parameter t_color[block_mask[x][y]][R] += original_colors[x][y][R]; t_color[block_mask[x][y]][G] += original_colors[x][y][G]; t_color[block_mask[x][y]][B] += original_colors[x][y][B]; } } current_colors[0][R] = t_color[0][R] / n; current_colors[1][R] = t_color[1][R] / (BLOCKWIDTH*BLOCKHEIGHT - n); current_colors[0][G] = t_color[0][G] / n; current_colors[1][G] = t_color[1][G] / (BLOCKWIDTH*BLOCKHEIGHT - n); current_colors[0][B] = t_color[0][B] / n; current_colors[1][B] = t_color[1][B] / (BLOCKWIDTH*BLOCKHEIGHT - n); } } } for(x=0;x<2;x++) { double qq, rr, ss; qq = best_colors[x][0]; rr = best_colors[x][1]; ss = best_colors[x][2]; current_colors[x][0] = CLAMP(0, (1.0/sqrt(1.0*3))*qq + (1.0/sqrt(1.0*2))*rr + (1.0/sqrt(1.0*6))*ss, 255); current_colors[x][1] = CLAMP(0, (1.0/sqrt(1.0*3))*qq - (1.0/sqrt(1.0*2))*rr + (1.0/sqrt(1.0*6))*ss, 255); current_colors[x][2] = CLAMP(0, (1.0/sqrt(1.0*3))*qq + (0.0 )*rr - (2.0/sqrt(1.0*6))*ss, 255); } for(x=0;x<2;x++) for(y=0;y<3;y++) LBG_colors[x][y] = JAS_ROUND(current_colors[x][y]); } // Calculation of the two block colors using the LBG-algorithm // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void computeColorLBG(uint8 *img,int width,int startx,int starty, uint8 (LBG_colors)[2][3]) { uint8 block_mask[4][4]; // reset rand so that we get predictable output per block srand(10000); //LBG-algorithm double D = 0, oldD, bestD = MAXIMUM_ERROR, eps = 0.0000000001; double error_a, error_b; int number_of_iterations = 10; double t_color[2][3]; double original_colors[4][4][3]; double current_colors[2][3]; double best_colors[2][3]; double max_v[3]; double min_v[3]; int x,y,i; double red, green, blue; bool continue_seeding; int maximum_number_of_seedings = 10; int seeding; bool continue_iterate; max_v[R] = -512.0; max_v[G] = -512.0; max_v[B] = -512.0; min_v[R] = 512.0; min_v[G] = 512.0; min_v[B] = 512.0; // resolve trainingdata for (y = 0; y < BLOCKHEIGHT; ++y) { for (x = 0; x < BLOCKWIDTH; ++x) { red = img[3*((starty+y)*width+startx+x)+R]; green = img[3*((starty+y)*width+startx+x)+G]; blue = img[3*((starty+y)*width+startx+x)+B]; original_colors[x][y][R] = red; original_colors[x][y][G] = green; original_colors[x][y][B] = blue; // find max if (original_colors[x][y][R] > max_v[R]) max_v[R] = original_colors[x][y][R]; if (original_colors[x][y][G] > max_v[G]) max_v[G] = original_colors[x][y][G]; if (original_colors[x][y][B] > max_v[B]) max_v[B] = original_colors[x][y][B]; // find min if (original_colors[x][y][R] < min_v[R]) min_v[R] = original_colors[x][y][R]; if (original_colors[x][y][G] < min_v[G]) min_v[G] = original_colors[x][y][G]; if (original_colors[x][y][B] < min_v[B]) min_v[B] = original_colors[x][y][B]; } } D = 512*512*3*16.0; bestD = 512*512*3*16.0; continue_seeding = true; // loop seeds for (seeding = 0; (seeding < maximum_number_of_seedings) && continue_seeding; seeding++) { // hopefully we will not need more seedings: continue_seeding = false; // calculate seeds for (uint8 s = 0; s < 2; ++s) { for (uint8 c = 0; c < 3; ++c) { current_colors[s][c] = double((double(rand())/RAND_MAX)*(max_v[c]-min_v[c])) + min_v[c]; } } // divide into two quantization sets and calculate distortion continue_iterate = true; for(i = 0; (i < number_of_iterations) && continue_iterate; i++) { oldD = D; D = 0; int n = 0; for (y = 0; y < BLOCKHEIGHT; ++y) { for (int x = 0; x < BLOCKWIDTH; ++x) { error_a = SQUARE(original_colors[x][y][R] - JAS_ROUND(current_colors[0][R])) + SQUARE(original_colors[x][y][G] - JAS_ROUND(current_colors[0][G])) + SQUARE(original_colors[x][y][B] - JAS_ROUND(current_colors[0][B])); error_b = SQUARE(original_colors[x][y][R] - JAS_ROUND(current_colors[1][R])) + SQUARE(original_colors[x][y][G] - JAS_ROUND(current_colors[1][G])) + SQUARE(original_colors[x][y][B] - JAS_ROUND(current_colors[1][B])); if (error_a < error_b) { block_mask[x][y] = 0; D += error_a; ++n; } else { block_mask[x][y] = 1; D += error_b; } } } // compare with old distortion if (D == 0) { // Perfect score -- we dont need to go further iterations. continue_iterate = false; continue_seeding = false; } if (D == oldD) { // Same score as last round -- no need to go for further iterations. continue_iterate = false; continue_seeding = true; } if (D < bestD) { bestD = D; for(uint8 s = 0; s < 2; ++s) { for(uint8 c = 0; c < 3; ++c) { best_colors[s][c] = current_colors[s][c]; } } } if (n == 0 || n == BLOCKWIDTH*BLOCKHEIGHT) { // All colors end up in the same voroni region. We need to reseed. continue_iterate = false; continue_seeding = true; } else { // Calculate new reconstruction points using the centroids // Find new construction values from average t_color[0][R] = 0; t_color[0][G] = 0; t_color[0][B] = 0; t_color[1][R] = 0; t_color[1][G] = 0; t_color[1][B] = 0; for (y = 0; y < BLOCKHEIGHT; ++y) { for (int x = 0; x < BLOCKWIDTH; ++x) { // use dummy value for q-parameter t_color[block_mask[x][y]][R] += original_colors[x][y][R]; t_color[block_mask[x][y]][G] += original_colors[x][y][G]; t_color[block_mask[x][y]][B] += original_colors[x][y][B]; } } current_colors[0][R] = t_color[0][R] / n; current_colors[1][R] = t_color[1][R] / (BLOCKWIDTH*BLOCKHEIGHT - n); current_colors[0][G] = t_color[0][G] / n; current_colors[1][G] = t_color[1][G] / (BLOCKWIDTH*BLOCKHEIGHT - n); current_colors[0][B] = t_color[0][B] / n; current_colors[1][B] = t_color[1][B] / (BLOCKWIDTH*BLOCKHEIGHT - n); } } } // Set the best colors as the final block colors for(int s = 0; s < 2; ++s) { for(uint8 c = 0; c < 3; ++c) { current_colors[s][c] = best_colors[s][c]; } } for(x=0;x<2;x++) for(y=0;y<3;y++) LBG_colors[x][y] = JAS_ROUND(current_colors[x][y]); } // Calculation of the two block colors using the LBG-algorithm // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void computeColorLBGfast(uint8 *img,int width,int startx,int starty, uint8 (LBG_colors)[2][3]) { uint8 block_mask[4][4]; // reset rand so that we get predictable output per block srand(10000); //LBG-algorithm double D = 0, oldD, bestD = MAXIMUM_ERROR, eps = 0.0000000001; double error_a, error_b; int number_of_iterations = 10; double t_color[2][3]; uint8 original_colors[4][4][3]; double current_colors[2][3]; double best_colors[2][3]; double max_v[3]; double min_v[3]; int x,y,i; bool continue_seeding; int maximum_number_of_seedings = 10; int seeding; bool continue_iterate; max_v[R] = -512.0; max_v[G] = -512.0; max_v[B] = -512.0; min_v[R] = 512.0; min_v[G] = 512.0; min_v[B] = 512.0; // resolve trainingdata for (y = 0; y < BLOCKHEIGHT; ++y) { for (x = 0; x < BLOCKWIDTH; ++x) { original_colors[x][y][R] = img[3*((starty+y)*width+startx+x)+R]; original_colors[x][y][G] = img[3*((starty+y)*width+startx+x)+G]; original_colors[x][y][B] = img[3*((starty+y)*width+startx+x)+B]; // find max if (original_colors[x][y][R] > max_v[R]) max_v[R] = original_colors[x][y][R]; if (original_colors[x][y][G] > max_v[G]) max_v[G] = original_colors[x][y][G]; if (original_colors[x][y][B] > max_v[B]) max_v[B] = original_colors[x][y][B]; // find min if (original_colors[x][y][R] < min_v[R]) min_v[R] = original_colors[x][y][R]; if (original_colors[x][y][G] < min_v[G]) min_v[G] = original_colors[x][y][G]; if (original_colors[x][y][B] < min_v[B]) min_v[B] = original_colors[x][y][B]; } } D = 512*512*3*16.0; bestD = 512*512*3*16.0; continue_seeding = true; // loop seeds for (seeding = 0; (seeding < maximum_number_of_seedings) && continue_seeding; seeding++) { // hopefully we will not need more seedings: continue_seeding = false; // calculate seeds for (uint8 s = 0; s < 2; ++s) { for (uint8 c = 0; c < 3; ++c) { current_colors[s][c] = double((double(rand())/RAND_MAX)*(max_v[c]-min_v[c])) + min_v[c]; } } // divide into two quantization sets and calculate distortion continue_iterate = true; for(i = 0; (i < number_of_iterations) && continue_iterate; i++) { oldD = D; D = 0; int n = 0; for (y = 0; y < BLOCKHEIGHT; ++y) { for (int x = 0; x < BLOCKWIDTH; ++x) { error_a = SQUARE(original_colors[x][y][R] - JAS_ROUND(current_colors[0][R])) + SQUARE(original_colors[x][y][G] - JAS_ROUND(current_colors[0][G])) + SQUARE(original_colors[x][y][B] - JAS_ROUND(current_colors[0][B])); error_b = SQUARE(original_colors[x][y][R] - JAS_ROUND(current_colors[1][R])) + SQUARE(original_colors[x][y][G] - JAS_ROUND(current_colors[1][G])) + SQUARE(original_colors[x][y][B] - JAS_ROUND(current_colors[1][B])); if (error_a < error_b) { block_mask[x][y] = 0; D += error_a; ++n; } else { block_mask[x][y] = 1; D += error_b; } } } // compare with old distortion if (D == 0) { // Perfect score -- we dont need to go further iterations. continue_iterate = false; continue_seeding = false; } if (D == oldD) { // Same score as last round -- no need to go for further iterations. continue_iterate = false; continue_seeding = false; } if (D < bestD) { bestD = D; for(uint8 s = 0; s < 2; ++s) { for(uint8 c = 0; c < 3; ++c) { best_colors[s][c] = current_colors[s][c]; } } } if (n == 0 || n == BLOCKWIDTH*BLOCKHEIGHT) { // All colors end up in the same voroni region. We need to reseed. continue_iterate = false; continue_seeding = true; } else { // Calculate new reconstruction points using the centroids // Find new construction values from average t_color[0][R] = 0; t_color[0][G] = 0; t_color[0][B] = 0; t_color[1][R] = 0; t_color[1][G] = 0; t_color[1][B] = 0; for (y = 0; y < BLOCKHEIGHT; ++y) { for (int x = 0; x < BLOCKWIDTH; ++x) { // use dummy value for q-parameter t_color[block_mask[x][y]][R] += original_colors[x][y][R]; t_color[block_mask[x][y]][G] += original_colors[x][y][G]; t_color[block_mask[x][y]][B] += original_colors[x][y][B]; } } current_colors[0][R] = t_color[0][R] / n; current_colors[1][R] = t_color[1][R] / (BLOCKWIDTH*BLOCKHEIGHT - n); current_colors[0][G] = t_color[0][G] / n; current_colors[1][G] = t_color[1][G] / (BLOCKWIDTH*BLOCKHEIGHT - n); current_colors[0][B] = t_color[0][B] / n; current_colors[1][B] = t_color[1][B] / (BLOCKWIDTH*BLOCKHEIGHT - n); } } } // Set the best colors as the final block colors for(int s = 0; s < 2; ++s) { for(uint8 c = 0; c < 3; ++c) { current_colors[s][c] = best_colors[s][c]; } } for(x=0;x<2;x++) for(y=0;y<3;y++) LBG_colors[x][y] = JAS_ROUND(current_colors[x][y]); } // Each color component is compressed to fit in its specified number of bits // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressColor(int R_B, int G_B, int B_B, uint8 (current_color)[2][3], uint8 (quantized_color)[2][3]) { // // The color is calculated as: // // c = (c + (2^(8-b))/2) / (255 / (2^b - 1)) where b is the number of bits // to code color c with // For instance, if b = 3: // // c = (c + 16) / (255 / 7) = 7 * (c + 16) / 255 // quantized_color[0][R] = CLAMP(0,(BINPOW(R_B)-1) * (current_color[0][R] + BINPOW(8-R_B-1)) / 255,255); quantized_color[0][G] = CLAMP(0,(BINPOW(G_B)-1) * (current_color[0][G] + BINPOW(8-G_B-1)) / 255,255); quantized_color[0][B] = CLAMP(0,(BINPOW(B_B)-1) * (current_color[0][B] + BINPOW(8-B_B-1)) / 255,255); quantized_color[1][R] = CLAMP(0,(BINPOW(R_B)-1) * (current_color[1][R] + BINPOW(8-R_B-1)) / 255,255); quantized_color[1][G] = CLAMP(0,(BINPOW(G_B)-1) * (current_color[1][G] + BINPOW(8-G_B-1)) / 255,255); quantized_color[1][B] = CLAMP(0,(BINPOW(B_B)-1) * (current_color[1][B] + BINPOW(8-B_B-1)) / 255,255); } // Swapping two RGB-colors // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void swapColors(uint8 (colors)[2][3]) { uint8 temp = colors[0][R]; colors[0][R] = colors[1][R]; colors[1][R] = temp; temp = colors[0][G]; colors[0][G] = colors[1][G]; colors[1][G] = temp; temp = colors[0][B]; colors[0][B] = colors[1][B]; colors[1][B] = temp; } // Calculate the paint colors from the block colors // using a distance d and one of the H- or T-patterns. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. // Calculate the error for the block at position (startx,starty) // The parameters needed for reconstruction are calculated as well // // Please note that the function can change the order between the two colors in colorsRGB444 // // In the 59T bit mode, we only have pattern T. // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateError59Tperceptual1000(uint8* srcimg, int width, int startx, int starty, uint8 (colorsRGB444)[2][3], uint8 &distance, unsigned int &pixel_indices) { unsigned int block_error = 0, best_block_error = MAXERR1000, pixel_error, best_pixel_error; int diff[3]; uint8 best_sw; unsigned int pixel_colors; uint8 colors[2][3]; uint8 possible_colors[4][3]; // First use the colors as they are, then swap them for (uint8 sw = 0; sw <2; ++sw) { if (sw == 1) { swapColors(colorsRGB444); } decompressColor(R_BITS59T, G_BITS59T, B_BITS59T, colorsRGB444, colors); // Test all distances for (uint8 d = 0; d < BINPOW(TABLE_BITS_59T); ++d) { calculatePaintColors59T(d,PATTERN_T, colors, possible_colors); block_error = 0; pixel_colors = 0; // Loop block for (size_t y = 0; y < BLOCKHEIGHT; ++y) { for (size_t x = 0; x < BLOCKWIDTH; ++x) { best_pixel_error = MAXERR1000; pixel_colors <<=2; // Make room for next value // Loop possible block colors for (uint8 c = 0; c < 4; ++c) { diff[R] = srcimg[3*((starty+y)*width+startx+x)+R] - CLAMP(0,possible_colors[c][R],255); diff[G] = srcimg[3*((starty+y)*width+startx+x)+G] - CLAMP(0,possible_colors[c][G],255); diff[B] = srcimg[3*((starty+y)*width+startx+x)+B] - CLAMP(0,possible_colors[c][B],255); pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*SQUARE(diff[R]) + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000*SQUARE(diff[G]) + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*SQUARE(diff[B]); // Choose best error if (pixel_error < best_pixel_error) { best_pixel_error = pixel_error; pixel_colors ^= (pixel_colors & 3); // Reset the two first bits pixel_colors |= c; } } block_error += best_pixel_error; } } if (block_error < best_block_error) { best_block_error = block_error; distance = d; pixel_indices = pixel_colors; best_sw = sw; } } if (sw == 1 && best_sw == 0) { swapColors(colorsRGB444); } decompressColor(R_BITS59T, G_BITS59T, B_BITS59T, colorsRGB444, colors); } return best_block_error; } // Calculate the error for the block at position (startx,starty) // The parameters needed for reconstruction is calculated as well // // Please note that the function can change the order between the two colors in colorsRGB444 // // In the 59T bit mode, we only have pattern T. // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double calculateError59T(uint8* srcimg, int width, int startx, int starty, uint8 (colorsRGB444)[2][3], uint8 &distance, unsigned int &pixel_indices) { double block_error = 0, best_block_error = MAXIMUM_ERROR, pixel_error, best_pixel_error; int diff[3]; uint8 best_sw; unsigned int pixel_colors; uint8 colors[2][3]; uint8 possible_colors[4][3]; // First use the colors as they are, then swap them for (uint8 sw = 0; sw <2; ++sw) { if (sw == 1) { swapColors(colorsRGB444); } decompressColor(R_BITS59T, G_BITS59T, B_BITS59T, colorsRGB444, colors); // Test all distances for (uint8 d = 0; d < BINPOW(TABLE_BITS_59T); ++d) { calculatePaintColors59T(d,PATTERN_T, colors, possible_colors); block_error = 0; pixel_colors = 0; // Loop block for (size_t y = 0; y < BLOCKHEIGHT; ++y) { for (size_t x = 0; x < BLOCKWIDTH; ++x) { best_pixel_error = MAXIMUM_ERROR; pixel_colors <<=2; // Make room for next value // Loop possible block colors for (uint8 c = 0; c < 4; ++c) { diff[R] = srcimg[3*((starty+y)*width+startx+x)+R] - CLAMP(0,possible_colors[c][R],255); diff[G] = srcimg[3*((starty+y)*width+startx+x)+G] - CLAMP(0,possible_colors[c][G],255); diff[B] = srcimg[3*((starty+y)*width+startx+x)+B] - CLAMP(0,possible_colors[c][B],255); pixel_error = weight[R]*SQUARE(diff[R]) + weight[G]*SQUARE(diff[G]) + weight[B]*SQUARE(diff[B]); // Choose best error if (pixel_error < best_pixel_error) { best_pixel_error = pixel_error; pixel_colors ^= (pixel_colors & 3); // Reset the two first bits pixel_colors |= c; } } block_error += best_pixel_error; } } if (block_error < best_block_error) { best_block_error = block_error; distance = d; pixel_indices = pixel_colors; best_sw = sw; } } if (sw == 1 && best_sw == 0) { swapColors(colorsRGB444); } decompressColor(R_BITS59T, G_BITS59T, B_BITS59T, colorsRGB444, colors); } return best_block_error; } // Calculate the error for the block at position (startx,starty) // The parameters needed for reconstruction is calculated as well // // In the 59T bit mode, we only have pattern T. // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateError59TnoSwapPerceptual1000(uint8* srcimg, int width, int startx, int starty, uint8 (colorsRGB444)[2][3], uint8 &distance, unsigned int &pixel_indices) { unsigned int block_error = 0, best_block_error = MAXERR1000, pixel_error, best_pixel_error; int diff[3]; unsigned int pixel_colors; uint8 colors[2][3]; uint8 possible_colors[4][3]; int thebestintheworld; // First use the colors as they are, then swap them decompressColor(R_BITS59T, G_BITS59T, B_BITS59T, colorsRGB444, colors); // Test all distances for (uint8 d = 0; d < BINPOW(TABLE_BITS_59T); ++d) { calculatePaintColors59T(d,PATTERN_T, colors, possible_colors); block_error = 0; pixel_colors = 0; // Loop block for (size_t y = 0; y < BLOCKHEIGHT; ++y) { for (size_t x = 0; x < BLOCKWIDTH; ++x) { best_pixel_error = MAXERR1000; pixel_colors <<=2; // Make room for next value // Loop possible block colors for (uint8 c = 0; c < 4; ++c) { diff[R] = srcimg[3*((starty+y)*width+startx+x)+R] - CLAMP(0,possible_colors[c][R],255); diff[G] = srcimg[3*((starty+y)*width+startx+x)+G] - CLAMP(0,possible_colors[c][G],255); diff[B] = srcimg[3*((starty+y)*width+startx+x)+B] - CLAMP(0,possible_colors[c][B],255); pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*SQUARE(diff[R]) + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000*SQUARE(diff[G]) + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*SQUARE(diff[B]); // Choose best error if (pixel_error < best_pixel_error) { best_pixel_error = pixel_error; pixel_colors ^= (pixel_colors & 3); // Reset the two first bits pixel_colors |= c; thebestintheworld = c; } } block_error += best_pixel_error; } } if (block_error < best_block_error) { best_block_error = block_error; distance = d; pixel_indices = pixel_colors; } } decompressColor(R_BITS59T, G_BITS59T, B_BITS59T, colorsRGB444, colors); return best_block_error; } // Calculate the error for the block at position (startx,starty) // The parameters needed for reconstruction is calculated as well // // In the 59T bit mode, we only have pattern T. // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double calculateError59TnoSwap(uint8* srcimg, int width, int startx, int starty, uint8 (colorsRGB444)[2][3], uint8 &distance, unsigned int &pixel_indices) { double block_error = 0, best_block_error = MAXIMUM_ERROR, pixel_error, best_pixel_error; int diff[3]; unsigned int pixel_colors; uint8 colors[2][3]; uint8 possible_colors[4][3]; int thebestintheworld; // First use the colors as they are, then swap them decompressColor(R_BITS59T, G_BITS59T, B_BITS59T, colorsRGB444, colors); // Test all distances for (uint8 d = 0; d < BINPOW(TABLE_BITS_59T); ++d) { calculatePaintColors59T(d,PATTERN_T, colors, possible_colors); block_error = 0; pixel_colors = 0; // Loop block for (size_t y = 0; y < BLOCKHEIGHT; ++y) { for (size_t x = 0; x < BLOCKWIDTH; ++x) { best_pixel_error = MAXIMUM_ERROR; pixel_colors <<=2; // Make room for next value // Loop possible block colors for (uint8 c = 0; c < 4; ++c) { diff[R] = srcimg[3*((starty+y)*width+startx+x)+R] - CLAMP(0,possible_colors[c][R],255); diff[G] = srcimg[3*((starty+y)*width+startx+x)+G] - CLAMP(0,possible_colors[c][G],255); diff[B] = srcimg[3*((starty+y)*width+startx+x)+B] - CLAMP(0,possible_colors[c][B],255); pixel_error = weight[R]*SQUARE(diff[R]) + weight[G]*SQUARE(diff[G]) + weight[B]*SQUARE(diff[B]); // Choose best error if (pixel_error < best_pixel_error) { best_pixel_error = pixel_error; pixel_colors ^= (pixel_colors & 3); // Reset the two first bits pixel_colors |= c; thebestintheworld = c; } } block_error += best_pixel_error; } } if (block_error < best_block_error) { best_block_error = block_error; distance = d; pixel_indices = pixel_colors; } } decompressColor(R_BITS59T, G_BITS59T, B_BITS59T, colorsRGB444, colors); return best_block_error; } // Put the compress params into the compression block // // //|63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 40 39|38 37 36 35|34 33 32| //|----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|--dist--| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void packBlock59T(uint8 (colors)[2][3], uint8 d, unsigned int pixel_indices, unsigned int &compressed1, unsigned int &compressed2) { compressed1 = 0; PUTBITSHIGH( compressed1, colors[0][R], 4, 58); PUTBITSHIGH( compressed1, colors[0][G], 4, 54); PUTBITSHIGH( compressed1, colors[0][B], 4, 50); PUTBITSHIGH( compressed1, colors[1][R], 4, 46); PUTBITSHIGH( compressed1, colors[1][G], 4, 42); PUTBITSHIGH( compressed1, colors[1][B], 4, 38); PUTBITSHIGH( compressed1, d, TABLE_BITS_59T, 34); pixel_indices=indexConversion(pixel_indices); compressed2 = 0; PUTBITS( compressed2, pixel_indices, 32, 31); } // Copy colors from source to dest // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void copyColors(uint8 (source)[2][3], uint8 (dest)[2][3]) { int x,y; for (x=0; x<2; x++) for (y=0; y<3; y++) dest[x][y] = source[x][y]; } // The below code should compress the block to 59 bits. // //|63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 40 39|38 37 36 35|34 33 32| //|----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|--dist--| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int compressBlockTHUMB59TFastestOnlyColorPerceptual1000(uint8 *img,int width,int height,int startx,int starty, int (best_colorsRGB444_packed)[2]) { unsigned int best_error = MAXERR1000; unsigned int best_pixel_indices; uint8 best_distance; unsigned int error_no_i; uint8 colorsRGB444_no_i[2][3]; unsigned int pixel_indices_no_i; uint8 distance_no_i; uint8 colors[2][3]; // Calculate average color using the LBG-algorithm computeColorLBGHalfIntensityFast(img,width,startx,starty, colors); compressColor(R_BITS59T, G_BITS59T, B_BITS59T, colors, colorsRGB444_no_i); // Determine the parameters for the lowest error error_no_i = calculateError59Tperceptual1000(img, width, startx, starty, colorsRGB444_no_i, distance_no_i, pixel_indices_no_i); best_error = error_no_i; best_distance = distance_no_i; best_pixel_indices = pixel_indices_no_i; best_colorsRGB444_packed[0] = (colorsRGB444_no_i[0][0] << 8) + (colorsRGB444_no_i[0][1] << 4) + (colorsRGB444_no_i[0][2] << 0); best_colorsRGB444_packed[1] = (colorsRGB444_no_i[1][0] << 8) + (colorsRGB444_no_i[1][1] << 4) + (colorsRGB444_no_i[1][2] << 0); return best_error; } // The below code should compress the block to 59 bits. // This is supposed to match the first of the three modes in TWOTIMER. // //|63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 40 39|38 37 36 35|34 33 32| //|----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|--dist--| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double compressBlockTHUMB59TFastestOnlyColor(uint8 *img,int width,int height,int startx,int starty, int (best_colorsRGB444_packed)[2]) { double best_error = MAXIMUM_ERROR; unsigned int best_pixel_indices; uint8 best_distance; double error_no_i; uint8 colorsRGB444_no_i[2][3]; unsigned int pixel_indices_no_i; uint8 distance_no_i; uint8 colors[2][3]; // Calculate average color using the LBG-algorithm computeColorLBGHalfIntensityFast(img,width,startx,starty, colors); compressColor(R_BITS59T, G_BITS59T, B_BITS59T, colors, colorsRGB444_no_i); // Determine the parameters for the lowest error error_no_i = calculateError59T(img, width, startx, starty, colorsRGB444_no_i, distance_no_i, pixel_indices_no_i); best_error = error_no_i; best_distance = distance_no_i; best_pixel_indices = pixel_indices_no_i; best_colorsRGB444_packed[0] = (colorsRGB444_no_i[0][0] << 8) + (colorsRGB444_no_i[0][1] << 4) + (colorsRGB444_no_i[0][2] << 0); best_colorsRGB444_packed[1] = (colorsRGB444_no_i[1][0] << 8) + (colorsRGB444_no_i[1][1] << 4) + (colorsRGB444_no_i[1][2] << 0); return best_error; } // The below code should compress the block to 59 bits. // This is supposed to match the first of the three modes in TWOTIMER. // //|63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 40 39|38 37 36 35|34 33 32| //|----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|--dist--| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double compressBlockTHUMB59TFastestPerceptual1000(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { double best_error = MAXIMUM_ERROR; uint8 best_colorsRGB444[2][3]; unsigned int best_pixel_indices; uint8 best_distance; double error_no_i; uint8 colorsRGB444_no_i[2][3]; unsigned int pixel_indices_no_i; uint8 distance_no_i; uint8 colors[2][3]; // Calculate average color using the LBG-algorithm computeColorLBGHalfIntensityFast(img,width,startx,starty, colors); compressColor(R_BITS59T, G_BITS59T, B_BITS59T, colors, colorsRGB444_no_i); // Determine the parameters for the lowest error error_no_i = calculateError59Tperceptual1000(img, width, startx, starty, colorsRGB444_no_i, distance_no_i, pixel_indices_no_i); best_error = error_no_i; best_distance = distance_no_i; best_pixel_indices = pixel_indices_no_i; copyColors(colorsRGB444_no_i, best_colorsRGB444); // Put the compress params into the compression block packBlock59T(best_colorsRGB444, best_distance, best_pixel_indices, compressed1, compressed2); return best_error; } // The below code should compress the block to 59 bits. // This is supposed to match the first of the three modes in TWOTIMER. // //|63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 40 39|38 37 36 35|34 33 32| //|----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|--dist--| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double compressBlockTHUMB59TFastest(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { double best_error = MAXIMUM_ERROR; uint8 best_colorsRGB444[2][3]; unsigned int best_pixel_indices; uint8 best_distance; double error_no_i; uint8 colorsRGB444_no_i[2][3]; unsigned int pixel_indices_no_i; uint8 distance_no_i; uint8 colors[2][3]; // Calculate average color using the LBG-algorithm computeColorLBGHalfIntensityFast(img,width,startx,starty, colors); compressColor(R_BITS59T, G_BITS59T, B_BITS59T, colors, colorsRGB444_no_i); // Determine the parameters for the lowest error error_no_i = calculateError59T(img, width, startx, starty, colorsRGB444_no_i, distance_no_i, pixel_indices_no_i); best_error = error_no_i; best_distance = distance_no_i; best_pixel_indices = pixel_indices_no_i; copyColors(colorsRGB444_no_i, best_colorsRGB444); // Put the compress params into the compression block packBlock59T(best_colorsRGB444, best_distance, best_pixel_indices, compressed1, compressed2); return best_error; } // The below code should compress the block to 59 bits. // This is supposed to match the first of the three modes in TWOTIMER. // //|63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 40 39|38 37 36 35|34 33 32| //|----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|--dist--| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double compressBlockTHUMB59TFast(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { double best_error = MAXIMUM_ERROR; uint8 best_colorsRGB444[2][3]; unsigned int best_pixel_indices; uint8 best_distance; double error_no_i; uint8 colorsRGB444_no_i[2][3]; unsigned int pixel_indices_no_i; uint8 distance_no_i; double error_half_i; uint8 colorsRGB444_half_i[2][3]; unsigned int pixel_indices_half_i; uint8 distance_half_i; double error; uint8 colorsRGB444[2][3]; unsigned int pixel_indices; uint8 distance; uint8 colors[2][3]; // Calculate average color using the LBG-algorithm computeColorLBGNotIntensityFast(img,width,startx,starty, colors); compressColor(R_BITS59T, G_BITS59T, B_BITS59T, colors, colorsRGB444_no_i); // Determine the parameters for the lowest error error_no_i = calculateError59T(img, width, startx, starty, colorsRGB444_no_i, distance_no_i, pixel_indices_no_i); // Calculate average color using the LBG-algorithm computeColorLBGHalfIntensityFast(img,width,startx,starty, colors); compressColor(R_BITS59T, G_BITS59T, B_BITS59T, colors, colorsRGB444_half_i); // Determine the parameters for the lowest error error_half_i = calculateError59T(img, width, startx, starty, colorsRGB444_half_i, distance_half_i, pixel_indices_half_i); // Calculate average color using the LBG-algorithm computeColorLBGfast(img,width,startx,starty, colors); compressColor(R_BITS59T, G_BITS59T, B_BITS59T, colors, colorsRGB444); // Determine the parameters for the lowest error error = calculateError59T(img, width, startx, starty, colorsRGB444, distance, pixel_indices); best_error = error_no_i; best_distance = distance_no_i; best_pixel_indices = pixel_indices_no_i; copyColors(colorsRGB444_no_i, best_colorsRGB444); if(error_half_i < best_error) { best_error = error_half_i; best_distance = distance_half_i; best_pixel_indices = pixel_indices_half_i; copyColors (colorsRGB444_half_i, best_colorsRGB444); } if(error < best_error) { best_error = error; best_distance = distance; best_pixel_indices = pixel_indices; copyColors (colorsRGB444, best_colorsRGB444); } // Put the compress params into the compression block packBlock59T(best_colorsRGB444, best_distance, best_pixel_indices, compressed1, compressed2); return best_error; } // Calculate the error for the block at position (startx,starty) // The parameters needed for reconstruction is calculated as well // // In the 58H bit mode, we only have pattern H. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateErrorAndCompress58Hperceptual1000(uint8* srcimg, int width, int startx, int starty, uint8 (colorsRGB444)[2][3], uint8 &distance, unsigned int &pixel_indices) { unsigned int block_error = 0, best_block_error = MAXERR1000, pixel_error, best_pixel_error; int diff[3]; unsigned int pixel_colors; uint8 possible_colors[4][3]; uint8 colors[2][3]; decompressColor(R_BITS58H, G_BITS58H, B_BITS58H, colorsRGB444, colors); // Test all distances for (uint8 d = 0; d < BINPOW(TABLE_BITS_58H); ++d) { calculatePaintColors58H(d, PATTERN_H, colors, possible_colors); block_error = 0; pixel_colors = 0; // Loop block for (size_t y = 0; y < BLOCKHEIGHT; ++y) { for (size_t x = 0; x < BLOCKWIDTH; ++x) { best_pixel_error = MAXERR1000; pixel_colors <<=2; // Make room for next value // Loop possible block colors for (uint8 c = 0; c < 4; ++c) { diff[R] = srcimg[3*((starty+y)*width+startx+x)+R] - CLAMP(0,possible_colors[c][R],255); diff[G] = srcimg[3*((starty+y)*width+startx+x)+G] - CLAMP(0,possible_colors[c][G],255); diff[B] = srcimg[3*((starty+y)*width+startx+x)+B] - CLAMP(0,possible_colors[c][B],255); pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*SQUARE(diff[R]) + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000*SQUARE(diff[G]) + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*SQUARE(diff[B]); // Choose best error if (pixel_error < best_pixel_error) { best_pixel_error = pixel_error; pixel_colors ^= (pixel_colors & 3); // Reset the two first bits pixel_colors |= c; } } block_error += best_pixel_error; } } if (block_error < best_block_error) { best_block_error = block_error; distance = d; pixel_indices = pixel_colors; } } return best_block_error; } // The H-mode but with punchthrough alpha // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double calculateErrorAndCompress58HAlpha(uint8* srcimg, uint8* alphaimg,int width, int startx, int starty, uint8 (colorsRGB444)[2][3], uint8 &distance, unsigned int &pixel_indices) { double block_error = 0, best_block_error = MAXIMUM_ERROR, pixel_error, best_pixel_error; int diff[3]; unsigned int pixel_colors; uint8 possible_colors[4][3]; uint8 colors[2][3]; int alphaindex; int colorsRGB444_packed[2]; colorsRGB444_packed[0] = (colorsRGB444[0][R] << 8) + (colorsRGB444[0][G] << 4) + colorsRGB444[0][B]; colorsRGB444_packed[1] = (colorsRGB444[1][R] << 8) + (colorsRGB444[1][G] << 4) + colorsRGB444[1][B]; decompressColor(R_BITS58H, G_BITS58H, B_BITS58H, colorsRGB444, colors); // Test all distances for (uint8 d = 0; d < BINPOW(TABLE_BITS_58H); ++d) { alphaindex=2; if( (colorsRGB444_packed[0] >= colorsRGB444_packed[1]) ^ ((d & 1)==1) ) { //we're going to have to swap the colors to be able to choose this distance.. that means //that the indices will be swapped as well, so C1 will be the one with alpha instead of C3.. alphaindex=0; } calculatePaintColors58H(d, PATTERN_H, colors, possible_colors); block_error = 0; pixel_colors = 0; // Loop block for (size_t y = 0; y < BLOCKHEIGHT; ++y) { for (size_t x = 0; x < BLOCKWIDTH; ++x) { int alpha=0; if(alphaimg[((starty+y)*width+startx+x)]>0) alpha=1; if(alphaimg[((starty+y)*width+startx+x)]>0&&alphaimg[((starty+y)*width+startx+x)]<255) printf("INVALID ALPHA DATA!!\n"); best_pixel_error = MAXIMUM_ERROR; pixel_colors <<=2; // Make room for next value // Loop possible block colors for (uint8 c = 0; c < 4; ++c) { if(c==alphaindex&&alpha) { pixel_error=0; } else if(c==alphaindex||alpha) { pixel_error=MAXIMUM_ERROR; } else { diff[R] = srcimg[3*((starty+y)*width+startx+x)+R] - CLAMP(0,possible_colors[c][R],255); diff[G] = srcimg[3*((starty+y)*width+startx+x)+G] - CLAMP(0,possible_colors[c][G],255); diff[B] = srcimg[3*((starty+y)*width+startx+x)+B] - CLAMP(0,possible_colors[c][B],255); pixel_error = weight[R]*SQUARE(diff[R]) + weight[G]*SQUARE(diff[G]) + weight[B]*SQUARE(diff[B]); } // Choose best error if (pixel_error < best_pixel_error) { best_pixel_error = pixel_error; pixel_colors ^= (pixel_colors & 3); // Reset the two first bits pixel_colors |= c; } } block_error += best_pixel_error; } } if (block_error < best_block_error) { best_block_error = block_error; distance = d; pixel_indices = pixel_colors; } } return best_block_error; } // Calculate the error for the block at position (startx,starty) // The parameters needed for reconstruction is calculated as well // // In the 58H bit mode, we only have pattern H. // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double calculateErrorAndCompress58H(uint8* srcimg, int width, int startx, int starty, uint8 (colorsRGB444)[2][3], uint8 &distance, unsigned int &pixel_indices) { double block_error = 0, best_block_error = MAXIMUM_ERROR, pixel_error, best_pixel_error; int diff[3]; unsigned int pixel_colors; uint8 possible_colors[4][3]; uint8 colors[2][3]; decompressColor(R_BITS58H, G_BITS58H, B_BITS58H, colorsRGB444, colors); // Test all distances for (uint8 d = 0; d < BINPOW(TABLE_BITS_58H); ++d) { calculatePaintColors58H(d, PATTERN_H, colors, possible_colors); block_error = 0; pixel_colors = 0; // Loop block for (size_t y = 0; y < BLOCKHEIGHT; ++y) { for (size_t x = 0; x < BLOCKWIDTH; ++x) { best_pixel_error = MAXIMUM_ERROR; pixel_colors <<=2; // Make room for next value // Loop possible block colors for (uint8 c = 0; c < 4; ++c) { diff[R] = srcimg[3*((starty+y)*width+startx+x)+R] - CLAMP(0,possible_colors[c][R],255); diff[G] = srcimg[3*((starty+y)*width+startx+x)+G] - CLAMP(0,possible_colors[c][G],255); diff[B] = srcimg[3*((starty+y)*width+startx+x)+B] - CLAMP(0,possible_colors[c][B],255); pixel_error = weight[R]*SQUARE(diff[R]) + weight[G]*SQUARE(diff[G]) + weight[B]*SQUARE(diff[B]); // Choose best error if (pixel_error < best_pixel_error) { best_pixel_error = pixel_error; pixel_colors ^= (pixel_colors & 3); // Reset the two first bits pixel_colors |= c; } } block_error += best_pixel_error; } } if (block_error < best_block_error) { best_block_error = block_error; distance = d; pixel_indices = pixel_colors; } } return best_block_error; } // Makes sure that col0 < col1; // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void sortColorsRGB444(uint8 (colorsRGB444)[2][3]) { unsigned int col0, col1, tcol; // sort colors col0 = 16*16*colorsRGB444[0][R] + 16*colorsRGB444[0][G] + colorsRGB444[0][B]; col1 = 16*16*colorsRGB444[1][R] + 16*colorsRGB444[1][G] + colorsRGB444[1][B]; // After this, col0 should be smaller than col1 (col0 < col1) if( col0 > col1) { tcol = col0; col0 = col1; col1 = tcol; } else { if(col0 == col1) { // Both colors are the same. That is useless. If they are both black, // col1 can just as well be (0,0,1). Else, col0 can be col1 - 1. if(col0 == 0) col1 = col0+1; else col0 = col1-1; } } colorsRGB444[0][R] = GETBITS(col0, 4, 11); colorsRGB444[0][G] = GETBITS(col0, 4, 7); colorsRGB444[0][B] = GETBITS(col0, 4, 3); colorsRGB444[1][R] = GETBITS(col1, 4, 11); colorsRGB444[1][G] = GETBITS(col1, 4, 7); colorsRGB444[1][B] = GETBITS(col1, 4, 3); } // The below code should compress the block to 58 bits. // The bit layout is thought to be: // //|63 62 61 60 59 58|57 56 55 54|53 52 51 50|49 48 47 46|45 44 43 42|41 40 39 38|37 36 35 34|33 32| //|-------empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|d2 d1| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // // The distance d is three bits, d2 (MSB), d1 and d0 (LSB). d0 is not stored explicitly. // Instead if the 12-bit word red0,green0,blue0 < red1,green1,blue1, d0 is assumed to be 0. // Else, it is assumed to be 1. // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int compressBlockTHUMB58HFastestPerceptual1000(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { unsigned int best_error = MAXERR1000; uint8 best_colorsRGB444[2][3]; unsigned int best_pixel_indices; uint8 best_distance; unsigned int error_no_i; uint8 colorsRGB444_no_i[2][3]; unsigned int pixel_indices_no_i; uint8 distance_no_i; uint8 colors[2][3]; // Calculate average color using the LBG-algorithm but discarding the intensity in the error function computeColorLBGHalfIntensityFast(img, width, startx, starty, colors); compressColor(R_BITS58H, G_BITS58H, B_BITS58H, colors, colorsRGB444_no_i); sortColorsRGB444(colorsRGB444_no_i); error_no_i = calculateErrorAndCompress58Hperceptual1000(img, width, startx, starty, colorsRGB444_no_i, distance_no_i, pixel_indices_no_i); best_error = error_no_i; best_distance = distance_no_i; best_pixel_indices = pixel_indices_no_i; copyColors(colorsRGB444_no_i, best_colorsRGB444); // | col0 >= col1 col0 < col1 //------------------------------------------------------ // (dist & 1) = 1 | no need to swap | need to swap // |-----------------+---------------- // (dist & 1) = 0 | need to swap | no need to swap // // This can be done with an xor test. int best_colorsRGB444_packed[2]; best_colorsRGB444_packed[0] = (best_colorsRGB444[0][R] << 8) + (best_colorsRGB444[0][G] << 4) + best_colorsRGB444[0][B]; best_colorsRGB444_packed[1] = (best_colorsRGB444[1][R] << 8) + (best_colorsRGB444[1][G] << 4) + best_colorsRGB444[1][B]; if( (best_colorsRGB444_packed[0] >= best_colorsRGB444_packed[1]) ^ ((best_distance & 1)==1) ) { swapColors(best_colorsRGB444); // Reshuffle pixel indices to to exchange C1 with C3, and C2 with C4 best_pixel_indices = (0x55555555 & best_pixel_indices) | (0xaaaaaaaa & (~best_pixel_indices)); } // Put the compress params into the compression block compressed1 = 0; PUTBITSHIGH( compressed1, best_colorsRGB444[0][R], 4, 57); PUTBITSHIGH( compressed1, best_colorsRGB444[0][G], 4, 53); PUTBITSHIGH( compressed1, best_colorsRGB444[0][B], 4, 49); PUTBITSHIGH( compressed1, best_colorsRGB444[1][R], 4, 45); PUTBITSHIGH( compressed1, best_colorsRGB444[1][G], 4, 41); PUTBITSHIGH( compressed1, best_colorsRGB444[1][B], 4, 37); PUTBITSHIGH( compressed1, (best_distance >> 1), 2, 33); compressed2 = 0; best_pixel_indices=indexConversion(best_pixel_indices); PUTBITS( compressed2, best_pixel_indices, 32, 31); return best_error; } // The below code should compress the block to 58 bits. // This is supposed to match the first of the three modes in TWOTIMER. // The bit layout is thought to be: // //|63 62 61 60 59 58|57 56 55 54|53 52 51 50|49 48 47 46|45 44 43 42|41 40 39 38|37 36 35 34|33 32| //|-------empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|d2 d1| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // // The distance d is three bits, d2 (MSB), d1 and d0 (LSB). d0 is not stored explicitly. // Instead if the 12-bit word red0,green0,blue0 < red1,green1,blue1, d0 is assumed to be 0. // Else, it is assumed to be 1. // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double compressBlockTHUMB58HFastest(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { double best_error = MAXIMUM_ERROR; uint8 best_colorsRGB444[2][3]; unsigned int best_pixel_indices; uint8 best_distance; double error_no_i; uint8 colorsRGB444_no_i[2][3]; unsigned int pixel_indices_no_i; uint8 distance_no_i; uint8 colors[2][3]; // Calculate average color using the LBG-algorithm but discarding the intensity in the error function computeColorLBGHalfIntensityFast(img, width, startx, starty, colors); compressColor(R_BITS58H, G_BITS58H, B_BITS58H, colors, colorsRGB444_no_i); sortColorsRGB444(colorsRGB444_no_i); error_no_i = calculateErrorAndCompress58H(img, width, startx, starty, colorsRGB444_no_i, distance_no_i, pixel_indices_no_i); best_error = error_no_i; best_distance = distance_no_i; best_pixel_indices = pixel_indices_no_i; copyColors(colorsRGB444_no_i, best_colorsRGB444); // | col0 >= col1 col0 < col1 //------------------------------------------------------ // (dist & 1) = 1 | no need to swap | need to swap // |-----------------+---------------- // (dist & 1) = 0 | need to swap | no need to swap // // This can be done with an xor test. int best_colorsRGB444_packed[2]; best_colorsRGB444_packed[0] = (best_colorsRGB444[0][R] << 8) + (best_colorsRGB444[0][G] << 4) + best_colorsRGB444[0][B]; best_colorsRGB444_packed[1] = (best_colorsRGB444[1][R] << 8) + (best_colorsRGB444[1][G] << 4) + best_colorsRGB444[1][B]; if( (best_colorsRGB444_packed[0] >= best_colorsRGB444_packed[1]) ^ ((best_distance & 1)==1) ) { swapColors(best_colorsRGB444); // Reshuffle pixel indices to to exchange C1 with C3, and C2 with C4 best_pixel_indices = (0x55555555 & best_pixel_indices) | (0xaaaaaaaa & (~best_pixel_indices)); } // Put the compress params into the compression block compressed1 = 0; PUTBITSHIGH( compressed1, best_colorsRGB444[0][R], 4, 57); PUTBITSHIGH( compressed1, best_colorsRGB444[0][G], 4, 53); PUTBITSHIGH( compressed1, best_colorsRGB444[0][B], 4, 49); PUTBITSHIGH( compressed1, best_colorsRGB444[1][R], 4, 45); PUTBITSHIGH( compressed1, best_colorsRGB444[1][G], 4, 41); PUTBITSHIGH( compressed1, best_colorsRGB444[1][B], 4, 37); PUTBITSHIGH( compressed1, (best_distance >> 1), 2, 33); best_pixel_indices=indexConversion(best_pixel_indices); compressed2 = 0; PUTBITS( compressed2, best_pixel_indices, 32, 31); return best_error; } //same as above, but with 1-bit alpha // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double compressBlockTHUMB58HAlpha(uint8 *img, uint8* alphaimg, int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { double best_error = MAXIMUM_ERROR; uint8 best_colorsRGB444[2][3]; unsigned int best_pixel_indices; uint8 best_distance; double error_no_i; uint8 colorsRGB444_no_i[2][3]; unsigned int pixel_indices_no_i; uint8 distance_no_i; uint8 colors[2][3]; // Calculate average color using the LBG-algorithm but discarding the intensity in the error function computeColorLBGHalfIntensityFast(img, width, startx, starty, colors); compressColor(R_BITS58H, G_BITS58H, B_BITS58H, colors, colorsRGB444_no_i); sortColorsRGB444(colorsRGB444_no_i); error_no_i = calculateErrorAndCompress58HAlpha(img, alphaimg,width, startx, starty, colorsRGB444_no_i, distance_no_i, pixel_indices_no_i); best_error = error_no_i; best_distance = distance_no_i; best_pixel_indices = pixel_indices_no_i; copyColors(colorsRGB444_no_i, best_colorsRGB444); // | col0 >= col1 col0 < col1 //------------------------------------------------------ // (dist & 1) = 1 | no need to swap | need to swap // |-----------------+---------------- // (dist & 1) = 0 | need to swap | no need to swap // // This can be done with an xor test. int best_colorsRGB444_packed[2]; best_colorsRGB444_packed[0] = (best_colorsRGB444[0][R] << 8) + (best_colorsRGB444[0][G] << 4) + best_colorsRGB444[0][B]; best_colorsRGB444_packed[1] = (best_colorsRGB444[1][R] << 8) + (best_colorsRGB444[1][G] << 4) + best_colorsRGB444[1][B]; if( (best_colorsRGB444_packed[0] >= best_colorsRGB444_packed[1]) ^ ((best_distance & 1)==1) ) { swapColors(best_colorsRGB444); // Reshuffle pixel indices to to exchange C1 with C3, and C2 with C4 best_pixel_indices = (0x55555555 & best_pixel_indices) | (0xaaaaaaaa & (~best_pixel_indices)); } // Put the compress params into the compression block compressed1 = 0; PUTBITSHIGH( compressed1, best_colorsRGB444[0][R], 4, 57); PUTBITSHIGH( compressed1, best_colorsRGB444[0][G], 4, 53); PUTBITSHIGH( compressed1, best_colorsRGB444[0][B], 4, 49); PUTBITSHIGH( compressed1, best_colorsRGB444[1][R], 4, 45); PUTBITSHIGH( compressed1, best_colorsRGB444[1][G], 4, 41); PUTBITSHIGH( compressed1, best_colorsRGB444[1][B], 4, 37); PUTBITSHIGH( compressed1, (best_distance >> 1), 2, 33); best_pixel_indices=indexConversion(best_pixel_indices); compressed2 = 0; PUTBITS( compressed2, best_pixel_indices, 32, 31); return best_error; } // The below code should compress the block to 58 bits. // This is supposed to match the first of the three modes in TWOTIMER. // The bit layout is thought to be: // //|63 62 61 60 59 58|57 56 55 54|53 52 51 50|49 48 47 46|45 44 43 42|41 40 39 38|37 36 35 34|33 32| //|-------empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|d2 d1| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // // The distance d is three bits, d2 (MSB), d1 and d0 (LSB). d0 is not stored explicitly. // Instead if the 12-bit word red0,green0,blue0 < red1,green1,blue1, d0 is assumed to be 0. // Else, it is assumed to be 1. // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double compressBlockTHUMB58HFast(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { double best_error = MAXIMUM_ERROR; uint8 best_colorsRGB444[2][3]; unsigned int best_pixel_indices; uint8 best_distance; double error_no_i; uint8 colorsRGB444_no_i[2][3]; unsigned int pixel_indices_no_i; uint8 distance_no_i; double error_half_i; uint8 colorsRGB444_half_i[2][3]; unsigned int pixel_indices_half_i; uint8 distance_half_i; double error; uint8 colorsRGB444[2][3]; unsigned int pixel_indices; uint8 distance; uint8 colors[2][3]; // Calculate average color using the LBG-algorithm but discarding the intensity in the error function computeColorLBGNotIntensity(img, width, startx, starty, colors); compressColor(R_BITS58H, G_BITS58H, B_BITS58H, colors, colorsRGB444_no_i); sortColorsRGB444(colorsRGB444_no_i); error_no_i = calculateErrorAndCompress58H(img, width, startx, starty, colorsRGB444_no_i, distance_no_i, pixel_indices_no_i); // Calculate average color using the LBG-algorithm but halfing the influence of the intensity in the error function computeColorLBGNotIntensity(img, width, startx, starty, colors); compressColor(R_BITS58H, G_BITS58H, B_BITS58H, colors, colorsRGB444_half_i); sortColorsRGB444(colorsRGB444_half_i); error_half_i = calculateErrorAndCompress58H(img, width, startx, starty, colorsRGB444_half_i, distance_half_i, pixel_indices_half_i); // Calculate average color using the LBG-algorithm computeColorLBG(img, width, startx, starty, colors); compressColor(R_BITS58H, G_BITS58H, B_BITS58H, colors, colorsRGB444); sortColorsRGB444(colorsRGB444); error = calculateErrorAndCompress58H(img, width, startx, starty, colorsRGB444, distance, pixel_indices); best_error = error_no_i; best_distance = distance_no_i; best_pixel_indices = pixel_indices_no_i; copyColors(colorsRGB444_no_i, best_colorsRGB444); if(error_half_i < best_error) { best_error = error_half_i; best_distance = distance_half_i; best_pixel_indices = pixel_indices_half_i; copyColors(colorsRGB444_half_i, best_colorsRGB444); } if(error < best_error) { best_error = error; best_distance = distance; best_pixel_indices = pixel_indices; copyColors(colorsRGB444, best_colorsRGB444); } // | col0 >= col1 col0 < col1 //------------------------------------------------------ // (dist & 1) = 1 | no need to swap | need to swap // |-----------------+---------------- // (dist & 1) = 0 | need to swap | no need to swap // // This can be done with an xor test. int best_colorsRGB444_packed[2]; best_colorsRGB444_packed[0] = (best_colorsRGB444[0][R] << 8) + (best_colorsRGB444[0][G] << 4) + best_colorsRGB444[0][B]; best_colorsRGB444_packed[1] = (best_colorsRGB444[1][R] << 8) + (best_colorsRGB444[1][G] << 4) + best_colorsRGB444[1][B]; if( (best_colorsRGB444_packed[0] >= best_colorsRGB444_packed[1]) ^ ((best_distance & 1)==1) ) { swapColors(best_colorsRGB444); // Reshuffle pixel indices to to exchange C1 with C3, and C2 with C4 best_pixel_indices = (0x55555555 & best_pixel_indices) | (0xaaaaaaaa & (~best_pixel_indices)); } // Put the compress params into the compression block compressed1 = 0; PUTBITSHIGH( compressed1, best_colorsRGB444[0][R], 4, 57); PUTBITSHIGH( compressed1, best_colorsRGB444[0][G], 4, 53); PUTBITSHIGH( compressed1, best_colorsRGB444[0][B], 4, 49); PUTBITSHIGH( compressed1, best_colorsRGB444[1][R], 4, 45); PUTBITSHIGH( compressed1, best_colorsRGB444[1][G], 4, 41); PUTBITSHIGH( compressed1, best_colorsRGB444[1][B], 4, 37); PUTBITSHIGH( compressed1, (best_distance >> 1), 2, 33); best_pixel_indices=indexConversion(best_pixel_indices); compressed2 = 0; PUTBITS( compressed2, best_pixel_indices, 32, 31); return best_error; } // Compress block testing both individual and differential mode. // Perceptual error metric. // Combined quantization for colors. // Both flipped and unflipped tested. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressBlockDiffFlipCombinedPerceptual(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { unsigned int compressed1_norm, compressed2_norm; unsigned int compressed1_flip, compressed2_flip; uint8 avg_color_quant1[3], avg_color_quant2[3]; float avg_color_float1[3],avg_color_float2[3]; int enc_color1[3], enc_color2[3], diff[3]; int min_error=255*255*8*3; unsigned int best_table_indices1=0, best_table_indices2=0; unsigned int best_table1=0, best_table2=0; int diffbit; int norm_err=0; int flip_err=0; // First try normal blocks 2x4: computeAverageColor2x4noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor2x4noQuantFloat(img,width,height,startx+2,starty,avg_color_float2); // First test if avg_color1 is similar enough to avg_color2 so that // we can use differential coding of colors. float eps; uint8 dummy[3]; quantize555ColorCombinedPerceptual(avg_color_float1, enc_color1, dummy); quantize555ColorCombinedPerceptual(avg_color_float2, enc_color2, dummy); diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; if( (diff[0] >= -4) && (diff[0] <= 3) && (diff[1] >= -4) && (diff[1] <= 3) && (diff[2] >= -4) && (diff[2] <= 3) ) { diffbit = 1; // The difference to be coded: diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; avg_color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); avg_color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); avg_color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); avg_color_quant2[0] = enc_color2[0] << 3 | (enc_color2[0] >> 2); avg_color_quant2[1] = enc_color2[1] << 3 | (enc_color2[1] >> 2); avg_color_quant2[2] = enc_color2[2] << 3 | (enc_color2[2] >> 2); // Pack bits into the first word. // ETC1_RGB8_OES: // // a) bit layout in bits 63 through 32 if diffbit = 0 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // b) bit layout in bits 63 through 32 if diffbit = 1 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |diff|flip| // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // c) bit layout in bits 31 through 0 (in both cases) // // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 // -------------------------------------------------------------------------------------------------- // | most significant pixel index bits | least significant pixel index bits | // | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | // -------------------------------------------------------------------------------------------------- compressed1_norm = 0; PUTBITSHIGH( compressed1_norm, diffbit, 1, 33); PUTBITSHIGH( compressed1_norm, enc_color1[0], 5, 63); PUTBITSHIGH( compressed1_norm, enc_color1[1], 5, 55); PUTBITSHIGH( compressed1_norm, enc_color1[2], 5, 47); PUTBITSHIGH( compressed1_norm, diff[0], 3, 58); PUTBITSHIGH( compressed1_norm, diff[1], 3, 50); PUTBITSHIGH( compressed1_norm, diff[2], 3, 42); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; norm_err = 0; // left part of block norm_err = tryalltables_3bittable2x4percep(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // right part of block norm_err += tryalltables_3bittable2x4percep(img,width,height,startx+2,starty,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_norm, best_table1, 3, 39); PUTBITSHIGH( compressed1_norm, best_table2, 3, 36); PUTBITSHIGH( compressed1_norm, 0, 1, 32); compressed2_norm = 0; PUTBITS( compressed2_norm, (best_pixel_indices1_MSB ), 8, 23); PUTBITS( compressed2_norm, (best_pixel_indices2_MSB ), 8, 31); PUTBITS( compressed2_norm, (best_pixel_indices1_LSB ), 8, 7); PUTBITS( compressed2_norm, (best_pixel_indices2_LSB ), 8, 15); } else { diffbit = 0; // The difference is bigger than what fits in 555 plus delta-333, so we will have // to deal with 444 444. eps = (float) 0.0001; quantize444ColorCombinedPerceptual(avg_color_float1, enc_color1, dummy); quantize444ColorCombinedPerceptual(avg_color_float2, enc_color2, dummy); avg_color_quant1[0] = enc_color1[0] << 4 | enc_color1[0]; avg_color_quant1[1] = enc_color1[1] << 4 | enc_color1[1]; avg_color_quant1[2] = enc_color1[2] << 4 | enc_color1[2]; avg_color_quant2[0] = enc_color2[0] << 4 | enc_color2[0]; avg_color_quant2[1] = enc_color2[1] << 4 | enc_color2[1]; avg_color_quant2[2] = enc_color2[2] << 4 | enc_color2[2]; // Pack bits into the first word. // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- compressed1_norm = 0; PUTBITSHIGH( compressed1_norm, diffbit, 1, 33); PUTBITSHIGH( compressed1_norm, enc_color1[0], 4, 63); PUTBITSHIGH( compressed1_norm, enc_color1[1], 4, 55); PUTBITSHIGH( compressed1_norm, enc_color1[2], 4, 47); PUTBITSHIGH( compressed1_norm, enc_color2[0], 4, 59); PUTBITSHIGH( compressed1_norm, enc_color2[1], 4, 51); PUTBITSHIGH( compressed1_norm, enc_color2[2], 4, 43); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; // left part of block norm_err = tryalltables_3bittable2x4percep(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // right part of block norm_err += tryalltables_3bittable2x4percep(img,width,height,startx+2,starty,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_norm, best_table1, 3, 39); PUTBITSHIGH( compressed1_norm, best_table2, 3, 36); PUTBITSHIGH( compressed1_norm, 0, 1, 32); compressed2_norm = 0; PUTBITS( compressed2_norm, (best_pixel_indices1_MSB ), 8, 23); PUTBITS( compressed2_norm, (best_pixel_indices2_MSB ), 8, 31); PUTBITS( compressed2_norm, (best_pixel_indices1_LSB ), 8, 7); PUTBITS( compressed2_norm, (best_pixel_indices2_LSB ), 8, 15); } // Now try flipped blocks 4x2: computeAverageColor4x2noQuantFloat(img,width,height,startx,starty,avg_color_float1); computeAverageColor4x2noQuantFloat(img,width,height,startx,starty+2,avg_color_float2); // First test if avg_color1 is similar enough to avg_color2 so that // we can use differential coding of colors. quantize555ColorCombinedPerceptual(avg_color_float1, enc_color1, dummy); quantize555ColorCombinedPerceptual(avg_color_float2, enc_color2, dummy); diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; if( (diff[0] >= -4) && (diff[0] <= 3) && (diff[1] >= -4) && (diff[1] <= 3) && (diff[2] >= -4) && (diff[2] <= 3) ) { diffbit = 1; // The difference to be coded: diff[0] = enc_color2[0]-enc_color1[0]; diff[1] = enc_color2[1]-enc_color1[1]; diff[2] = enc_color2[2]-enc_color1[2]; avg_color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); avg_color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); avg_color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); avg_color_quant2[0] = enc_color2[0] << 3 | (enc_color2[0] >> 2); avg_color_quant2[1] = enc_color2[1] << 3 | (enc_color2[1] >> 2); avg_color_quant2[2] = enc_color2[2] << 3 | (enc_color2[2] >> 2); // Pack bits into the first word. compressed1_flip = 0; PUTBITSHIGH( compressed1_flip, diffbit, 1, 33); PUTBITSHIGH( compressed1_flip, enc_color1[0], 5, 63); PUTBITSHIGH( compressed1_flip, enc_color1[1], 5, 55); PUTBITSHIGH( compressed1_flip, enc_color1[2], 5, 47); PUTBITSHIGH( compressed1_flip, diff[0], 3, 58); PUTBITSHIGH( compressed1_flip, diff[1], 3, 50); PUTBITSHIGH( compressed1_flip, diff[2], 3, 42); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; // upper part of block flip_err = tryalltables_3bittable4x2percep(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // lower part of block flip_err += tryalltables_3bittable4x2percep(img,width,height,startx,starty+2,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_flip, best_table1, 3, 39); PUTBITSHIGH( compressed1_flip, best_table2, 3, 36); PUTBITSHIGH( compressed1_flip, 1, 1, 32); best_pixel_indices1_MSB |= (best_pixel_indices2_MSB << 2); best_pixel_indices1_LSB |= (best_pixel_indices2_LSB << 2); compressed2_flip = ((best_pixel_indices1_MSB & 0xffff) << 16) | (best_pixel_indices1_LSB & 0xffff); } else { diffbit = 0; // The difference is bigger than what fits in 555 plus delta-333, so we will have // to deal with 444 444. eps = (float) 0.0001; quantize444ColorCombinedPerceptual(avg_color_float1, enc_color1, dummy); quantize444ColorCombinedPerceptual(avg_color_float2, enc_color2, dummy); avg_color_quant1[0] = enc_color1[0] << 4 | enc_color1[0]; avg_color_quant1[1] = enc_color1[1] << 4 | enc_color1[1]; avg_color_quant1[2] = enc_color1[2] << 4 | enc_color1[2]; avg_color_quant2[0] = enc_color2[0] << 4 | enc_color2[0]; avg_color_quant2[1] = enc_color2[1] << 4 | enc_color2[1]; avg_color_quant2[2] = enc_color2[2] << 4 | enc_color2[2]; // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // Pack bits into the first word. compressed1_flip = 0; PUTBITSHIGH( compressed1_flip, diffbit, 1, 33); PUTBITSHIGH( compressed1_flip, enc_color1[0], 4, 63); PUTBITSHIGH( compressed1_flip, enc_color1[1], 4, 55); PUTBITSHIGH( compressed1_flip, enc_color1[2], 4, 47); PUTBITSHIGH( compressed1_flip, enc_color2[0], 4, 59); PUTBITSHIGH( compressed1_flip, enc_color2[1], 4, 51); PUTBITSHIGH( compressed1_flip, enc_color2[2], 4, 43); unsigned int best_pixel_indices1_MSB; unsigned int best_pixel_indices1_LSB; unsigned int best_pixel_indices2_MSB; unsigned int best_pixel_indices2_LSB; // upper part of block flip_err = tryalltables_3bittable4x2percep(img,width,height,startx,starty,avg_color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); // lower part of block flip_err += tryalltables_3bittable4x2percep(img,width,height,startx,starty+2,avg_color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); PUTBITSHIGH( compressed1_flip, best_table1, 3, 39); PUTBITSHIGH( compressed1_flip, best_table2, 3, 36); PUTBITSHIGH( compressed1_flip, 1, 1, 32); best_pixel_indices1_MSB |= (best_pixel_indices2_MSB << 2); best_pixel_indices1_LSB |= (best_pixel_indices2_LSB << 2); compressed2_flip = ((best_pixel_indices1_MSB & 0xffff) << 16) | (best_pixel_indices1_LSB & 0xffff); } // Now lets see which is the best table to use. Only 8 tables are possible. if(norm_err <= flip_err) { compressed1 = compressed1_norm | 0; compressed2 = compressed2_norm; } else { compressed1 = compressed1_flip | 1; compressed2 = compressed2_flip; } } // Calculate the error of a block // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double calcBlockErrorRGB(uint8 *img, uint8 *imgdec, int width, int height, int startx, int starty) { int xx,yy; double err; err = 0; for(xx = startx; xx< startx+4; xx++) { for(yy = starty; yy3) diff[c]=3; enc_color2[c]=enc_color1[c]+diff[c]; } avg_color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); avg_color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); avg_color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); avg_color_quant2[0] = enc_color2[0] << 3 | (enc_color2[0] >> 2); avg_color_quant2[1] = enc_color2[1] << 3 | (enc_color2[1] >> 2); avg_color_quant2[2] = enc_color2[2] << 3 | (enc_color2[2] >> 2); // Pack bits into the first word. // see regular compressblockdiffflipfast for details compressed1_temp = 0; PUTBITSHIGH( compressed1_temp, !isTransparent, 1, 33); PUTBITSHIGH( compressed1_temp, enc_color1[0], 5, 63); PUTBITSHIGH( compressed1_temp, enc_color1[1], 5, 55); PUTBITSHIGH( compressed1_temp, enc_color1[2], 5, 47); PUTBITSHIGH( compressed1_temp, diff[0], 3, 58); PUTBITSHIGH( compressed1_temp, diff[1], 3, 50); PUTBITSHIGH( compressed1_temp, diff[2], 3, 42); temp_err = 0; int besterror[2]; besterror[0]=255*255*3*16; besterror[1]=255*255*3*16; int besttable[2]; int best_indices_LSB[16]; int best_indices_MSB[16]; //for each table, we're going to compute the indices required to get minimum error in each half. //then we'll check if this was the best table for either half, and set besterror/besttable accordingly. for(int table=0; table<8; table++) { int taberror[2];//count will be sort of an index of each pixel within a half, determining where the index will be placed in the bitstream. int pixel_indices_LSB[16],pixel_indices_MSB[16]; for(int i=0; i<2; i++) { taberror[i]=0; } for(int x=0; x<4; x++) { for(int y=0; y<4; y++) { int index = x+startx+(y+starty)*width; uint8 basecol[3]; bool transparentPixel=alphaimg[index]<128; //determine which half of the block this pixel is in, based on the flipbit. int half=0; if( (flipbit==0&&x<2) || (flipbit&&y<2) ) { basecol[0]=avg_color_quant1[0]; basecol[1]=avg_color_quant1[1]; basecol[2]=avg_color_quant1[2]; } else { half=1; basecol[0]=avg_color_quant2[0]; basecol[1]=avg_color_quant2[1]; basecol[2]=avg_color_quant2[2]; } int besterri=255*255*3*2; int besti=0; int erri; for(int i=0; i<4; i++) { if(i==1&&isTransparent) continue; erri=0; for(int c=0; c<3; c++) { int col=CLAMP(0,((int)basecol[c])+compressParams[table*2][i],255); if(i==2&&isTransparent) { col=(int)basecol[c]; } int errcol=col-((int)(img[index*3+c])); erri=erri+(errcol*errcol); } if(erri> 1); pixel_indices_LSB[x*4+y]=(pixel_index & 1); } } for(int half=0; half<2; half++) { if(taberror[half] 128) // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double calcBlockErrorRGBA(uint8 *img, uint8 *imgdec, uint8* alpha, int width, int height, int startx, int starty) { int xx,yy; double err; err = 0; for(xx = startx; xx< startx+4; xx++) { for(yy = starty; yy128) { err += SQUARE(1.0*RED(img,width,xx,yy) - 1.0*RED(imgdec, width, xx,yy)); err += SQUARE(1.0*GREEN(img,width,xx,yy)- 1.0*GREEN(imgdec, width, xx,yy)); err += SQUARE(1.0*BLUE(img,width,xx,yy) - 1.0*BLUE(imgdec, width, xx,yy)); } } } return err; } //calculates the error for a block using the given colors, and the paremeters required to obtain the error. This version uses 1-bit punch-through alpha. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double calculateError59TAlpha(uint8* srcimg, uint8* alpha,int width, int startx, int starty, uint8 (colorsRGB444)[2][3], uint8 &distance, unsigned int &pixel_indices) { double block_error = 0, best_block_error = MAXIMUM_ERROR, pixel_error, best_pixel_error; int diff[3]; uint8 best_sw; unsigned int pixel_colors; uint8 colors[2][3]; uint8 possible_colors[4][3]; // First use the colors as they are, then swap them for (uint8 sw = 0; sw <2; ++sw) { if (sw == 1) { swapColors(colorsRGB444); } decompressColor(R_BITS59T, G_BITS59T, B_BITS59T, colorsRGB444, colors); // Test all distances for (uint8 d = 0; d < BINPOW(TABLE_BITS_59T); ++d) { calculatePaintColors59T(d,PATTERN_T, colors, possible_colors); block_error = 0; pixel_colors = 0; // Loop block for (size_t y = 0; y < BLOCKHEIGHT; ++y) { for (size_t x = 0; x < BLOCKWIDTH; ++x) { best_pixel_error = MAXIMUM_ERROR; pixel_colors <<=2; // Make room for next value // Loop possible block colors if(alpha[x+startx+(y+starty)*width]==0) { best_pixel_error=0; pixel_colors ^= (pixel_colors & 3); // Reset the two first bits pixel_colors |= 2; //insert the index for this pixel, two meaning transparent. } else { for (uint8 c = 0; c < 4; ++c) { if(c==2) continue; //don't use this, because we don't have alpha here and index 2 means transparent. diff[R] = srcimg[3*((starty+y)*width+startx+x)+R] - CLAMP(0,possible_colors[c][R],255); diff[G] = srcimg[3*((starty+y)*width+startx+x)+G] - CLAMP(0,possible_colors[c][G],255); diff[B] = srcimg[3*((starty+y)*width+startx+x)+B] - CLAMP(0,possible_colors[c][B],255); pixel_error = weight[R]*SQUARE(diff[R]) + weight[G]*SQUARE(diff[G]) + weight[B]*SQUARE(diff[B]); // Choose best error if (pixel_error < best_pixel_error) { best_pixel_error = pixel_error; pixel_colors ^= (pixel_colors & 3); // Reset the two first bits pixel_colors |= c; //insert the index for this pixel } } } block_error += best_pixel_error; } } if (block_error < best_block_error) { best_block_error = block_error; distance = d; pixel_indices = pixel_colors; best_sw = sw; } } if (sw == 1 && best_sw == 0) { swapColors(colorsRGB444); } decompressColor(R_BITS59T, G_BITS59T, B_BITS59T, colorsRGB444, colors); } return best_block_error; } // same as fastest t-mode compressor above, but here one of the colors (the central one in the T) is used to also signal that the pixel is transparent. // the only difference is that calculateError has been swapped out to one that considers alpha. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double compressBlockTHUMB59TAlpha(uint8 *img, uint8* alpha, int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { double best_error = MAXIMUM_ERROR; uint8 best_colorsRGB444[2][3]; unsigned int best_pixel_indices; uint8 best_distance; double error_no_i; uint8 colorsRGB444_no_i[2][3]; unsigned int pixel_indices_no_i; uint8 distance_no_i; uint8 colors[2][3]; // Calculate average color using the LBG-algorithm computeColorLBGHalfIntensityFast(img,width,startx,starty, colors); compressColor(R_BITS59T, G_BITS59T, B_BITS59T, colors, colorsRGB444_no_i); // Determine the parameters for the lowest error error_no_i = calculateError59TAlpha(img, alpha, width, startx, starty, colorsRGB444_no_i, distance_no_i, pixel_indices_no_i); best_error = error_no_i; best_distance = distance_no_i; best_pixel_indices = pixel_indices_no_i; copyColors(colorsRGB444_no_i, best_colorsRGB444); // Put the compress params into the compression block packBlock59T(best_colorsRGB444, best_distance, best_pixel_indices, compressed1, compressed2); return best_error; } // Put bits in order for the format. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void stuff59bitsDiffFalse(unsigned int thumbT59_word1, unsigned int thumbT59_word2, unsigned int &thumbT_word1, unsigned int &thumbT_word2) { // Put bits in twotimer configuration for 59 (red overflows) // // Go from this bit layout: // // |63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 40 39|38 37 36 35|34 33 32| // |----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|--dist--| // // |31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| // |----------------------------------------index bits---------------------------------------------| // // // To this: // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // ----------------------------------------------------------------------------------------------- // |// // //|R0a |//|R0b |G0 |B0 |R1 |G1 |B1 |da |df|db| // ----------------------------------------------------------------------------------------------- // // |31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| // |----------------------------------------index bits---------------------------------------------| // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // ----------------------------------------------------------------------------------------------- // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |df|fp| // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bt|bt| // ------------------------------------------------------------------------------------------------ uint8 R0a; uint8 bit, a, b, c, d, bits; R0a = GETBITSHIGH( thumbT59_word1, 2, 58); // Fix middle part thumbT_word1 = thumbT59_word1 << 1; // Fix R0a (top two bits of R0) PUTBITSHIGH( thumbT_word1, R0a, 2, 60); // Fix db (lowest bit of d) PUTBITSHIGH( thumbT_word1, thumbT59_word1, 1, 32); // // Make sure that red overflows: a = GETBITSHIGH( thumbT_word1, 1, 60); b = GETBITSHIGH( thumbT_word1, 1, 59); c = GETBITSHIGH( thumbT_word1, 1, 57); d = GETBITSHIGH( thumbT_word1, 1, 56); // The following bit abcd bit sequences should be padded with ones: 0111, 1010, 1011, 1101, 1110, 1111 // The following logical expression checks for the presence of any of those: bit = (a & c) | (!a & b & c & d) | (a & b & !c & d); bits = 0xf*bit; PUTBITSHIGH( thumbT_word1, bits, 3, 63); PUTBITSHIGH( thumbT_word1, !bit, 1, 58); // Set diffbit PUTBITSHIGH( thumbT_word1, 0, 1, 33); thumbT_word2 = thumbT59_word2; } // Tests if there is at least one pixel in the image which would get alpha = 0 in punchtrough mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. bool hasAlpha(uint8* alphaimg, int ix, int iy, int width) { for(int x=ix; x> 8) & 0xff; bytes[1] = (block >> 0) & 0xff; fwrite(&bytes[0],1,1,f); fwrite(&bytes[1],1,1,f); } // Write a word in big endian style // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void write_big_endian_4byte_word(unsigned int *blockadr, FILE *f) { uint8 bytes[4]; unsigned int block; block = blockadr[0]; bytes[0] = (block >> 24) & 0xff; bytes[1] = (block >> 16) & 0xff; bytes[2] = (block >> 8) & 0xff; bytes[3] = (block >> 0) & 0xff; fwrite(&bytes[0],1,1,f); fwrite(&bytes[1],1,1,f); fwrite(&bytes[2],1,1,f); fwrite(&bytes[3],1,1,f); } extern int alphaTable[256][8]; extern int alphaBase[16][4]; // valtab holds precalculated data used for compressing using EAC2. // Note that valtab is constructed using get16bits11bits, which means // that it already is expanded to 16 bits. // Note also that it its contents will depend on the value of formatSigned. int *valtab; void setupAlphaTableAndValtab() { setupAlphaTable(); //fix precomputation table..! valtab = new int[1024*512]; int16 val16; int count=0; for(int base=0; base<256; base++) { for(int tab=0; tab<16; tab++) { for(int mul=0; mul<16; mul++) { for(int index=0; index<8; index++) { if(formatSigned) { val16=get16bits11signed(base,tab,mul,index); valtab[count] = val16 + 256*128; } else valtab[count]=get16bits11bits(base,tab,mul,index); count++; } } } } } // Reads alpha data // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void readAlpha(uint8* &data, int &width, int &height, int &extendedwidth, int &extendedheight) { //width and height are already known..? uint8* tempdata; int wantedBitDepth; if(format==ETC2PACKAGE_RGBA_NO_MIPMAPS||format==ETC2PACKAGE_RGBA1_NO_MIPMAPS||format==ETC2PACKAGE_sRGBA_NO_MIPMAPS||format==ETC2PACKAGE_sRGBA1_NO_MIPMAPS) { wantedBitDepth=8; } else if(format==ETC2PACKAGE_R_NO_MIPMAPS) { wantedBitDepth=16; } else { printf("invalid format for alpha reading!\n"); exit(1); } fReadPGM("alpha.pgm",width,height,tempdata,wantedBitDepth); extendedwidth=4*((width+3)/4); extendedheight=4*((height+3)/4); if(width==extendedwidth&&height==extendedheight) { data=tempdata; } else { data = (uint8*)malloc(extendedwidth*extendedheight*wantedBitDepth/8); uint8 last=0; uint8 lastlast=0; for(int x=0; xmaxdist) maxdist=abs(alpha-data[ix+x+(iy+y)*width]); //maximum distance from average } } int approxPos = (maxdist*255)/160-4; //experimentally derived formula for calculating approximate table position given a max distance from average if(approxPos>255) approxPos=255; int startTable=approxPos-15; //first table to be tested if(startTable<0) startTable=0; int endTable=clamp(approxPos+15); //last table to be tested int bestsum=1000000000; int besttable=-3; int bestalpha=128; int prevalpha=alpha; //main loop: determine best base alpha value and offset table to use for compression //try some different alpha tables. for(int table = startTable; table0; table++) { int tablealpha=prevalpha; int tablebestsum=1000000000; //test some different alpha values, trying to find the best one for the given table. for(int alphascale=16; alphascale>0; alphascale/=4) { int startalpha; int endalpha; if(alphascale==16) { startalpha = clamp(tablealpha-alphascale*4); endalpha = clamp(tablealpha+alphascale*4); } else { startalpha = clamp(tablealpha-alphascale*2); endalpha = clamp(tablealpha+alphascale*2); } for(alpha=startalpha; alpha<=endalpha; alpha+=alphascale) { int sum=0; int val,diff,bestdiff=10000000,index; for(int x=0; x<4; x++) { for(int y=0; y<4; y++) { //compute best offset here, add square difference to sum.. val=data[ix+x+(iy+y)*width]; bestdiff=1000000000; //the values are always ordered from small to large, with the first 4 being negative and the last 4 positive //search is therefore made in the order 0-1-2-3 or 7-6-5-4, stopping when error increases compared to the previous entry tested. if(val>alpha) { for(index=7; index>3; index--) { diff=clamp_table[alpha+(int)(alphaTable[table][index])+255]-val; diff*=diff; if(diff<=bestdiff) { bestdiff=diff; } else break; } } else { for(index=0; index<4; index++) { diff=clamp_table[alpha+(int)(alphaTable[table][index])+255]-val; diff*=diff; if(diffbestsum) { x=9999; //just to make it large and get out of the x<4 loop break; } } } if(sum7) { bit=0; byte++; } } } } } // Helper function for the below function // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. int getPremulIndex(int base, int tab, int mul, int index) { return (base<<11)+(tab<<7)+(mul<<3)+index; } // Calculates the error used in compressBlockAlpha16() // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double calcError(uint8* data, int ix, int iy, int width, int height, int base, int tab, int mul, double prevbest) { int offset = getPremulIndex(base,tab,mul,0); double error=0; for (int y=0; y<4; y++) { for(int x=0; x<4; x++) { double besthere = (1<<20); besthere*=besthere; uint8 byte1 = data[2*(x+ix+(y+iy)*width)]; uint8 byte2 = data[2*(x+ix+(y+iy)*width)+1]; int alpha = (byte1<<8)+byte2; for(int index=0; index<8; index++) { double indexError; indexError = alpha-valtab[offset+index]; indexError*=indexError; if(indexError=prevbest) return prevbest+(1<<30); } } return error; } // compressBlockAlpha16 // // Compresses a block using the 11-bit EAC formats. // Depends on the global variable formatSigned. // // COMPRESSED_R11_EAC (if formatSigned = 0) // This is an 11-bit unsigned format. Since we do not have a good 11-bit file format, we use 16-bit pgm instead. // Here we assume that, in the input 16-bit pgm file, 0 represents 0.0 and 65535 represents 1.0. The function compressBlockAlpha16 // will find the compressed block which best matches the data. In detail, it will find the compressed block, which // if decompressed, will generate an 11-bit block that after bit replication to 16-bits will generate the closest // block to the original 16-bit pgm block. // // COMPRESSED_SIGNED_R11_EAC (if formatSigned = 1) // This is an 11-bit signed format. Since we do not have any signed file formats, we use unsigned 16-bit pgm instead. // Hence we assume that, in the input 16-bit pgm file, 1 represents -1.0, 32768 represents 0.0 and 65535 represents 1.0. // The function compresseBlockAlpha16 will find the compressed block, which if decompressed, will generate a signed // 11-bit block that after bit replication to 16-bits and conversion to unsigned (1 equals -1.0, 32768 equals 0.0 and // 65535 equals 1.0) will generate the closest block to the original 16-bit pgm block. // // COMPRESSED_RG11_EAC is compressed by calling the function twice, dito for COMPRESSED_SIGNED_RG11_EAC. // // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressBlockAlpha16(uint8* data, int ix, int iy, int width, int height, uint8* returnData) { unsigned int bestbase, besttable, bestmul; double besterror; besterror=1<<20; besterror*=besterror; for(int base=0; base<256; base++) { for(int table=0; table<16; table++) { for(int mul=0; mul<16; mul++) { double e = calcError(data, ix, iy, width, height,base,table,mul,besterror); if(e7) { bit=0; byte++; } } } } } // Exhaustive compression of alpha compression in a GL_COMPRESSED_RGB8_ETC2 block // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressBlockAlphaSlow(uint8* data, int ix, int iy, int width, int height, uint8* returnData) { //determine the best table and base alpha value for this block using MSE int alphasum=0; int maxdist=-2; for(int x=0; x<4; x++) { for(int y=0; y<4; y++) { alphasum+=data[ix+x+(iy+y)*width]; } } int alpha = (int)( ((float)alphasum)/16.0f+0.5f); //average pixel value, used as guess for base value. int bestsum=1000000000; int besttable=-3; int bestalpha=128; int prevalpha=alpha; //main loop: determine best base alpha value and offset table to use for compression //try some different alpha tables. for(int table = 0; table<256&&bestsum>0; table++) { int tablealpha=prevalpha; int tablebestsum=1000000000; //test some different alpha values, trying to find the best one for the given table. for(int alphascale=32; alphascale>0; alphascale/=8) { int startalpha = clamp(tablealpha-alphascale*4); int endalpha = clamp(tablealpha+alphascale*4); for(alpha=startalpha; alpha<=endalpha; alpha+=alphascale) { int sum=0; int val,diff,bestdiff=10000000,index; for(int x=0; x<4; x++) { for(int y=0; y<4; y++) { //compute best offset here, add square difference to sum.. val=data[ix+x+(iy+y)*width]; bestdiff=1000000000; //the values are always ordered from small to large, with the first 4 being negative and the last 4 positive //search is therefore made in the order 0-1-2-3 or 7-6-5-4, stopping when error increases compared to the previous entry tested. if(val>alpha) { for(index=7; index>3; index--) { diff=clamp_table[alpha+(alphaTable[table][index])+255]-val; diff*=diff; if(diff<=bestdiff) { bestdiff=diff; } else break; } } else { for(index=0; index<5; index++) { diff=clamp_table[alpha+(alphaTable[table][index])+255]-val; diff*=diff; if(difftablebestsum) { x=9999; //just to make it large and get out of the x<4 loop break; } } } if(sum7) { bit=0; byte++; } } } } } // Calculate weighted PSNR // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double calculateWeightedPSNR(uint8 *lossyimg, uint8 *origimg, int width, int height, double w1, double w2, double w3) { // Note: This calculation of PSNR uses the formula // // PSNR = 10 * log_10 ( 255^2 / wMSE ) // // where the wMSE is calculated as // // 1/(N*M) * sum ( ( w1*(R' - R)^2 + w2*(G' - G)^2 + w3*(B' - B)^2) ) // // typical weights are 0.299, 0.587, 0.114 for perceptually weighted PSNR and // 1.0/3.0, 1.0/3.0, 1.0/3.0 for nonweighted PSNR int x,y; double wMSE; double PSNR; double err; wMSE = 0; for(y=0;y.\n",srcfile); exit(1); } height=active_height; width=active_width; fclose(f); } // Writes output file // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void writeOutputFile(char *dstfile, uint8* img, uint8* alphaimg, int width, int height) { char str[300]; if(format!=ETC2PACKAGE_R_NO_MIPMAPS&&format!=ETC2PACKAGE_RG_NO_MIPMAPS) { fWritePPM("tmp.ppm",width,height,img,8,false); printf("Saved file tmp.ppm \n\n"); } else if(format==ETC2PACKAGE_RG_NO_MIPMAPS) { fWritePPM("tmp.ppm",width,height,img,16,false); } if(format==ETC2PACKAGE_RGBA_NO_MIPMAPS||format==ETC2PACKAGE_RGBA1_NO_MIPMAPS||format==ETC2PACKAGE_sRGBA_NO_MIPMAPS||format==ETC2PACKAGE_sRGBA1_NO_MIPMAPS) fWritePGM("alphaout.pgm",width,height,alphaimg,false,8); if(format==ETC2PACKAGE_R_NO_MIPMAPS) fWritePGM("alphaout.pgm",width,height,alphaimg,false,16); // Delete destination file if it exists if(fileExist(dstfile)) { sprintf(str, "del %s\n",dstfile); system(str); } int q = find_pos_of_extension(dstfile); if(!strcmp(&dstfile[q],".ppm")&&format!=ETC2PACKAGE_R_NO_MIPMAPS) { // Already a .ppm file. Just rename. sprintf(str,"move tmp.ppm %s\n",dstfile); printf("Renaming destination file to %s\n",dstfile); } else { // Converting from .ppm to other file format // // Use your favorite command line image converter program, // for instance Image Magick. Just make sure the syntax can // be written as below: // // C:\imconv source.ppm dest.jpg // if(format==ETC2PACKAGE_RGBA_NO_MIPMAPS||format==ETC2PACKAGE_RGBA1_NO_MIPMAPS||format==ETC2PACKAGE_sRGBA_NO_MIPMAPS||format==ETC2PACKAGE_sRGBA1_NO_MIPMAPS) { // Somewhere after version 6.7.1-2 of ImageMagick the following command gives the wrong result due to a bug. // sprintf(str,"composite -compose CopyOpacity alphaout.pgm tmp.ppm %s\n",dstfile); // Instead we read the file and write a tga. printf("Converting destination file from .ppm/.pgm to %s with alpha\n",dstfile); int rw, rh; unsigned char *pixelsRGB; unsigned char *pixelsA; fReadPPM("tmp.ppm", rw, rh, pixelsRGB, 8); fReadPGM("alphaout.pgm", rw, rh, pixelsA, 8); fWriteTGAfromRGBandA(dstfile, rw, rh, pixelsRGB, pixelsA, true); free(pixelsRGB); free(pixelsA); sprintf(str,""); // Nothing to execute. } else if(format==ETC2PACKAGE_R_NO_MIPMAPS) { sprintf(str,"imconv alphaout.pgm %s\n",dstfile); printf("Converting destination file from .pgm to %s\n",dstfile); } else { sprintf(str,"imconv tmp.ppm %s\n",dstfile); printf("Converting destination file from .ppm to %s\n",dstfile); } } // Execute system call system(str); free(img); if(alphaimg!=NULL) free(alphaimg); } // Calculates the PSNR between two files // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double calculatePSNRfile(char *srcfile, uint8 *origimg, uint8* origalpha) { uint8 *alphaimg, *img; int active_width, active_height; uncompressFile(srcfile,img,alphaimg,active_width,active_height); // calculate Mean Square Error (MSE) double MSER=0,MSEG=0,MSEB=0,MSEA, PSNRR,PSNRG,PSNRA; double MSE; double wMSE; double PSNR=0; double wPSNR; double err; MSE = 0; MSEA=0; wMSE = 0; int width=((active_width+3)/4)*4; int height=((active_height+3)/4)*4; int numpixels = 0; for(int y=0;y 0) { err = img[y*active_width*3+x*3+0] - origimg[y*width*3+x*3+0]; MSE += ((err * err)/3.0); wMSE += PERCEPTUAL_WEIGHT_R_SQUARED * (err*err); err = img[y*active_width*3+x*3+1] - origimg[y*width*3+x*3+1]; MSE += ((err * err)/3.0); wMSE += PERCEPTUAL_WEIGHT_G_SQUARED * (err*err); err = img[y*active_width*3+x*3+2] - origimg[y*width*3+x*3+2]; MSE += ((err * err)/3.0); wMSE += PERCEPTUAL_WEIGHT_B_SQUARED * (err*err); numpixels++; } } else if(format==ETC2PACKAGE_RG_NO_MIPMAPS) { int rorig = (origimg[6*(y*width+x)+0]<<8)+origimg[6*(y*width+x)+1]; int rnew = ( img[6*(y*active_width+x)+0]<<8)+ img[6*(y*active_width+x)+1]; int gorig = (origimg[6*(y*width+x)+2]<<8)+origimg[6*(y*width+x)+3]; int gnew = ( img[6*(y*active_width+x)+2]<<8)+ img[6*(y*active_width+x)+3]; err=rorig-rnew; MSER+=(err*err); err=gorig-gnew; MSEG+=(err*err); } else if(format==ETC2PACKAGE_R_NO_MIPMAPS) { int aorig = (((int)origalpha[2*(y*width+x)+0])<<8)+origalpha[2*(y*width+x)+1]; int anew = (((int)alphaimg[2*(y*active_width+x)+0])<<8)+alphaimg[2*(y*active_width+x)+1]; err=aorig-anew; MSEA+=(err*err); } } } if(format == ETC2PACKAGE_RGBA1_NO_MIPMAPS || format == ETC2PACKAGE_sRGBA1_NO_MIPMAPS) { MSE = MSE / (1.0 * numpixels); wMSE = wMSE / (1.0 * numpixels); PSNR = 10*log((1.0*255*255)/MSE)/log(10.0); wPSNR = 10*log((1.0*255*255)/wMSE)/log(10.0); printf("PSNR only calculated on pixels where compressed alpha > 0\n"); printf("color PSNR: %lf\nweighted PSNR: %lf\n",PSNR,wPSNR); } else if(format!=ETC2PACKAGE_R_NO_MIPMAPS&&format!=ETC2PACKAGE_RG_NO_MIPMAPS) { MSE = MSE / (active_width * active_height); wMSE = wMSE / (active_width * active_height); PSNR = 10*log((1.0*255*255)/MSE)/log(10.0); wPSNR = 10*log((1.0*255*255)/wMSE)/log(10.0); if(format == ETC2PACKAGE_RGBA_NO_MIPMAPS || format == ETC2PACKAGE_sRGBA_NO_MIPMAPS) printf("PSNR only calculated on RGB, not on alpha\n"); printf("color PSNR: %lf\nweighted PSNR: %lf\n",PSNR,wPSNR); } else if(format==ETC2PACKAGE_RG_NO_MIPMAPS) { MSER = MSER / (active_width * active_height); MSEG = MSEG / (active_width * active_height); PSNRR = 10*log((1.0*65535*65535)/MSER)/log(10.0); PSNRG = 10*log((1.0*65535*65535)/MSEG)/log(10.0); printf("red PSNR: %lf\ngreen PSNR: %lf\n",PSNRR,PSNRG); } else if(format==ETC2PACKAGE_R_NO_MIPMAPS) { MSEA = MSEA / (active_width * active_height); PSNRA = 10*log((1.0*65535.0*65535.0)/MSEA)/log(10.0); printf("PSNR: %lf\n",PSNRA); } free(img); return PSNR; } //// Exhaustive code starts here. #if EXHAUSTIVE_CODE_ACTIVE // Precomutes a table that is used when compressing a block exhaustively // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. inline unsigned int precompute_3bittable_all_subblocksRG_withtest_perceptual1000(uint8 *block,uint8 *avg_color, unsigned int *precalc_err_UL_R, unsigned int *precalc_err_UR_R, unsigned int *precalc_err_LL_R, unsigned int *precalc_err_LR_R,unsigned int *precalc_err_UL_RG, unsigned int *precalc_err_UR_RG, unsigned int *precalc_err_LL_RG, unsigned int *precalc_err_LR_RG, unsigned int best_err) { int table; int index; int orig[3],approx[3][4]; int x; int intensity_modifier; const int *table_indices; int good_enough_to_test; unsigned int err[4]; unsigned int err_this_table_upper; unsigned int err_this_table_lower; unsigned int err_this_table_left; unsigned int err_this_table_right; // If the error in the red and green component is already larger than best_err for all 8 tables in // all of upper, lower, left and right, this combination of red and green will never be used in // the optimal color configuration. Therefore we can avoid testing all the blue colors for this // combination. good_enough_to_test = false; for(table=0;table<8;table++) // try all the 8 tables. { table_indices = &compressParamsFast[table*4]; intensity_modifier = table_indices[0]; approx[1][0]=CLAMP(0, avg_color[1]+intensity_modifier,255); intensity_modifier = table_indices[1]; approx[1][1]=CLAMP(0, avg_color[1]+intensity_modifier,255); intensity_modifier = table_indices[2]; approx[1][2]=CLAMP(0, avg_color[1]+intensity_modifier,255); intensity_modifier = table_indices[3]; approx[1][3]=CLAMP(0, avg_color[1]+intensity_modifier,255); err_this_table_upper = 0; err_this_table_lower = 0; err_this_table_left = 0; err_this_table_right = 0; for(x=0; x<4; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index] = precalc_err_UL_R[table*4*4+x*4+index] + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000 * SQUARE(approx[1][index]-orig[1]); precalc_err_UL_RG[table*4*4+x*4+index] = err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_upper+=err[0]; err_this_table_left+=err[0]; } for(x=4; x<8; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index] = precalc_err_UR_R[table*4*4+(x-4)*4+index] + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000 * SQUARE(approx[1][index]-orig[1]); precalc_err_UR_RG[table*4*4+(x-4)*4+index] = err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_upper+=err[0]; err_this_table_right+=err[0]; } for(x=8; x<12; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index] = precalc_err_LL_R[table*4*4+(x-8)*4+index] + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000 * SQUARE(approx[1][index]-orig[1]); precalc_err_LL_RG[table*4*4+(x-8)*4+index] = err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_lower+=err[0]; err_this_table_left+=err[0]; } for(x=12; x<16; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index] = precalc_err_LR_R[table*4*4+(x-12)*4+index] + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000 * SQUARE(approx[1][index]-orig[1]); precalc_err_LR_RG[table*4*4+(x-12)*4+index] = err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_lower+=err[0]; err_this_table_right+=err[0]; } if(err_this_table_upper < best_err) good_enough_to_test = true; if(err_this_table_lower < best_err) good_enough_to_test = true; if(err_this_table_left < best_err) good_enough_to_test = true; if(err_this_table_right < best_err) good_enough_to_test = true; } return good_enough_to_test; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precomutes a table that is used when compressing a block exhaustively // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. inline int precompute_3bittable_all_subblocksRG_withtest(uint8 *block,uint8 *avg_color, unsigned int *precalc_err_UL_R, unsigned int *precalc_err_UR_R, unsigned int *precalc_err_LL_R, unsigned int *precalc_err_LR_R,unsigned int *precalc_err_UL_RG, unsigned int *precalc_err_UR_RG, unsigned int *precalc_err_LL_RG, unsigned int *precalc_err_LR_RG, unsigned int best_err) { int table; int index; int orig[3],approx[3][4]; int x; int intensity_modifier; const int *table_indices; int good_enough_to_test; unsigned int err[4]; unsigned int err_this_table_upper; unsigned int err_this_table_lower; unsigned int err_this_table_left; unsigned int err_this_table_right; // If the error in the red and green component is already larger than best_err for all 8 tables in // all of upper, lower, left and right, this combination of red and green will never be used in // the optimal color configuration. Therefore we can avoid testing all the blue colors for this // combination. good_enough_to_test = false; for(table=0;table<8;table++) // try all the 8 tables. { table_indices = &compressParamsFast[table*4]; intensity_modifier = table_indices[0]; approx[1][0]=CLAMP(0, avg_color[1]+intensity_modifier,255); intensity_modifier = table_indices[1]; approx[1][1]=CLAMP(0, avg_color[1]+intensity_modifier,255); intensity_modifier = table_indices[2]; approx[1][2]=CLAMP(0, avg_color[1]+intensity_modifier,255); intensity_modifier = table_indices[3]; approx[1][3]=CLAMP(0, avg_color[1]+intensity_modifier,255); err_this_table_upper = 0; err_this_table_lower = 0; err_this_table_left = 0; err_this_table_right = 0; for(x=0; x<4; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index] = precalc_err_UL_R[table*4*4+x*4+index]+SQUARE(approx[1][index]-orig[1]); precalc_err_UL_RG[table*4*4+x*4+index] = err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_upper+=err[0]; err_this_table_left+=err[0]; } for(x=4; x<8; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index] = precalc_err_UR_R[table*4*4+(x-4)*4+index]+SQUARE(approx[1][index]-orig[1]); precalc_err_UR_RG[table*4*4+(x-4)*4+index] = err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_upper+=err[0]; err_this_table_right+=err[0]; } for(x=8; x<12; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index] = precalc_err_LL_R[table*4*4+(x-8)*4+index]+SQUARE(approx[1][index]-orig[1]); precalc_err_LL_RG[table*4*4+(x-8)*4+index] = err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_lower+=err[0]; err_this_table_left+=err[0]; } for(x=12; x<16; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index] = precalc_err_LR_R[table*4*4+(x-12)*4+index]+SQUARE(approx[1][index]-orig[1]); precalc_err_LR_RG[table*4*4+(x-12)*4+index] = err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_lower+=err[0]; err_this_table_right+=err[0]; } if(err_this_table_upper < best_err) good_enough_to_test = true; if(err_this_table_lower < best_err) good_enough_to_test = true; if(err_this_table_left < best_err) good_enough_to_test = true; if(err_this_table_right < best_err) good_enough_to_test = true; } return good_enough_to_test; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precomutes a table that is used when compressing a block exhaustively // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. inline unsigned int precompute_3bittable_all_subblocksR_with_test_perceptual1000(uint8 *block,uint8 *avg_color, unsigned int *precalc_err_UL_R, unsigned int *precalc_err_UR_R, unsigned int *precalc_err_LL_R, unsigned int *precalc_err_LR_R, unsigned int best_err) { int table; int index; int orig[3],approx[3][4]; int x; int intensity_modifier; const int *table_indices; unsigned int err[4]; unsigned int err_this_table_upper; unsigned int err_this_table_lower; unsigned int err_this_table_left; unsigned int err_this_table_right; int good_enough_to_test; good_enough_to_test = false; for(table=0;table<8;table++) // try all the 8 tables. { err_this_table_upper = 0; err_this_table_lower = 0; err_this_table_left = 0; err_this_table_right = 0; table_indices = &compressParamsFast[table*4]; intensity_modifier = table_indices[0]; approx[0][0]=CLAMP(0, avg_color[0]+intensity_modifier,255); intensity_modifier = table_indices[1]; approx[0][1]=CLAMP(0, avg_color[0]+intensity_modifier,255); intensity_modifier = table_indices[2]; approx[0][2]=CLAMP(0, avg_color[0]+intensity_modifier,255); intensity_modifier = table_indices[3]; approx[0][3]=CLAMP(0, avg_color[0]+intensity_modifier,255); for(x=0; x<4; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index]=PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*SQUARE(approx[0][index]-orig[0]); precalc_err_UL_R[table*4*4+x*4+index]=err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_upper+=err[0]; err_this_table_left+=err[0]; } for(x=4; x<8; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index]=PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*SQUARE(approx[0][index]-orig[0]); precalc_err_UR_R[table*4*4+(x-4)*4+index]=err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_upper+=err[0]; err_this_table_right+=err[0]; } for(x=8; x<12; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index]=PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*SQUARE(approx[0][index]-orig[0]); precalc_err_LL_R[table*4*4+(x-8)*4+index]=err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_lower+=err[0]; err_this_table_left+=err[0]; } for(x=12; x<16; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index]=PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*SQUARE(approx[0][index]-orig[0]); precalc_err_LR_R[table*4*4+(x-12)*4+index]=err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_lower+=err[0]; err_this_table_right+=err[0]; } if(err_this_table_upper < best_err) good_enough_to_test = true; if(err_this_table_lower < best_err) good_enough_to_test = true; if(err_this_table_left < best_err) good_enough_to_test = true; if(err_this_table_right < best_err) good_enough_to_test = true; } return good_enough_to_test; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precomutes a table that is used when compressing a block exhaustively // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. inline int precompute_3bittable_all_subblocksR_with_test(uint8 *block,uint8 *avg_color, unsigned int *precalc_err_UL_R, unsigned int *precalc_err_UR_R, unsigned int *precalc_err_LL_R, unsigned int *precalc_err_LR_R, unsigned int best_err) { int table; int index; int orig[3],approx[3][4]; int x; int intensity_modifier; const int *table_indices; unsigned int err[4]; unsigned int err_this_table_upper; unsigned int err_this_table_lower; unsigned int err_this_table_left; unsigned int err_this_table_right; int good_enough_to_test; good_enough_to_test = false; for(table=0;table<8;table++) // try all the 8 tables. { err_this_table_upper = 0; err_this_table_lower = 0; err_this_table_left = 0; err_this_table_right = 0; table_indices = &compressParamsFast[table*4]; intensity_modifier = table_indices[0]; approx[0][0]=CLAMP(0, avg_color[0]+intensity_modifier,255); intensity_modifier = table_indices[1]; approx[0][1]=CLAMP(0, avg_color[0]+intensity_modifier,255); intensity_modifier = table_indices[2]; approx[0][2]=CLAMP(0, avg_color[0]+intensity_modifier,255); intensity_modifier = table_indices[3]; approx[0][3]=CLAMP(0, avg_color[0]+intensity_modifier,255); for(x=0; x<4; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index]=SQUARE(approx[0][index]-orig[0]); precalc_err_UL_R[table*4*4+x*4+index]=err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_upper+=err[0]; err_this_table_left+=err[0]; } for(x=4; x<8; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index]=SQUARE(approx[0][index]-orig[0]); precalc_err_UR_R[table*4*4+(x-4)*4+index]=err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_upper+=err[0]; err_this_table_right+=err[0]; } for(x=8; x<12; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index]=SQUARE(approx[0][index]-orig[0]); precalc_err_LL_R[table*4*4+(x-8)*4+index]=err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_lower+=err[0]; err_this_table_left+=err[0]; } for(x=12; x<16; x++) { orig[0]=block[x*4]; orig[1]=block[x*4+1]; orig[2]=block[x*4+2]; for(index=0;index<4;index++) { err[index]=SQUARE(approx[0][index]-orig[0]); precalc_err_LR_R[table*4*4+(x-12)*4+index]=err[index]; } if(err[0] > err[1]) err[0] = err[1]; if(err[2] > err[3]) err[2] = err[3]; if(err[0] > err[2]) err[0] = err[2]; err_this_table_lower+=err[0]; err_this_table_right+=err[0]; } if(err_this_table_upper < best_err) good_enough_to_test = true; if(err_this_table_lower < best_err) good_enough_to_test = true; if(err_this_table_left < best_err) good_enough_to_test = true; if(err_this_table_right < best_err) good_enough_to_test = true; } return good_enough_to_test; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Tries all index-tables, used when compressing a block exhaustively // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. inline void tryalltables_3bittable_all_subblocks_using_precalc(uint8 *block_2x2,uint8 *color_quant1, unsigned int *precalc_err_UL_RG, unsigned int *precalc_err_UR_RG, unsigned int *precalc_err_LL_RG, unsigned int *precalc_err_LR_RG, unsigned int &err_upper, unsigned int &err_lower, unsigned int &err_left, unsigned int &err_right, unsigned int best_err) { unsigned int err_this_table_upper; unsigned int err_this_table_lower; unsigned int err_this_table_left; unsigned int err_this_table_right; int orig[3],approx[4]; int err[4]; err_upper = 3*255*255*16; err_lower = 3*255*255*16; err_left = 3*255*255*16; err_right = 3*255*255*16; #define ONE_PIXEL_UL(table_nbr,xx)\ orig[0]=block_2x2[xx*4];\ orig[1]=block_2x2[xx*4+1];\ orig[2]=block_2x2[xx*4+2];\ /* unrolled loop for(index=0;index<4;index++)*/\ err[0]=precalc_err_UL_RG[table_nbr*4*4+xx*4+0] + square_table[approx[0]-orig[2]];\ err[1]=precalc_err_UL_RG[table_nbr*4*4+xx*4+1] + square_table[approx[1]-orig[2]];\ err[2]=precalc_err_UL_RG[table_nbr*4*4+xx*4+2] + square_table[approx[2]-orig[2]];\ err[3]=precalc_err_UL_RG[table_nbr*4*4+xx*4+3] + square_table[approx[3]-orig[2]];\ /* end unrolled loop*/\ if(err[0] > err[1])\ err[0] = err[1];\ if(err[2] > err[3])\ err[2] = err[3];\ if(err[0] > err[2])\ err[0] = err[2];\ err_this_table_upper+=err[0];\ err_this_table_left+=err[0];\ #define ONE_PIXEL_UR(table_nbr,xx)\ orig[0]=block_2x2[xx*4];\ orig[1]=block_2x2[xx*4+1];\ orig[2]=block_2x2[xx*4+2];\ /* unrolled loop for(index=0;index<4;index++)*/\ err[0]=precalc_err_UR_RG[table_nbr*4*4+(xx-4)*4+0] + square_table[approx[0]-orig[2]];\ err[1]=precalc_err_UR_RG[table_nbr*4*4+(xx-4)*4+1] + square_table[approx[1]-orig[2]];\ err[2]=precalc_err_UR_RG[table_nbr*4*4+(xx-4)*4+2] + square_table[approx[2]-orig[2]];\ err[3]=precalc_err_UR_RG[table_nbr*4*4+(xx-4)*4+3] + square_table[approx[3]-orig[2]];\ /* end unrolled loop */\ if(err[0] > err[1])\ err[0] = err[1];\ if(err[2] > err[3])\ err[2] = err[3];\ if(err[0] > err[2])\ err[0] = err[2];\ err_this_table_upper+=err[0];\ err_this_table_right+=err[0]; #define ONE_PIXEL_LL(table_nbr,xx)\ orig[0]=block_2x2[xx*4];\ orig[1]=block_2x2[xx*4+1];\ orig[2]=block_2x2[xx*4+2];\ /* unrolled loop for(index=0;index<4;index++)*/\ err[0]=precalc_err_LL_RG[table_nbr*4*4+(xx-8)*4+0] + square_table[approx[0]-orig[2]];\ err[1]=precalc_err_LL_RG[table_nbr*4*4+(xx-8)*4+1] + square_table[approx[1]-orig[2]];\ err[2]=precalc_err_LL_RG[table_nbr*4*4+(xx-8)*4+2] + square_table[approx[2]-orig[2]];\ err[3]=precalc_err_LL_RG[table_nbr*4*4+(xx-8)*4+3] + square_table[approx[3]-orig[2]];\ /* end unrolled loop*/\ if(err[0] > err[1])\ err[0] = err[1];\ if(err[2] > err[3])\ err[2] = err[3];\ if(err[0] > err[2])\ err[0] = err[2];\ err_this_table_lower+=err[0];\ err_this_table_left+=err[0];\ #define ONE_PIXEL_LR(table_nbr,xx)\ orig[0]=block_2x2[xx*4];\ orig[1]=block_2x2[xx*4+1];\ orig[2]=block_2x2[xx*4+2];\ /* unrolled loop for(index=0;index<4;index++)*/\ err[0]=precalc_err_LR_RG[table_nbr*4*4+(xx-12)*4+0] + square_table[approx[0]-orig[2]];\ err[1]=precalc_err_LR_RG[table_nbr*4*4+(xx-12)*4+1] + square_table[approx[1]-orig[2]];\ err[2]=precalc_err_LR_RG[table_nbr*4*4+(xx-12)*4+2] + square_table[approx[2]-orig[2]];\ err[3]=precalc_err_LR_RG[table_nbr*4*4+(xx-12)*4+3] + square_table[approx[3]-orig[2]];\ /* end unrolled loop*/\ if(err[0] > err[1])\ err[0] = err[1];\ if(err[2] > err[3])\ err[2] = err[3];\ if(err[0] > err[2])\ err[0] = err[2];\ err_this_table_lower+=err[0];\ err_this_table_right+=err[0];\ #define ONE_TABLE_3(table_nbr)\ err_this_table_upper = 0;\ err_this_table_lower = 0;\ err_this_table_left = 0;\ err_this_table_right = 0;\ approx[0]=clamp_table_plus_255[color_quant1[2]+compressParamsFast[table_nbr*4+0]+255];\ approx[1]=clamp_table_plus_255[color_quant1[2]+compressParamsFast[table_nbr*4+1]+255];\ approx[2]=clamp_table_plus_255[color_quant1[2]+compressParamsFast[table_nbr*4+2]+255];\ approx[3]=clamp_table_plus_255[color_quant1[2]+compressParamsFast[table_nbr*4+3]+255];\ /* unroll loop for(xx=0; xx<4; xx++) */\ ONE_PIXEL_UL(table_nbr,0)\ ONE_PIXEL_UL(table_nbr,1)\ ONE_PIXEL_UL(table_nbr,2)\ ONE_PIXEL_UL(table_nbr,3)\ /* end unroll loop */\ /* unroll loop for(xx=4; xx<8; xx++) */\ ONE_PIXEL_LR(table_nbr,12)\ ONE_PIXEL_LR(table_nbr,13)\ ONE_PIXEL_LR(table_nbr,14)\ ONE_PIXEL_LR(table_nbr,15)\ /* end unroll loop */\ /* If error in the top left 2x2 pixel area is already larger than the best error, and */\ /* The same is true for the bottom right 2x2 pixel area, this combination of table and color */\ /* can never be part of an optimal solution and therefore we do not need to test the other */\ /* two 2x2 pixel areas */\ if((err_this_table_upper err[1])\ err[0] = err[1];\ if(err[2] > err[3])\ err[2] = err[3];\ if(err[0] > err[2])\ err[0] = err[2];\ err_this_table_upper+=err[0];\ err_this_table_left+=err[0];\ #define ONE_PIXEL_UR_PERCEP(table_nbr,xx)\ orig[0]=block_2x2[xx*4];\ orig[1]=block_2x2[xx*4+1];\ orig[2]=block_2x2[xx*4+2];\ /* unrolled loop for(index=0;index<4;index++)*/\ err[0]=precalc_err_UR_RG[table_nbr*4*4+(xx-4)*4+0] + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[approx[0]-orig[2]];\ err[1]=precalc_err_UR_RG[table_nbr*4*4+(xx-4)*4+1] + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[approx[1]-orig[2]];\ err[2]=precalc_err_UR_RG[table_nbr*4*4+(xx-4)*4+2] + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[approx[2]-orig[2]];\ err[3]=precalc_err_UR_RG[table_nbr*4*4+(xx-4)*4+3] + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[approx[3]-orig[2]];\ /* end unrolled loop */\ if(err[0] > err[1])\ err[0] = err[1];\ if(err[2] > err[3])\ err[2] = err[3];\ if(err[0] > err[2])\ err[0] = err[2];\ err_this_table_upper+=err[0];\ err_this_table_right+=err[0]; #define ONE_PIXEL_LL_PERCEP(table_nbr,xx)\ orig[0]=block_2x2[xx*4];\ orig[1]=block_2x2[xx*4+1];\ orig[2]=block_2x2[xx*4+2];\ /* unrolled loop for(index=0;index<4;index++)*/\ err[0]=precalc_err_LL_RG[table_nbr*4*4+(xx-8)*4+0] + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[approx[0]-orig[2]];\ err[1]=precalc_err_LL_RG[table_nbr*4*4+(xx-8)*4+1] + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[approx[1]-orig[2]];\ err[2]=precalc_err_LL_RG[table_nbr*4*4+(xx-8)*4+2] + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[approx[2]-orig[2]];\ err[3]=precalc_err_LL_RG[table_nbr*4*4+(xx-8)*4+3] + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[approx[3]-orig[2]];\ /* end unrolled loop*/\ if(err[0] > err[1])\ err[0] = err[1];\ if(err[2] > err[3])\ err[2] = err[3];\ if(err[0] > err[2])\ err[0] = err[2];\ err_this_table_lower+=err[0];\ err_this_table_left+=err[0];\ #define ONE_PIXEL_LR_PERCEP(table_nbr,xx)\ orig[0]=block_2x2[xx*4];\ orig[1]=block_2x2[xx*4+1];\ orig[2]=block_2x2[xx*4+2];\ /* unrolled loop for(index=0;index<4;index++)*/\ err[0]=precalc_err_LR_RG[table_nbr*4*4+(xx-12)*4+0] + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[approx[0]-orig[2]];\ err[1]=precalc_err_LR_RG[table_nbr*4*4+(xx-12)*4+1] + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[approx[1]-orig[2]];\ err[2]=precalc_err_LR_RG[table_nbr*4*4+(xx-12)*4+2] + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[approx[2]-orig[2]];\ err[3]=precalc_err_LR_RG[table_nbr*4*4+(xx-12)*4+3] + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[approx[3]-orig[2]];\ /* end unrolled loop*/\ if(err[0] > err[1])\ err[0] = err[1];\ if(err[2] > err[3])\ err[2] = err[3];\ if(err[0] > err[2])\ err[0] = err[2];\ err_this_table_lower+=err[0];\ err_this_table_right+=err[0];\ #define ONE_TABLE_3_PERCEP(table_nbr)\ err_this_table_upper = 0;\ err_this_table_lower = 0;\ err_this_table_left = 0;\ err_this_table_right = 0;\ approx[0]=clamp_table_plus_255[color_quant1[2]+compressParamsFast[table_nbr*4+0]+255];\ approx[1]=clamp_table_plus_255[color_quant1[2]+compressParamsFast[table_nbr*4+1]+255];\ approx[2]=clamp_table_plus_255[color_quant1[2]+compressParamsFast[table_nbr*4+2]+255];\ approx[3]=clamp_table_plus_255[color_quant1[2]+compressParamsFast[table_nbr*4+3]+255];\ /* unroll loop for(xx=0; xx<4; xx++) */\ ONE_PIXEL_UL_PERCEP(table_nbr,0)\ ONE_PIXEL_UL_PERCEP(table_nbr,1)\ ONE_PIXEL_UL_PERCEP(table_nbr,2)\ ONE_PIXEL_UL_PERCEP(table_nbr,3)\ /* end unroll loop */\ /* unroll loop for(xx=4; xx<8; xx++) */\ ONE_PIXEL_LR_PERCEP(table_nbr,12)\ ONE_PIXEL_LR_PERCEP(table_nbr,13)\ ONE_PIXEL_LR_PERCEP(table_nbr,14)\ ONE_PIXEL_LR_PERCEP(table_nbr,15)\ /* end unroll loop */\ /* If error in the top left 2x2 pixel area is already larger than the best error, and */\ /* The same is true for the bottom right 2x2 pixel area, this combination of table and color */\ /* can never be part of an optimal solution and therefore we do not need to test the other */\ /* two 2x2 pixel areas */\ if((err_this_table_upper> 5; bytediff[1] = bytediff[1] >> 5; bytediff[2] = bytediff[2] >> 5; best_enc_color2[0]= best_enc_color1[0] + bytediff[0]; best_enc_color2[1]= best_enc_color1[1] + bytediff[1]; best_enc_color2[2]= best_enc_color1[2] + bytediff[2]; // allocate memory for errors: err_upper = (unsigned int*) malloc(32*32*32*sizeof(unsigned int)); if(!err_upper){printf("Out of memory allocating \n");exit(1);} err_lower = (unsigned int*) malloc(32*32*32*sizeof(unsigned int)); if(!err_lower){printf("Out of memory allocating \n");exit(1);} err_left = (unsigned int*) malloc(32*32*32*sizeof(unsigned int)); if(!err_left){printf("Out of memory allocating \n");exit(1);} err_right = (unsigned int*) malloc(32*32*32*sizeof(unsigned int)); if(!err_right){printf("Out of memory allocating \n");exit(1);} int q; // Calculate all errors for(enc_color1[0]=0; enc_color1[0]<32; enc_color1[0]++) { color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); if(precompute_3bittable_all_subblocksR_with_test_perceptual1000(block_2x2, color_quant1, precalc_err_UL_R, precalc_err_UR_R, precalc_err_LL_R, precalc_err_LR_R, best_error_so_far)) { for(enc_color1[1]=0; enc_color1[1]<32; enc_color1[1]++) { color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); if(precompute_3bittable_all_subblocksRG_withtest_perceptual1000(block_2x2, color_quant1, precalc_err_UL_R, precalc_err_UR_R, precalc_err_LL_R, precalc_err_LR_R, precalc_err_UL_RG, precalc_err_UR_RG, precalc_err_LL_RG, precalc_err_LR_RG, best_error_so_far)) { for(enc_color1[2]=0; enc_color1[2]<32; enc_color1[2]++) { color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); tryalltables_3bittable_all_subblocks_using_precalc_perceptual1000(block_2x2, color_quant1, precalc_err_UL_RG, precalc_err_UR_RG, precalc_err_LL_RG, precalc_err_LR_RG, err_upper[32*32*enc_color1[0]+32*enc_color1[1]+enc_color1[2]], err_lower[32*32*enc_color1[0]+32*enc_color1[1]+enc_color1[2]], err_left[32*32*enc_color1[0]+32*enc_color1[1]+enc_color1[2]], err_right[32*32*enc_color1[0]+32*enc_color1[1]+enc_color1[2]], best_error_so_far); } } else { for(q=0;q<32;q++) { err_upper[32*32*enc_color1[0]+32*enc_color1[1]+q] = MAXERR1000; err_lower[32*32*enc_color1[0]+32*enc_color1[1]+q] = MAXERR1000; err_left[32*32*enc_color1[0]+32*enc_color1[1]+q] = MAXERR1000; err_right[32*32*enc_color1[0]+32*enc_color1[1]+q] = MAXERR1000; } } } } else { for(q=0;q<32*32;q++) { err_upper[32*32*enc_color1[0]+q] = MAXERR1000; err_lower[32*32*enc_color1[0]+q] = MAXERR1000; err_left[32*32*enc_color1[0]+q] = MAXERR1000; err_right[32*32*enc_color1[0]+q] = MAXERR1000; } } } for(enc_color1[0]=0; enc_color1[0]<32; enc_color1[0]++) { for(enc_color1[1]=0; enc_color1[1]<32; enc_color1[1]++) { for(enc_color1[2]=0; enc_color1[2]<4; enc_color1[2]++) { error_lying = err_upper[32*32*enc_color1[0]+32*enc_color1[1]+enc_color1[2]]; error_standing = err_left[32*32*enc_color1[0]+32*enc_color1[1]+enc_color1[2]]; if(error_lying < best_error_so_far || error_standing < best_error_so_far) { for(enc_color2[0]=JAS_MAX(0,enc_color1[0]-4); enc_color2[0]> 2); color_quant1[1] = best_enc_color1[1] << 3 | (best_enc_color1[1] >> 2); color_quant1[2] = best_enc_color1[2] << 3 | (best_enc_color1[2] >> 2); if(best_flip == 0) tryalltables_3bittable2x4percep1000(img,width,height,startx,starty,color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); else tryalltables_3bittable4x2percep1000(img,width,height,startx,starty,color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); color_quant2[0] = best_enc_color2[0] << 3 | (best_enc_color2[0] >> 2); color_quant2[1] = best_enc_color2[1] << 3 | (best_enc_color2[1] >> 2); color_quant2[2] = best_enc_color2[2] << 3 | (best_enc_color2[2] >> 2); if(best_flip == 0) tryalltables_3bittable2x4percep1000(img,width,height,startx+2,starty,color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); else tryalltables_3bittable4x2percep1000(img,width,height,startx,starty+2,color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); diff[0] = best_enc_color2[0]-best_enc_color1[0]; diff[1] = best_enc_color2[1]-best_enc_color1[1]; diff[2] = best_enc_color2[2]-best_enc_color1[2]; // ETC1_RGB8_OES: // // a) bit layout in bits 63 through 32 if diffbit = 0 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // b) bit layout in bits 63 through 32 if diffbit = 1 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |diff|flip| // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // c) bit layout in bits 31 through 0 (in both cases) // // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 // -------------------------------------------------------------------------------------------------- // | most significant pixel index bits | least significant pixel index bits | // | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | // -------------------------------------------------------------------------------------------------- diffbit = 1; compressed1 = 0; PUTBITSHIGH( compressed1, diffbit, 1, 33); PUTBITSHIGH( compressed1, best_enc_color1[0], 5, 63); PUTBITSHIGH( compressed1, best_enc_color1[1], 5, 55); PUTBITSHIGH( compressed1, best_enc_color1[2], 5, 47); PUTBITSHIGH( compressed1, diff[0], 3, 58); PUTBITSHIGH( compressed1, diff[1], 3, 50); PUTBITSHIGH( compressed1, diff[2], 3, 42); PUTBITSHIGH( compressed1, best_table1, 3, 39); PUTBITSHIGH( compressed1, best_table2, 3, 36); PUTBITSHIGH( compressed1, best_flip, 1, 32); if(best_flip == 0) { compressed2 = 0; PUTBITS( compressed2, (best_pixel_indices1_MSB ), 8, 23); PUTBITS( compressed2, (best_pixel_indices2_MSB ), 8, 31); PUTBITS( compressed2, (best_pixel_indices1_LSB ), 8, 7); PUTBITS( compressed2, (best_pixel_indices2_LSB ), 8, 15); } else { best_pixel_indices1_MSB |= (best_pixel_indices2_MSB << 2); best_pixel_indices1_LSB |= (best_pixel_indices2_LSB << 2); compressed2 = ((best_pixel_indices1_MSB & 0xffff) << 16) | (best_pixel_indices1_LSB & 0xffff); } return best_error_using_diff_mode; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Compresses the differential mode exhaustively. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int compressBlockDifferentialExhaustive(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2, unsigned int previous_best_err) { unsigned int best_err_norm_diff = 255*255*16*3; unsigned int best_err_norm_444 = 255*255*16*3; unsigned int best_err_flip_diff = 255*255*16*3; unsigned int best_err_flip_444 = 255*255*16*3; uint8 color_quant1[3], color_quant2[3]; int enc_color1[3], enc_color2[3], diff[3]; int best_enc_color1[3], best_enc_color2[3]; int min_error=255*255*8*3; unsigned int best_pixel_indices1_MSB=0; unsigned int best_pixel_indices1_LSB=0; unsigned int best_pixel_indices2_MSB=0; unsigned int best_pixel_indices2_LSB=0; unsigned int pixel_indices1_MSB=0; unsigned int pixel_indices1_LSB=0; unsigned int pixel_indices2_MSB=0; unsigned int *err_upper, *err_lower; unsigned int *err_left, *err_right; unsigned int pixel_indices2_LSB=0; unsigned int table1=0, table2=0; unsigned int best_table1=0, best_table2=0; unsigned int precalc_err_UL_R[8*4*4]; unsigned int precalc_err_UR_R[8*4*4]; unsigned int precalc_err_LL_R[8*4*4]; unsigned int precalc_err_LR_R[8*4*4]; unsigned int precalc_err_UL_RG[8*4*4]; unsigned int precalc_err_UR_RG[8*4*4]; unsigned int precalc_err_LL_RG[8*4*4]; unsigned int precalc_err_LR_RG[8*4*4]; int diffbit; uint8 block_2x2[4*4*4]; unsigned int error, error_lying, error_standing, best_err, total_best_err; unsigned int *err_lower_adr; int best_flip; unsigned int *err_right_adr; int xx,yy,count = 0; // Reshuffle pixels so that the top left 2x2 pixels arrive first, then the top right 2x2 pixels etc. Also put use 4 bytes per pixel to make it 32-word aligned. for(xx = 0; xx<2; xx++) { for(yy=0; yy<2; yy++) { block_2x2[(count)*4] = img[((starty+yy)*width+(startx+xx))*3]; block_2x2[(count)*4+1] = img[((starty+yy)*width+(startx+xx))*3+1]; block_2x2[(count)*4+2] = img[((starty+yy)*width+(startx+xx))*3+2]; block_2x2[(count)*4+3] = 0; count++; } } for(xx = 2; xx<4; xx++) { for(yy=0; yy<2; yy++) { block_2x2[(count)*4] = img[((starty+yy)*width+(startx+xx))*3]; block_2x2[(count)*4+1] = img[((starty+yy)*width+(startx+xx))*3+1]; block_2x2[(count)*4+2] = img[((starty+yy)*width+(startx+xx))*3+2]; block_2x2[(count)*4+3] = 0; count++; } } for(xx = 0; xx<2; xx++) { for(yy=2; yy<4; yy++) { block_2x2[(count)*4] = img[((starty+yy)*width+(startx+xx))*3]; block_2x2[(count)*4+1] = img[((starty+yy)*width+(startx+xx))*3+1]; block_2x2[(count)*4+2] = img[((starty+yy)*width+(startx+xx))*3+2]; block_2x2[(count)*4+3] = 0; count++; } } for(xx = 2; xx<4; xx++) { for(yy=2; yy<4; yy++) { block_2x2[(count)*4] = img[((starty+yy)*width+(startx+xx))*3]; block_2x2[(count)*4+1] = img[((starty+yy)*width+(startx+xx))*3+1]; block_2x2[(count)*4+2] = img[((starty+yy)*width+(startx+xx))*3+2]; block_2x2[(count)*4+3] = 0; count++; } } unsigned int test1, test2; best_err = (unsigned int)compressBlockOnlyDiffFlipAverage(img, width, height, startx, starty, test1, test2, best_enc_color1, best_enc_color2, best_flip); if(previous_best_err < best_err) total_best_err = previous_best_err; else total_best_err = best_err; // allocate memory for errors: err_upper = (unsigned int*) malloc(32*32*32*sizeof(unsigned int)); if(!err_upper){printf("Out of memory allocating \n");exit(1);} err_lower = (unsigned int*) malloc(32*32*32*sizeof(unsigned int)); if(!err_lower){printf("Out of memory allocating \n");exit(1);} err_left = (unsigned int*) malloc(32*32*32*sizeof(unsigned int)); if(!err_left){printf("Out of memory allocating \n");exit(1);} err_right = (unsigned int*) malloc(32*32*32*sizeof(unsigned int)); if(!err_right){printf("Out of memory allocating \n");exit(1);} int q; // Calculate all errors for(enc_color1[0]=0; enc_color1[0]<32; enc_color1[0]++) { color_quant1[0] = enc_color1[0] << 3 | (enc_color1[0] >> 2); if(precompute_3bittable_all_subblocksR_with_test(block_2x2, color_quant1, precalc_err_UL_R, precalc_err_UR_R, precalc_err_LL_R, precalc_err_LR_R, total_best_err)) { for(enc_color1[1]=0; enc_color1[1]<32; enc_color1[1]++) { color_quant1[1] = enc_color1[1] << 3 | (enc_color1[1] >> 2); if(precompute_3bittable_all_subblocksRG_withtest(block_2x2, color_quant1, precalc_err_UL_R, precalc_err_UR_R, precalc_err_LL_R, precalc_err_LR_R, precalc_err_UL_RG, precalc_err_UR_RG, precalc_err_LL_RG, precalc_err_LR_RG, total_best_err)) { for(enc_color1[2]=0; enc_color1[2]<32; enc_color1[2]++) { color_quant1[2] = enc_color1[2] << 3 | (enc_color1[2] >> 2); tryalltables_3bittable_all_subblocks_using_precalc(block_2x2, color_quant1, precalc_err_UL_RG, precalc_err_UR_RG, precalc_err_LL_RG, precalc_err_LR_RG, err_upper[32*32*enc_color1[0]+32*enc_color1[1]+enc_color1[2]], err_lower[32*32*enc_color1[0]+32*enc_color1[1]+enc_color1[2]], err_left[32*32*enc_color1[0]+32*enc_color1[1]+enc_color1[2]], err_right[32*32*enc_color1[0]+32*enc_color1[1]+enc_color1[2]], total_best_err); } } else { for(q=0;q<32;q++) { err_upper[32*32*enc_color1[0]+32*enc_color1[1]+q] = 255*255*16*3; err_lower[32*32*enc_color1[0]+32*enc_color1[1]+q] = 255*255*16*3; err_left[32*32*enc_color1[0]+32*enc_color1[1]+q] = 255*255*16*3; err_right[32*32*enc_color1[0]+32*enc_color1[1]+q] = 255*255*16*3; } } } } else { for(q=0;q<32*32;q++) { err_upper[32*32*enc_color1[0]+q] = 255*255*16*3; err_lower[32*32*enc_color1[0]+q] = 255*255*16*3; err_left[32*32*enc_color1[0]+q] = 255*255*16*3; err_right[32*32*enc_color1[0]+q] = 255*255*16*3; } } } for(enc_color1[0]=0; enc_color1[0]<32; enc_color1[0]++) { for(enc_color1[1]=0; enc_color1[1]<32; enc_color1[1]++) { for(enc_color1[2]=0; enc_color1[2]<4; enc_color1[2]++) { error_lying = err_upper[32*32*enc_color1[0]+32*enc_color1[1]+enc_color1[2]]; error_standing = err_left[32*32*enc_color1[0]+32*enc_color1[1]+enc_color1[2]]; if(error_lying < total_best_err || error_standing < total_best_err) { for(enc_color2[0]=JAS_MAX(0,enc_color1[0]-4); enc_color2[0]> 2); color_quant1[1] = best_enc_color1[1] << 3 | (best_enc_color1[1] >> 2); color_quant1[2] = best_enc_color1[2] << 3 | (best_enc_color1[2] >> 2); if(best_flip == 0) tryalltables_3bittable2x4(img,width,height,startx,starty,color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); else tryalltables_3bittable4x2(img,width,height,startx,starty,color_quant1,best_table1,best_pixel_indices1_MSB, best_pixel_indices1_LSB); color_quant2[0] = best_enc_color2[0] << 3 | (best_enc_color2[0] >> 2); color_quant2[1] = best_enc_color2[1] << 3 | (best_enc_color2[1] >> 2); color_quant2[2] = best_enc_color2[2] << 3 | (best_enc_color2[2] >> 2); if(best_flip == 0) tryalltables_3bittable2x4(img,width,height,startx+2,starty,color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); else tryalltables_3bittable4x2(img,width,height,startx,starty+2,color_quant2,best_table2,best_pixel_indices2_MSB, best_pixel_indices2_LSB); diff[0] = best_enc_color2[0]-best_enc_color1[0]; diff[1] = best_enc_color2[1]-best_enc_color1[1]; diff[2] = best_enc_color2[2]-best_enc_color1[2]; // ETC1_RGB8_OES: // // a) bit layout in bits 63 through 32 if diffbit = 0 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | base col2 | base col1 | base col2 | base col1 | base col2 | table | table |diff|flip| // | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)| B1 (4bits)| B2 (4bits)| cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // b) bit layout in bits 63 through 32 if diffbit = 1 // // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 // --------------------------------------------------------------------------------------------------- // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |diff|flip| // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | // --------------------------------------------------------------------------------------------------- // // c) bit layout in bits 31 through 0 (in both cases) // // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 // -------------------------------------------------------------------------------------------------- // | most significant pixel index bits | least significant pixel index bits | // | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a| p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | // -------------------------------------------------------------------------------------------------- diffbit = 1; compressed1 = 0; PUTBITSHIGH( compressed1, diffbit, 1, 33); PUTBITSHIGH( compressed1, best_enc_color1[0], 5, 63); PUTBITSHIGH( compressed1, best_enc_color1[1], 5, 55); PUTBITSHIGH( compressed1, best_enc_color1[2], 5, 47); PUTBITSHIGH( compressed1, diff[0], 3, 58); PUTBITSHIGH( compressed1, diff[1], 3, 50); PUTBITSHIGH( compressed1, diff[2], 3, 42); PUTBITSHIGH( compressed1, best_table1, 3, 39); PUTBITSHIGH( compressed1, best_table2, 3, 36); PUTBITSHIGH( compressed1, best_flip, 1, 32); if(best_flip == 0) { compressed2 = 0; PUTBITS( compressed2, (best_pixel_indices1_MSB ), 8, 23); PUTBITS( compressed2, (best_pixel_indices2_MSB ), 8, 31); PUTBITS( compressed2, (best_pixel_indices1_LSB ), 8, 7); PUTBITS( compressed2, (best_pixel_indices2_LSB ), 8, 15); } else { best_pixel_indices1_MSB |= (best_pixel_indices2_MSB << 2); best_pixel_indices1_LSB |= (best_pixel_indices2_LSB << 2); compressed2 = ((best_pixel_indices1_MSB & 0xffff) << 16) | (best_pixel_indices1_LSB & 0xffff); } return best_err; } #endif #if EXHAUSTIVE_CODE_ACTIVE // This function uses real exhaustive search for the planar mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressBlockPlanar57ExhaustivePerceptual(uint8 *img, int width,int height,int startx,int starty, unsigned int &compressed57_1, unsigned int &compressed57_2, unsigned int best_error_sofar, unsigned int best_error_planar_red, unsigned int best_error_planar_green, unsigned int best_error_planar_blue) { int colorO_enc[3], colorH_enc[3], colorV_enc[3]; int best_colorO_enc[3], best_colorH_enc[3], best_colorV_enc[3]; unsigned int error; unsigned int best_error; unsigned int lowest_possible_error; unsigned int best_error_red_sofar; unsigned int best_error_green_sofar; unsigned int best_error_blue_sofar; unsigned int BBBtable[128*128]; unsigned int CCCtable[128*128]; uint8 block[4*4*4]; // Use 4 bytes per pixel to make it 32-word aligned. int count = 0; int xx, yy; for(yy=0; yy<4; yy++) { for(xx = 0; xx<4; xx++) { block[(count)*4] = img[((starty+yy)*width+(startx+xx))*3]; block[(count)*4+1] = img[((starty+yy)*width+(startx+xx))*3+1]; block[(count)*4+2] = img[((starty+yy)*width+(startx+xx))*3+2]; block[(count)*4+3] = 0; count++; } } // The task is to calculate the sum of the error over the entire area of the block. // // The block can be partitioned into: O A A A // B D D C // B D C D // B C D D // where the error in // O only depends on colorO // A only depends on colorO and colorH // B only depends on colorO and colorV // C only depends on colorH and colorV // D depends on all three (colorO, colorH and colorV) // // Note that B can be precalculated for all combinations of colorO and colorV // and the precalculated values can be used instead of calculating it in the inner loop. // The same applies to C. // // In the code below, the squared error over O A A A is calculated and stored in lowest_possible_error // Precalc BBB errors for(colorO_enc[0] = 0; colorO_enc[0]<64; colorO_enc[0]++) { for(colorV_enc[0] = 0; colorV_enc[0]<64; colorV_enc[0]++) { BBBtable[colorO_enc[0]*64+colorV_enc[0]] = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*calcBBBred(block, colorO_enc[0], colorV_enc[0]); } } // Precalc CCC errors for(colorH_enc[0] = 0; colorH_enc[0]<64; colorH_enc[0]++) { for(colorV_enc[0] = 0; colorV_enc[0]<64; colorV_enc[0]++) { CCCtable[colorH_enc[0]*64+colorV_enc[0]] = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*calcCCCred(block, colorH_enc[0], colorV_enc[0]); } } best_error = MAXERR1000; best_error_red_sofar = JAS_MIN(best_error_planar_red, best_error_sofar); for(colorO_enc[0] = 0; colorO_enc[0]<64; colorO_enc[0]++) { for(colorH_enc[0] = 0; colorH_enc[0]<64; colorH_enc[0]++) { lowest_possible_error = calcLowestPossibleRedOHperceptual(block, colorO_enc[0], colorH_enc[0], best_error_red_sofar); if(lowest_possible_error <= best_error_red_sofar) { for(colorV_enc[0] = 0; colorV_enc[0]<64; colorV_enc[0]++) { error = calcErrorPlanarOnlyRedPerceptual(block, colorO_enc[0], colorH_enc[0], colorV_enc[0], lowest_possible_error, BBBtable[colorO_enc[0]*64+colorV_enc[0]], CCCtable[colorH_enc[0]*64+colorV_enc[0]], best_error_red_sofar); if(error < best_error) { best_error = error; best_colorO_enc[0] = colorO_enc[0]; best_colorH_enc[0] = colorH_enc[0]; best_colorV_enc[0] = colorV_enc[0]; } } } } } if(best_error < best_error_planar_red) best_error_planar_red = best_error; if(best_error_planar_red > best_error_sofar) { // The red component in itself is already bigger than the previously best value ---- we can give up. // use the dummy color black for all colors and report that the errors for the different color components are infinite best_error_planar_green = MAXERR1000; best_error_planar_blue = MAXERR1000; compressed57_1 = 0; compressed57_2 = 0; return; } // The task is to calculate the sum of the error over the entire area of the block. // // The block can be partitioned into: O A A A // B D D C // B D C D // B C D D // where the error in // O only depends on colorO // A only depends on colorO and colorH // B only depends on colorO and colorV // C only depends on colorH and colorV // D depends on all three (colorO, colorH and colorV) // // Note that B can be precalculated for all combinations of colorO and colorV // and the precalculated values can be used instead of calculating it in the inner loop. // The same applies to C. // // In the code below, the squared error over O A A A is calculated and store in lowest_possible_error // Precalc BBB errors for(colorO_enc[1] = 0; colorO_enc[1]<128; colorO_enc[1]++) { for(colorV_enc[1] = 0; colorV_enc[1]<128; colorV_enc[1]++) { BBBtable[colorO_enc[1]*128+colorV_enc[1]] = PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000*calcBBBgreen(block, colorO_enc[1], colorV_enc[1]); } } // Precalc CCC errors for(colorH_enc[1] = 0; colorH_enc[1]<128; colorH_enc[1]++) { for(colorV_enc[1] = 0; colorV_enc[1]<128; colorV_enc[1]++) { CCCtable[colorH_enc[1]*128+colorV_enc[1]] = PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000*calcCCCgreen(block, colorH_enc[1], colorV_enc[1]); } } best_error = MAXERR1000; best_error_green_sofar = JAS_MIN(best_error_planar_green, best_error_sofar); for(colorO_enc[1] = 0; colorO_enc[1]<128; colorO_enc[1]++) { for(colorH_enc[1] = 0; colorH_enc[1]<128; colorH_enc[1]++) { lowest_possible_error = calcLowestPossibleGreenOHperceptual(block, colorO_enc[1], colorH_enc[1], best_error_green_sofar); if(lowest_possible_error <= best_error_green_sofar) { for(colorV_enc[1] = 0; colorV_enc[1]<128; colorV_enc[1]++) { error = calcErrorPlanarOnlyGreenPerceptual(block, colorO_enc[1], colorH_enc[1], colorV_enc[1], lowest_possible_error, BBBtable[colorO_enc[1]*128+colorV_enc[1]], CCCtable[colorH_enc[1]*128+colorV_enc[1]], best_error_green_sofar); if(error < best_error) { best_error = error; best_colorO_enc[1] = colorO_enc[1]; best_colorH_enc[1] = colorH_enc[1]; best_colorV_enc[1] = colorV_enc[1]; } } } } } if(best_error < best_error_planar_green) best_error_planar_green = best_error; if(best_error_planar_red + best_error_planar_green > best_error_sofar) { // The red component in itself is already bigger than the previously best value ---- we can give up. // use the dummy color black for all colors and report that the errors for the different color components are infinite best_error_planar_blue = MAXERR1000; compressed57_1 = 0; compressed57_2 = 0; return; } // The task is to calculate the sum of the error over the entire area of the block. // // The block can be partitioned into: O A A A // B D D C // B D C D // B C D D // where the error in // O only depends on colorO // A only depends on colorO and colorH // B only depends on colorO and colorV // C only depends on colorH and colorV // D depends on all three (colorO, colorH and colorV) // // Note that B can be precalculated for all combinations of colorO and colorV // and the precalculated values can be used instead of calculating it in the inner loop. // The same applies to C. // // In the code below, the squared error over O A A A is calculated and store in lowest_possible_error // Precalc BBB errors for(colorO_enc[2] = 0; colorO_enc[2]<64; colorO_enc[2]++) { for(colorV_enc[2] = 0; colorV_enc[2]<64; colorV_enc[2]++) { BBBtable[colorO_enc[2]*64+colorV_enc[2]] = calcBBBbluePerceptual(block, colorO_enc[2], colorV_enc[2]); } } // Precalc CCC errors for(colorH_enc[2] = 0; colorH_enc[2]<64; colorH_enc[2]++) { for(colorV_enc[2] = 0; colorV_enc[2]<64; colorV_enc[2]++) { CCCtable[colorH_enc[2]*64+colorV_enc[2]] = calcCCCbluePerceptual(block, colorH_enc[2], colorV_enc[2]); } } best_error = MAXERR1000; best_error_blue_sofar = JAS_MIN(best_error_planar_blue, best_error_sofar); for(colorO_enc[2] = 0; colorO_enc[2]<64; colorO_enc[2]++) { for(colorH_enc[2] = 0; colorH_enc[2]<64; colorH_enc[2]++) { lowest_possible_error = calcLowestPossibleBlueOHperceptual(block, colorO_enc[2], colorH_enc[2], best_error_blue_sofar); if(lowest_possible_error <= best_error_blue_sofar) { for(colorV_enc[2] = 0; colorV_enc[2]<64; colorV_enc[2]++) { error = calcErrorPlanarOnlyBluePerceptual(block, colorO_enc[2], colorH_enc[2], colorV_enc[2], lowest_possible_error, BBBtable[colorO_enc[2]*64+colorV_enc[2]], CCCtable[colorH_enc[2]*64+colorV_enc[2]], best_error_blue_sofar); if(error < best_error) { best_error = error; best_colorO_enc[2] = colorO_enc[2]; best_colorH_enc[2] = colorH_enc[2]; best_colorV_enc[2] = colorV_enc[2]; } } } } } if(best_error < best_error_planar_blue) best_error_planar_blue = best_error; compressed57_1 = 0; compressed57_2 = 0; PUTBITSHIGH( compressed57_1, best_colorO_enc[0], 6, 63); PUTBITSHIGH( compressed57_1, best_colorO_enc[1], 7, 57); PUTBITSHIGH( compressed57_1, best_colorO_enc[2], 6, 50); PUTBITSHIGH( compressed57_1, best_colorH_enc[0], 6, 44); PUTBITSHIGH( compressed57_1, best_colorH_enc[1], 7, 38); PUTBITS( compressed57_2, best_colorH_enc[2], 6, 31); PUTBITS( compressed57_2, best_colorV_enc[0], 6, 25); PUTBITS( compressed57_2, best_colorV_enc[1], 7, 19); PUTBITS( compressed57_2, best_colorV_enc[2], 6, 12); } #endif #if EXHAUSTIVE_CODE_ACTIVE // This function uses real exhaustive search for the planar mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressBlockPlanar57Exhaustive(uint8 *img, int width,int height,int startx,int starty, unsigned int &compressed57_1, unsigned int &compressed57_2, unsigned int best_error_sofar, unsigned int best_error_red, unsigned int best_error_green, unsigned int best_error_blue) { int colorO_enc[3], colorH_enc[3], colorV_enc[3]; int best_colorO_enc[3], best_colorH_enc[3], best_colorV_enc[3]; unsigned int error; unsigned int best_error; unsigned int lowest_possible_error; unsigned int best_error_red_sofar; unsigned int best_error_green_sofar; unsigned int best_error_blue_sofar; unsigned int BBBtable[128*128]; unsigned int CCCtable[128*128]; uint8 block[4*4*4]; // Use 4 bytes per pixel to make it 32-word aligned. int count = 0; int xx, yy; for(yy=0; yy<4; yy++) { for(xx = 0; xx<4; xx++) { block[(count)*4] = img[((starty+yy)*width+(startx+xx))*3]; block[(count)*4+1] = img[((starty+yy)*width+(startx+xx))*3+1]; block[(count)*4+2] = img[((starty+yy)*width+(startx+xx))*3+2]; block[(count)*4+3] = 0; count++; } } // The task is to calculate the sum of the error over the entire area of the block. // // The block can be partitioned into: O A A A // B D D C // B D C D // B C D D // where the error in // O only depends on colorO // A only depends on colorO and colorH // B only depends on colorO and colorV // C only depends on colorH and colorV // D depends on all three (colorO, colorH and colorV) // // Note that B can be precalculated for all combinations of colorO and colorV // and the precalculated values can be used instead of calculating it in the inner loop. // The same applies to C. // // In the code below, the squared error over O A A A is calculated and store in lowest_possible_error // Precalc BBB errors for(colorO_enc[0] = 0; colorO_enc[0]<64; colorO_enc[0]++) { for(colorV_enc[0] = 0; colorV_enc[0]<64; colorV_enc[0]++) { BBBtable[colorO_enc[0]*64+colorV_enc[0]] = calcBBBred(block, colorO_enc[0], colorV_enc[0]); } } // Precalc CCC errors for(colorH_enc[0] = 0; colorH_enc[0]<64; colorH_enc[0]++) { for(colorV_enc[0] = 0; colorV_enc[0]<64; colorV_enc[0]++) { CCCtable[colorH_enc[0]*64+colorV_enc[0]] = calcCCCred(block, colorH_enc[0], colorV_enc[0]); } } best_error = MAXERR1000; best_error_red_sofar = JAS_MIN(best_error_red, best_error_sofar); for(colorO_enc[0] = 0; colorO_enc[0]<64; colorO_enc[0]++) { for(colorH_enc[0] = 0; colorH_enc[0]<64; colorH_enc[0]++) { lowest_possible_error = calcLowestPossibleRedOH(block, colorO_enc[0], colorH_enc[0], best_error_red_sofar); if(lowest_possible_error <= best_error_red_sofar) { for(colorV_enc[0] = 0; colorV_enc[0]<64; colorV_enc[0]++) { error = calcErrorPlanarOnlyRed(block, colorO_enc[0], colorH_enc[0], colorV_enc[0], lowest_possible_error, BBBtable[colorO_enc[0]*64+colorV_enc[0]], CCCtable[colorH_enc[0]*64+colorV_enc[0]], best_error_red_sofar); if(error < best_error) { best_error = error; best_colorO_enc[0] = colorO_enc[0]; best_colorH_enc[0] = colorH_enc[0]; best_colorV_enc[0] = colorV_enc[0]; } } } } } // The task is to calculate the sum of the error over the entire area of the block. // // The block can be partitioned into: O A A A // B D D C // B D C D // B C D D // where the error in // O only depends on colorO // A only depends on colorO and colorH // B only depends on colorO and colorV // C only depends on colorH and colorV // D depends on all three (colorO, colorH and colorV) // // Note that B can be precalculated for all combinations of colorO and colorV // and the precalculated values can be used instead of calculating it in the inner loop. // The same applies to C. // // In the code below, the squared error over O A A A is calculated and store in lowest_possible_error // Precalc BBB errors for(colorO_enc[1] = 0; colorO_enc[1]<128; colorO_enc[1]++) { for(colorV_enc[1] = 0; colorV_enc[1]<128; colorV_enc[1]++) { BBBtable[colorO_enc[1]*128+colorV_enc[1]] = calcBBBgreen(block, colorO_enc[1], colorV_enc[1]); } } // Precalc CCC errors for(colorH_enc[1] = 0; colorH_enc[1]<128; colorH_enc[1]++) { for(colorV_enc[1] = 0; colorV_enc[1]<128; colorV_enc[1]++) { CCCtable[colorH_enc[1]*128+colorV_enc[1]] = calcCCCgreen(block, colorH_enc[1], colorV_enc[1]); } } best_error = MAXERR1000; best_error_green_sofar = JAS_MIN(best_error_green, best_error_sofar); for(colorO_enc[1] = 0; colorO_enc[1]<128; colorO_enc[1]++) { for(colorH_enc[1] = 0; colorH_enc[1]<128; colorH_enc[1]++) { lowest_possible_error = calcLowestPossibleGreenOH(block, colorO_enc[1], colorH_enc[1], best_error_green_sofar); if(lowest_possible_error <= best_error_green_sofar) { for(colorV_enc[1] = 0; colorV_enc[1]<128; colorV_enc[1]++) { error = calcErrorPlanarOnlyGreen(block, colorO_enc[1], colorH_enc[1], colorV_enc[1], lowest_possible_error, BBBtable[colorO_enc[1]*128+colorV_enc[1]], CCCtable[colorH_enc[1]*128+colorV_enc[1]], best_error_green_sofar); if(error < best_error) { best_error = error; best_colorO_enc[1] = colorO_enc[1]; best_colorH_enc[1] = colorH_enc[1]; best_colorV_enc[1] = colorV_enc[1]; } } } } } // The task is to calculate the sum of the error over the entire area of the block. // // The block can be partitioned into: O A A A // B D D C // B D C D // B C D D // where the error in // O only depends on colorO // A only depends on colorO and colorH // B only depends on colorO and colorV // C only depends on colorH and colorV // D depends on all three (colorO, colorH and colorV) // // Note that B can be precalculated for all combinations of colorO and colorV // and the precalculated values can be used instead of calculating it in the inner loop. // The same applies to C. // // In the code below, the squared error over O A A A is calculated and store in lowest_possible_error // Precalc BBB errors for(colorO_enc[2] = 0; colorO_enc[2]<64; colorO_enc[2]++) { for(colorV_enc[2] = 0; colorV_enc[2]<64; colorV_enc[2]++) { BBBtable[colorO_enc[2]*64+colorV_enc[2]] = calcBBBblue(block, colorO_enc[2], colorV_enc[2]); } } // Precalc CCC errors for(colorH_enc[2] = 0; colorH_enc[2]<64; colorH_enc[2]++) { for(colorV_enc[2] = 0; colorV_enc[2]<64; colorV_enc[2]++) { CCCtable[colorH_enc[2]*64+colorV_enc[2]] = calcCCCblue(block, colorH_enc[2], colorV_enc[2]); } } best_error = MAXERR1000; best_error_blue_sofar = JAS_MIN(best_error_blue, best_error_sofar); for(colorO_enc[2] = 0; colorO_enc[2]<64; colorO_enc[2]++) { for(colorH_enc[2] = 0; colorH_enc[2]<64; colorH_enc[2]++) { lowest_possible_error = calcLowestPossibleBlueOH(block, colorO_enc[2], colorH_enc[2], best_error_blue_sofar); if(lowest_possible_error <= best_error_blue_sofar) { for(colorV_enc[2] = 0; colorV_enc[2]<64; colorV_enc[2]++) { error = calcErrorPlanarOnlyBlue(block, colorO_enc[2], colorH_enc[2], colorV_enc[2], lowest_possible_error, BBBtable[colorO_enc[2]*64+colorV_enc[2]], CCCtable[colorH_enc[2]*64+colorV_enc[2]], best_error_blue_sofar); if(error < best_error) { best_error = error; best_colorO_enc[2] = colorO_enc[2]; best_colorH_enc[2] = colorH_enc[2]; best_colorV_enc[2] = colorV_enc[2]; } } } } } compressed57_1 = 0; compressed57_2 = 0; PUTBITSHIGH( compressed57_1, best_colorO_enc[0], 6, 63); PUTBITSHIGH( compressed57_1, best_colorO_enc[1], 7, 57); PUTBITSHIGH( compressed57_1, best_colorO_enc[2], 6, 50); PUTBITSHIGH( compressed57_1, best_colorH_enc[0], 6, 44); PUTBITSHIGH( compressed57_1, best_colorH_enc[1], 7, 38); PUTBITS( compressed57_2, best_colorH_enc[2], 6, 31); PUTBITS( compressed57_2, best_colorV_enc[0], 6, 25); PUTBITS( compressed57_2, best_colorV_enc[1], 7, 19); PUTBITS( compressed57_2, best_colorV_enc[2], 6, 12); } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates a table used in exhaustive compression of the T-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcError59T_col0_Rpercep1000(uint8* block, int colorRGB444_packed, unsigned int *precalc_err_col0_R) { unsigned int block_error = 0, best_block_error = MAXERR1000, pixel_error, best_pixel_error; int diff; uint8 color; uint8 possible_colors[3]; color = ((colorRGB444_packed >> 8) & 0xf)*17; // Test all distances for (uint8 d = 0; d < 8; d++) { possible_colors[0] = CLAMP(0,color - table59T[d],255); possible_colors[1] = CLAMP(0,color,255); possible_colors[2] = CLAMP(0,color + table59T[d],255); // Loop block for (int x = 0; x < 16; x++) { best_pixel_error = MAXERR1000; // Loop possible block colors for (uint8 c = 0; c < 3; c++) { diff = block[4*x + R] - CLAMP(0,possible_colors[c],255); pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*SQUARE(diff); // Choose best error if (pixel_error < best_pixel_error) best_pixel_error = pixel_error; } precalc_err_col0_R[((colorRGB444_packed>>8)*8 + d)*16 + x] = (unsigned int) best_pixel_error; } } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates a table used in exhaustive compression of the T-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcError59T_col0_R(uint8* block, int colorRGB444_packed, unsigned int *precalc_err_col0_R) { unsigned int block_error = 0, best_block_error = MAXIMUM_ERROR, pixel_error, best_pixel_error; int diff; uint8 color; uint8 possible_colors[3]; color = ((colorRGB444_packed >> 8) & 0xf)*17; // Test all distances for (uint8 d = 0; d < 8; d++) { possible_colors[0] = CLAMP(0,color - table59T[d],255); possible_colors[1] = CLAMP(0,color,255); possible_colors[2] = CLAMP(0,color + table59T[d],255); // Loop block for (int x = 0; x < 16; x++) { best_pixel_error = MAXIMUM_ERROR; // Loop possible block colors for (uint8 c = 0; c < 3; c++) { diff = block[4*x + R] - CLAMP(0,possible_colors[c],255); pixel_error = SQUARE(diff); // Choose best error if (pixel_error < best_pixel_error) best_pixel_error = pixel_error; } precalc_err_col0_R[((colorRGB444_packed>>8)*8 + d)*16 + x] = (unsigned int) best_pixel_error; } } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates a table used in exhaustive compression of the T-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcError59T_col0_RGpercep1000(uint8* block, int colorRGB444_packed, unsigned int *precalc_err_col0_RG) { unsigned int block_error = 0, best_block_error = MAXERR1000, pixel_error, best_pixel_error; int diff[3]; uint8 color[3]; uint8 possible_colors[3][2]; color[R] = ((colorRGB444_packed >> 8) & 0xf)*17; color[G] = ((colorRGB444_packed >> 4) & 0xf)*17; // Test all distances for (uint8 d = 0; d < 8; d++) { possible_colors[0][R] = CLAMP(0,color[R] - table59T[d],255); possible_colors[0][G] = CLAMP(0,color[G] - table59T[d],255); possible_colors[1][R] = CLAMP(0,color[R],255); possible_colors[1][G] = CLAMP(0,color[G],255); possible_colors[2][R] = CLAMP(0,color[R] + table59T[d],255); possible_colors[2][G] = CLAMP(0,color[G] + table59T[d],255); // Loop block for (int x = 0; x < 16; x++) { best_pixel_error = MAXERR1000; // Loop possible block colors for (uint8 c = 0; c < 3; c++) { diff[R] = block[4*x + R] - CLAMP(0,possible_colors[c][R],255); diff[G] = block[4*x + G] - CLAMP(0,possible_colors[c][G],255); pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*SQUARE(diff[R]) + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000*SQUARE(diff[G]); // Choose best error if (pixel_error < best_pixel_error) best_pixel_error = pixel_error; } precalc_err_col0_RG[((colorRGB444_packed>>4)*8 + d)*16 + x] = (unsigned int) best_pixel_error; } } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates a table used in exhaustive compression of the T-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcError59T_col0_RG(uint8* block, int colorRGB444_packed, unsigned int *precalc_err_col0_RG) { unsigned int block_error = 0, best_block_error = MAXIMUM_ERROR, pixel_error, best_pixel_error; int diff[3]; uint8 color[3]; uint8 possible_colors[3][2]; color[R] = ((colorRGB444_packed >> 8) & 0xf)*17; color[G] = ((colorRGB444_packed >> 4) & 0xf)*17; // Test all distances for (uint8 d = 0; d < 8; d++) { possible_colors[0][R] = CLAMP(0,color[R] - table59T[d],255); possible_colors[0][G] = CLAMP(0,color[G] - table59T[d],255); possible_colors[1][R] = CLAMP(0,color[R],255); possible_colors[1][G] = CLAMP(0,color[G],255); possible_colors[2][R] = CLAMP(0,color[R] + table59T[d],255); possible_colors[2][G] = CLAMP(0,color[G] + table59T[d],255); // Loop block for (int x = 0; x < 16; x++) { best_pixel_error = MAXIMUM_ERROR; // Loop possible block colors for (uint8 c = 0; c < 3; c++) { diff[R] = block[4*x + R] - CLAMP(0,possible_colors[c][R],255); diff[G] = block[4*x + G] - CLAMP(0,possible_colors[c][G],255); pixel_error = SQUARE(diff[R]) + SQUARE(diff[G]); // Choose best error if (pixel_error < best_pixel_error) best_pixel_error = pixel_error; } precalc_err_col0_RG[((colorRGB444_packed>>4)*8 + d)*16 + x] = (unsigned int) best_pixel_error; } } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates a table used in exhaustive compression of the T-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcError59T_col1_Rpercep1000(uint8* block, int colorRGB444_packed, unsigned int *precalc_err_col1_R) { unsigned int pixel_error; int diff; uint8 color; color = ((colorRGB444_packed >> 8) & 0xf)*17; // Loop block for (int x = 0; x < 16; x++) { diff = block[4*x + R] - color; pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*SQUARE(diff); precalc_err_col1_R[((colorRGB444_packed>>8))*16 + x] = (unsigned int) pixel_error; } } #endif #if EXHAUSTIVE_CODE_ACTIVE /** * Calculate the error for the block at position (startx,starty) * The parameters needed for reconstruction is calculated as well * * In the 59T bit mode, we only have pattern T. */ void precalcError59T_col1_R(uint8* block, int colorRGB444_packed, unsigned int *precalc_err_col1_R) { unsigned int pixel_error; int diff; uint8 color; color = ((colorRGB444_packed >> 8) & 0xf)*17; // Loop block for (int x = 0; x < 16; x++) { diff = block[4*x + R] - color; pixel_error = SQUARE(diff); precalc_err_col1_R[((colorRGB444_packed>>8))*16 + x] = (unsigned int) pixel_error; } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates a table used in exhaustive compression of the T-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcError59T_col1_RGpercep1000(uint8* block, int colorRGB444_packed, unsigned int *precalc_err_col1_RG) { unsigned int pixel_error; int diff[3]; uint8 color[2]; color[R] = ((colorRGB444_packed >> 8) & 0xf)*17; color[G] = ((colorRGB444_packed >> 4) & 0xf)*17; // Loop block for (int x = 0; x < 16; x++) { diff[R] = block[4*x + R] - color[R]; diff[G] = block[4*x + G] - color[G]; pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*SQUARE(diff[R]) + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000*SQUARE(diff[G]); precalc_err_col1_RG[((colorRGB444_packed>>4))*16 + x] = (unsigned int) pixel_error; } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates a table used in exhaustive compression of the T-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcError59T_col1_RG(uint8* block, int colorRGB444_packed, unsigned int *precalc_err_col1_RG) { unsigned int pixel_error; int diff[3]; uint8 color[2]; color[R] = ((colorRGB444_packed >> 8) & 0xf)*17; color[G] = ((colorRGB444_packed >> 4) & 0xf)*17; // Loop block for (int x = 0; x < 16; x++) { diff[R] = block[4*x + R] - color[R]; diff[G] = block[4*x + G] - color[G]; pixel_error = SQUARE(diff[R]) + SQUARE(diff[G]); precalc_err_col1_RG[((colorRGB444_packed>>4))*16 + x] = (unsigned int) pixel_error; } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates a table used in exhaustive compression of the T-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcError59T_col0_RGBpercep1000(uint8* block, int colorRGB444_packed, unsigned int *precalc_err_col0_RGB) { unsigned int block_error = 0, best_block_error = MAXERR1000, pixel_error, best_pixel_error; uint8 color[3]; int possible_colors[3][3]; unsigned int *precalc_err_col0_RGB_adr; #define ONEPOINT59RGB_PERCEP(xval) \ /* Loop possible block colors */\ /* unroll loop for (uint8 c = 0; c < 3; c++) */\ {\ best_pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*square_table[block[4*xval + R] - possible_colors[0][R]]\ + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000*square_table[block[4*xval + G] - possible_colors[0][G]] \ + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[block[4*xval + B] - possible_colors[0][B]];\ pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*square_table[block[4*xval + R] - possible_colors[1][R]]\ + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000*square_table[block[4*xval + G] - possible_colors[1][G]]\ + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[block[4*xval + B] - possible_colors[1][B]];\ if (pixel_error < best_pixel_error)\ best_pixel_error = pixel_error;\ pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*square_table[block[4*xval + R] - possible_colors[2][R]]\ + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000*square_table[block[4*xval + G] - possible_colors[2][G]]\ + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[block[4*xval + B] - possible_colors[2][B]];\ if (pixel_error < best_pixel_error)\ best_pixel_error = pixel_error;\ }\ precalc_err_col0_RGB_adr[xval] = (unsigned int) best_pixel_error;\ #define ONETABLE59RGB_PERCEP(dval) \ possible_colors[0][R] = clamp_table[color[R] - table59T[dval]+255]-255;\ possible_colors[0][G] = clamp_table[color[G] - table59T[dval]+255]-255;\ possible_colors[0][B] = clamp_table[color[B] - table59T[dval]+255]-255;\ possible_colors[1][R] = color[R]-255;\ possible_colors[1][G] = color[G]-255;\ possible_colors[1][B] = color[B]-255;\ possible_colors[2][R] = clamp_table[color[R] + table59T[dval]+255]-255;\ possible_colors[2][G] = clamp_table[color[G] + table59T[dval]+255]-255;\ possible_colors[2][B] = clamp_table[color[B] + table59T[dval]+255]-255;\ precalc_err_col0_RGB_adr = &precalc_err_col0_RGB[(colorRGB444_packed*8 + dval)*16];\ /* Loop block */\ /* unroll loop for (int x = 0; x < 16; x++) */\ {\ ONEPOINT59RGB_PERCEP(0)\ ONEPOINT59RGB_PERCEP(1)\ ONEPOINT59RGB_PERCEP(2)\ ONEPOINT59RGB_PERCEP(3)\ ONEPOINT59RGB_PERCEP(4)\ ONEPOINT59RGB_PERCEP(5)\ ONEPOINT59RGB_PERCEP(6)\ ONEPOINT59RGB_PERCEP(7)\ ONEPOINT59RGB_PERCEP(8)\ ONEPOINT59RGB_PERCEP(9)\ ONEPOINT59RGB_PERCEP(10)\ ONEPOINT59RGB_PERCEP(11)\ ONEPOINT59RGB_PERCEP(12)\ ONEPOINT59RGB_PERCEP(13)\ ONEPOINT59RGB_PERCEP(14)\ ONEPOINT59RGB_PERCEP(15)\ }\ color[R] = (((colorRGB444_packed >> 8) ) << 4) | ((colorRGB444_packed >> 8) ) ; color[G] = (((colorRGB444_packed >> 4) & 0xf) << 4) | ((colorRGB444_packed >> 4) & 0xf) ; color[B] = (((colorRGB444_packed) & 0xf) << 4) | ((colorRGB444_packed) & 0xf) ; /* Test all distances */ /* unroll loop for (uint8 d = 0; d < 8; ++d) */ { ONETABLE59RGB_PERCEP(0) ONETABLE59RGB_PERCEP(1) ONETABLE59RGB_PERCEP(2) ONETABLE59RGB_PERCEP(3) ONETABLE59RGB_PERCEP(4) ONETABLE59RGB_PERCEP(5) ONETABLE59RGB_PERCEP(6) ONETABLE59RGB_PERCEP(7) } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates a table used in exhaustive compression of the T-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcError59T_col0_RGB(uint8* block, int colorRGB444_packed, unsigned int *precalc_err_col0_RGB) { unsigned int block_error = 0, best_block_error = MAXIMUM_ERROR, pixel_error, best_pixel_error; uint8 color[3]; int possible_colors[3][3]; unsigned int *precalc_err_col0_RGB_adr; #define ONEPOINT59RGB(xval) \ /* Loop possible block colors */\ /* unroll loop for (uint8 c = 0; c < 3; c++) */\ {\ best_pixel_error = square_table[block[4*xval + R] - possible_colors[0][R]]\ + square_table[block[4*xval + G] - possible_colors[0][G]] \ + square_table[block[4*xval + B] - possible_colors[0][B]];\ pixel_error = square_table[block[4*xval + R] - possible_colors[1][R]]\ + square_table[block[4*xval + G] - possible_colors[1][G]]\ + square_table[block[4*xval + B] - possible_colors[1][B]];\ if (pixel_error < best_pixel_error)\ best_pixel_error = pixel_error;\ pixel_error = square_table[block[4*xval + R] - possible_colors[2][R]]\ + square_table[block[4*xval + G] - possible_colors[2][G]]\ + square_table[block[4*xval + B] - possible_colors[2][B]];\ if (pixel_error < best_pixel_error)\ best_pixel_error = pixel_error;\ }\ precalc_err_col0_RGB_adr[xval] = (unsigned int) best_pixel_error;\ #define ONETABLE59RGB(dval) \ possible_colors[0][R] = clamp_table[color[R] - table59T[dval]+255]-255;\ possible_colors[0][G] = clamp_table[color[G] - table59T[dval]+255]-255;\ possible_colors[0][B] = clamp_table[color[B] - table59T[dval]+255]-255;\ possible_colors[1][R] = color[R]-255;\ possible_colors[1][G] = color[G]-255;\ possible_colors[1][B] = color[B]-255;\ possible_colors[2][R] = clamp_table[color[R] + table59T[dval]+255]-255;\ possible_colors[2][G] = clamp_table[color[G] + table59T[dval]+255]-255;\ possible_colors[2][B] = clamp_table[color[B] + table59T[dval]+255]-255;\ precalc_err_col0_RGB_adr = &precalc_err_col0_RGB[(colorRGB444_packed*8 + dval)*16];\ /* Loop block */\ /* unroll loop for (int x = 0; x < 16; x++) */\ {\ ONEPOINT59RGB(0)\ ONEPOINT59RGB(1)\ ONEPOINT59RGB(2)\ ONEPOINT59RGB(3)\ ONEPOINT59RGB(4)\ ONEPOINT59RGB(5)\ ONEPOINT59RGB(6)\ ONEPOINT59RGB(7)\ ONEPOINT59RGB(8)\ ONEPOINT59RGB(9)\ ONEPOINT59RGB(10)\ ONEPOINT59RGB(11)\ ONEPOINT59RGB(12)\ ONEPOINT59RGB(13)\ ONEPOINT59RGB(14)\ ONEPOINT59RGB(15)\ }\ color[R] = (((colorRGB444_packed >> 8) ) << 4) | ((colorRGB444_packed >> 8) ) ; color[G] = (((colorRGB444_packed >> 4) & 0xf) << 4) | ((colorRGB444_packed >> 4) & 0xf) ; color[B] = (((colorRGB444_packed) & 0xf) << 4) | ((colorRGB444_packed) & 0xf) ; /* Test all distances */ /* unroll loop for (uint8 d = 0; d < 8; ++d) */ { ONETABLE59RGB(0) ONETABLE59RGB(1) ONETABLE59RGB(2) ONETABLE59RGB(3) ONETABLE59RGB(4) ONETABLE59RGB(5) ONETABLE59RGB(6) ONETABLE59RGB(7) } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates a table used in exhaustive compression of the T-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcError59T_col1_RGBpercep1000(uint8* block, int colorRGB444_packed, unsigned int *precalc_err_col1_RGB) { unsigned int pixel_error; int diff[3]; uint8 colorRGB[3]; colorRGB[0] = ((colorRGB444_packed >> 8) & 0xf)*17; colorRGB[1] = ((colorRGB444_packed >> 4) & 0xf)*17; colorRGB[2] = ((colorRGB444_packed >> 0) & 0xf)*17; // Loop block for (int x = 0; x < 16; x++) { diff[R] = block[4*x + R] - colorRGB[R]; diff[G] = block[4*x + G] - colorRGB[G]; diff[B] = block[4*x + B] - colorRGB[B]; pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*SQUARE(diff[R]) + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000*SQUARE(diff[G]) + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*SQUARE(diff[B]); precalc_err_col1_RGB[(colorRGB444_packed)*16 + x] = (unsigned int) pixel_error; } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates a table used in exhaustive compression of the T-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcError59T_col1_RGB(uint8* block, int colorRGB444_packed, unsigned int *precalc_err_col1_RGB) { unsigned int pixel_error; int diff[3]; uint8 colorRGB[3]; colorRGB[0] = ((colorRGB444_packed >> 8) & 0xf)*17; colorRGB[1] = ((colorRGB444_packed >> 4) & 0xf)*17; colorRGB[2] = ((colorRGB444_packed >> 0) & 0xf)*17; // Loop block for (int x = 0; x < 16; x++) { diff[R] = block[4*x + R] - colorRGB[R]; diff[G] = block[4*x + G] - colorRGB[G]; diff[B] = block[4*x + B] - colorRGB[B]; pixel_error = SQUARE(diff[R]) + SQUARE(diff[G]) + SQUARE(diff[B]); precalc_err_col1_RGB[(colorRGB444_packed)*16 + x] = (unsigned int) pixel_error; } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Calculate a minimal error for the T-mode when compressing exhaustively. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateError59TusingPrecalcRperceptual1000(uint8* block, int *colorsRGB444_packed, unsigned int *precalc_err_col0_R, unsigned int *precalc_err_col1_R, unsigned int best_error_so_far) { unsigned int block_error = 0, best_block_error = MAXERR1000; unsigned int *pixel_error_col0_base_adr; unsigned int *pixel_error_col0_adr, *pixel_error_col1_adr; #define FIRSTCHOICE59R_PERCEP\ if(*pixel_error_col0_adr < *pixel_error_col1_adr)\ block_error = *pixel_error_col0_adr;\ else\ block_error = *pixel_error_col1_adr;\ #define CHOICE59R_PERCEP(xval)\ if(pixel_error_col0_adr[xval] < pixel_error_col1_adr[xval])\ block_error += pixel_error_col0_adr[xval];\ else\ block_error += pixel_error_col1_adr[xval];\ #define ONETABLE59R_PERCEP(dval) \ pixel_error_col0_adr = &pixel_error_col0_base_adr[dval*16];\ /* unroll loop for(int x = 0; block_error < best_error_so_far && x<16; x++) */\ {\ FIRSTCHOICE59R_PERCEP\ if( block_error < best_error_so_far)\ {\ CHOICE59R_PERCEP(1)\ if( block_error < best_error_so_far)\ {\ CHOICE59R_PERCEP(2)\ CHOICE59R_PERCEP(3)\ if( block_error < best_error_so_far)\ {\ CHOICE59R_PERCEP(4)\ CHOICE59R_PERCEP(5)\ if( block_error < best_error_so_far)\ {\ CHOICE59R_PERCEP(6)\ CHOICE59R_PERCEP(7)\ if( block_error < best_error_so_far)\ {\ CHOICE59R_PERCEP(8)\ CHOICE59R_PERCEP(9)\ if( block_error < best_error_so_far)\ {\ CHOICE59R_PERCEP(10)\ CHOICE59R_PERCEP(11)\ if( block_error < best_error_so_far)\ {\ CHOICE59R_PERCEP(12)\ CHOICE59R_PERCEP(13)\ if( block_error < best_error_so_far)\ {\ CHOICE59R_PERCEP(14)\ CHOICE59R_PERCEP(15)\ }\ }\ }\ }\ }\ }\ }\ }\ }\ if (block_error < best_block_error)\ best_block_error = block_error;\ pixel_error_col0_base_adr = &precalc_err_col0_R[((colorsRGB444_packed[0]>>8)*8)*16]; pixel_error_col1_adr = &precalc_err_col1_R[((colorsRGB444_packed[1]>>8))*16]; // Test all distances /* unroll loop for (uint8 d = 0; d < 8; d++) */ { ONETABLE59R_PERCEP(0) ONETABLE59R_PERCEP(1) ONETABLE59R_PERCEP(2) ONETABLE59R_PERCEP(3) ONETABLE59R_PERCEP(4) ONETABLE59R_PERCEP(5) ONETABLE59R_PERCEP(6) ONETABLE59R_PERCEP(7) } return best_block_error; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Calculate a minimal error for the T-mode when compressing exhaustively. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateError59TusingPrecalcR(uint8* block, int *colorsRGB444_packed, unsigned int *precalc_err_col0_R, unsigned int *precalc_err_col1_R, unsigned int best_error_so_far) { unsigned int block_error = 0, best_block_error = MAXIMUM_ERROR; unsigned int *pixel_error_col0_base_adr; unsigned int *pixel_error_col0_adr, *pixel_error_col1_adr; #define FIRSTCHOICE59R\ if(*pixel_error_col0_adr < *pixel_error_col1_adr)\ block_error = *pixel_error_col0_adr;\ else\ block_error = *pixel_error_col1_adr;\ #define CHOICE59R(xval)\ if(pixel_error_col0_adr[xval] < pixel_error_col1_adr[xval])\ block_error += pixel_error_col0_adr[xval];\ else\ block_error += pixel_error_col1_adr[xval];\ #define ONETABLE59R(dval) \ pixel_error_col0_adr = &pixel_error_col0_base_adr[dval*16];\ /* unroll loop for(int x = 0; block_error < best_error_so_far && x<16; x++) */\ {\ FIRSTCHOICE59R\ if( block_error < best_error_so_far)\ {\ CHOICE59R(1)\ if( block_error < best_error_so_far)\ {\ CHOICE59R(2)\ CHOICE59R(3)\ if( block_error < best_error_so_far)\ {\ CHOICE59R(4)\ CHOICE59R(5)\ if( block_error < best_error_so_far)\ {\ CHOICE59R(6)\ CHOICE59R(7)\ if( block_error < best_error_so_far)\ {\ CHOICE59R(8)\ CHOICE59R(9)\ if( block_error < best_error_so_far)\ {\ CHOICE59R(10)\ CHOICE59R(11)\ if( block_error < best_error_so_far)\ {\ CHOICE59R(12)\ CHOICE59R(13)\ if( block_error < best_error_so_far)\ {\ CHOICE59R(14)\ CHOICE59R(15)\ }\ }\ }\ }\ }\ }\ }\ }\ }\ if (block_error < best_block_error)\ best_block_error = block_error;\ pixel_error_col0_base_adr = &precalc_err_col0_R[((colorsRGB444_packed[0]>>8)*8)*16]; pixel_error_col1_adr = &precalc_err_col1_R[((colorsRGB444_packed[1]>>8))*16]; // Test all distances /* unroll loop for (uint8 d = 0; d < 8; d++) */ { ONETABLE59R(0) ONETABLE59R(1) ONETABLE59R(2) ONETABLE59R(3) ONETABLE59R(4) ONETABLE59R(5) ONETABLE59R(6) ONETABLE59R(7) } return best_block_error; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Calculate a minimal error for the T-mode when compressing exhaustively. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateError59TusingPrecalcRGperceptual1000(uint8* block, int *colorsRGB444_packed, unsigned int *precalc_err_col0_RG, unsigned int *precalc_err_col1_RG, unsigned int best_error_so_far) { unsigned int block_error = 0, best_block_error = MAXERR1000; unsigned int *pixel_error_col0_adr, *pixel_error_col1_adr; unsigned int *pixel_error_col0_base_adr; #define FIRSTCHOICE59RG_PERCEP \ if(*pixel_error_col0_adr < *pixel_error_col1_adr)\ block_error = *pixel_error_col0_adr;\ else\ block_error = *pixel_error_col1_adr;\ #define CHOICE59RG_PERCEP(xval) \ if(pixel_error_col0_adr[xval] < pixel_error_col1_adr[xval])\ block_error += pixel_error_col0_adr[xval];\ else\ block_error += pixel_error_col1_adr[xval];\ #define ONETABLE59RG_PERCEP(dval)\ pixel_error_col0_adr = &pixel_error_col0_base_adr[dval*16];\ /* unroll loop for(int x = 0; block_error < best_error_so_far && x<16; x++) */\ {\ FIRSTCHOICE59RG_PERCEP\ if( block_error < best_error_so_far)\ {\ CHOICE59RG_PERCEP(1)\ if( block_error < best_error_so_far)\ {\ CHOICE59RG_PERCEP(2)\ CHOICE59RG_PERCEP(3)\ if( block_error < best_error_so_far)\ {\ CHOICE59RG_PERCEP(4)\ CHOICE59RG_PERCEP(5)\ if( block_error < best_error_so_far)\ {\ CHOICE59RG_PERCEP(6)\ CHOICE59RG_PERCEP(7)\ if( block_error < best_error_so_far)\ {\ CHOICE59RG_PERCEP(8)\ CHOICE59RG_PERCEP(9)\ if( block_error < best_error_so_far)\ {\ CHOICE59RG_PERCEP(10)\ CHOICE59RG_PERCEP(11)\ if( block_error < best_error_so_far)\ {\ CHOICE59RG_PERCEP(12)\ CHOICE59RG_PERCEP(13)\ if( block_error < best_error_so_far)\ {\ CHOICE59RG_PERCEP(14)\ CHOICE59RG_PERCEP(15)\ }\ }\ }\ }\ }\ }\ }\ }\ }\ if (block_error < best_block_error)\ best_block_error = block_error;\ pixel_error_col0_base_adr = &precalc_err_col0_RG[((colorsRGB444_packed[0]>>4)*8)*16]; pixel_error_col1_adr = &precalc_err_col1_RG[((colorsRGB444_packed[1]>>4))*16]; // Test all distances /* unroll loop for (uint8 d = 0; d < 8; d++) */ { ONETABLE59RG_PERCEP(0) ONETABLE59RG_PERCEP(1) ONETABLE59RG_PERCEP(2) ONETABLE59RG_PERCEP(3) ONETABLE59RG_PERCEP(4) ONETABLE59RG_PERCEP(5) ONETABLE59RG_PERCEP(6) ONETABLE59RG_PERCEP(7) } return best_block_error; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Calculate a minimal error for the T-mode when compressing exhaustively. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateError59TusingPrecalcRG(uint8* block, int *colorsRGB444_packed, unsigned int *precalc_err_col0_RG, unsigned int *precalc_err_col1_RG, unsigned int best_error_so_far) { unsigned int block_error = 0, best_block_error = MAXIMUM_ERROR; unsigned int *pixel_error_col0_adr, *pixel_error_col1_adr; unsigned int *pixel_error_col0_base_adr; #define FIRSTCHOICE59RG \ if(*pixel_error_col0_adr < *pixel_error_col1_adr)\ block_error = *pixel_error_col0_adr;\ else\ block_error = *pixel_error_col1_adr;\ #define CHOICE59RG(xval) \ if(pixel_error_col0_adr[xval] < pixel_error_col1_adr[xval])\ block_error += pixel_error_col0_adr[xval];\ else\ block_error += pixel_error_col1_adr[xval];\ #define ONETABLE59RG(dval)\ pixel_error_col0_adr = &pixel_error_col0_base_adr[dval*16];\ /* unroll loop for(int x = 0; block_error < best_error_so_far && x<16; x++) */\ {\ FIRSTCHOICE59RG\ if( block_error < best_error_so_far)\ {\ CHOICE59RG(1)\ if( block_error < best_error_so_far)\ {\ CHOICE59RG(2)\ CHOICE59RG(3)\ if( block_error < best_error_so_far)\ {\ CHOICE59RG(4)\ CHOICE59RG(5)\ if( block_error < best_error_so_far)\ {\ CHOICE59RG(6)\ CHOICE59RG(7)\ if( block_error < best_error_so_far)\ {\ CHOICE59RG(8)\ CHOICE59RG(9)\ if( block_error < best_error_so_far)\ {\ CHOICE59RG(10)\ CHOICE59RG(11)\ if( block_error < best_error_so_far)\ {\ CHOICE59RG(12)\ CHOICE59RG(13)\ if( block_error < best_error_so_far)\ {\ CHOICE59RG(14)\ CHOICE59RG(15)\ }\ }\ }\ }\ }\ }\ }\ }\ }\ if (block_error < best_block_error)\ best_block_error = block_error;\ pixel_error_col0_base_adr = &precalc_err_col0_RG[((colorsRGB444_packed[0]>>4)*8)*16]; pixel_error_col1_adr = &precalc_err_col1_RG[((colorsRGB444_packed[1]>>4))*16]; // Test all distances /* unroll loop for (uint8 d = 0; d < 8; d++) */ { ONETABLE59RG(0) ONETABLE59RG(1) ONETABLE59RG(2) ONETABLE59RG(3) ONETABLE59RG(4) ONETABLE59RG(5) ONETABLE59RG(6) ONETABLE59RG(7) } return best_block_error; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Calculate a minimal error for the T-mode when compressing exhaustively. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateError59TusingPrecalcRGBperceptual1000(uint8* block, int *colorsRGB444_packed, unsigned int *precalc_err_col0_RGB, unsigned int *precalc_err_col1_RGB, unsigned int best_error_so_far) { unsigned int block_error = 0, best_block_error = MAXERR1000; unsigned int *pixel_error_col0_adr, *pixel_error_col1_adr; unsigned int *pixel_error_col0_base_adr; #define FIRSTCHOICE59_PERCEP \ if(*pixel_error_col0_adr < *pixel_error_col1_adr)\ block_error = *pixel_error_col0_adr;\ else\ block_error = *pixel_error_col1_adr;\ #define CHOICE59_PERCEP(xval) \ if(pixel_error_col0_adr[xval] < pixel_error_col1_adr[xval])\ block_error += pixel_error_col0_adr[xval];\ else\ block_error += pixel_error_col1_adr[xval];\ #define ONETABLE59T_PERCEP(dval)\ pixel_error_col0_adr = &pixel_error_col0_base_adr[dval*16];\ /* unroll for(int x = 0; block_error < best_error_so_far && x<16; x++) */\ {\ FIRSTCHOICE59_PERCEP\ if( block_error < best_error_so_far)\ {\ CHOICE59_PERCEP(1)\ if( block_error < best_error_so_far)\ {\ CHOICE59_PERCEP(2)\ CHOICE59_PERCEP(3)\ if( block_error < best_error_so_far)\ {\ CHOICE59_PERCEP(4)\ CHOICE59_PERCEP(5)\ if( block_error < best_error_so_far)\ {\ CHOICE59_PERCEP(6)\ CHOICE59_PERCEP(7)\ if( block_error < best_error_so_far)\ {\ CHOICE59_PERCEP(8)\ CHOICE59_PERCEP(9)\ if( block_error < best_error_so_far)\ {\ CHOICE59_PERCEP(10)\ CHOICE59_PERCEP(11)\ if( block_error < best_error_so_far)\ {\ CHOICE59_PERCEP(12)\ CHOICE59_PERCEP(13)\ if( block_error < best_error_so_far)\ {\ CHOICE59_PERCEP(14)\ CHOICE59_PERCEP(15)\ }\ }\ }\ }\ }\ }\ }\ }\ }\ if (block_error < best_block_error)\ best_block_error = block_error;\ pixel_error_col1_adr = &precalc_err_col1_RGB[(colorsRGB444_packed[1])*16]; pixel_error_col0_base_adr = &precalc_err_col0_RGB[(colorsRGB444_packed[0]*8)*16]; // Test all distances /* unroll loop for (uint8 d = 0; d < 8; d++)*/ { ONETABLE59T_PERCEP(0) ONETABLE59T_PERCEP(1) ONETABLE59T_PERCEP(2) ONETABLE59T_PERCEP(3) ONETABLE59T_PERCEP(4) ONETABLE59T_PERCEP(5) ONETABLE59T_PERCEP(6) ONETABLE59T_PERCEP(7) } return best_block_error; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Calculate a minimal error for the T-mode when compressing exhaustively. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateError59TusingPrecalcRGB(uint8* block, int *colorsRGB444_packed, unsigned int *precalc_err_col0_RGB, unsigned int *precalc_err_col1_RGB, unsigned int best_error_so_far) { unsigned int block_error = 0, best_block_error = MAXIMUM_ERROR; unsigned int *pixel_error_col0_adr, *pixel_error_col1_adr; unsigned int *pixel_error_col0_base_adr; #define FIRSTCHOICE59 \ if(*pixel_error_col0_adr < *pixel_error_col1_adr)\ block_error = *pixel_error_col0_adr;\ else\ block_error = *pixel_error_col1_adr;\ #define CHOICE59(xval) \ if(pixel_error_col0_adr[xval] < pixel_error_col1_adr[xval])\ block_error += pixel_error_col0_adr[xval];\ else\ block_error += pixel_error_col1_adr[xval];\ #define ONETABLE59T(dval)\ pixel_error_col0_adr = &pixel_error_col0_base_adr[dval*16];\ /* unroll for(int x = 0; block_error < best_error_so_far && x<16; x++) */\ {\ FIRSTCHOICE59\ if( block_error < best_error_so_far)\ {\ CHOICE59(1)\ if( block_error < best_error_so_far)\ {\ CHOICE59(2)\ CHOICE59(3)\ if( block_error < best_error_so_far)\ {\ CHOICE59(4)\ CHOICE59(5)\ if( block_error < best_error_so_far)\ {\ CHOICE59(6)\ CHOICE59(7)\ if( block_error < best_error_so_far)\ {\ CHOICE59(8)\ CHOICE59(9)\ if( block_error < best_error_so_far)\ {\ CHOICE59(10)\ CHOICE59(11)\ if( block_error < best_error_so_far)\ {\ CHOICE59(12)\ CHOICE59(13)\ if( block_error < best_error_so_far)\ {\ CHOICE59(14)\ CHOICE59(15)\ }\ }\ }\ }\ }\ }\ }\ }\ }\ if (block_error < best_block_error)\ best_block_error = block_error;\ pixel_error_col1_adr = &precalc_err_col1_RGB[(colorsRGB444_packed[1])*16]; pixel_error_col0_base_adr = &precalc_err_col0_RGB[(colorsRGB444_packed[0]*8)*16]; // Test all distances /* unroll loop for (uint8 d = 0; d < 8; d++)*/ { ONETABLE59T(0) ONETABLE59T(1) ONETABLE59T(2) ONETABLE59T(3) ONETABLE59T(4) ONETABLE59T(5) ONETABLE59T(6) ONETABLE59T(7) } return best_block_error; } #endif #if EXHAUSTIVE_CODE_ACTIVE // The below code should compress the block to 59 bits. // This is supposed to match the first of the three modes in TWOTIMER. // //|63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 40 39|38 37 36 35|34 33 32| //|----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|--dist--| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // // Note that this method might not return the best possible compression for the T-mode. It will only do so if the best possible T-representation // is less than best_error_so_far. To guarantee that the best possible T-representation is found, the function should be called using // best_error_so_far = 255*255*3*16, which is the maximum error for a block. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int compressBlockTHUMB59TExhaustivePerceptual(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2, unsigned int best_error_so_far) { uint8 colorsRGB444[2][3]; unsigned int pixel_indices; uint8 distance; uint8 block[4*4*4]; unsigned int *precalc_err_col0_RGB; unsigned int *precalc_err_col1_RGB; unsigned int *precalc_err_col0_RG; unsigned int *precalc_err_col1_RG; unsigned int *precalc_err_col0_R; unsigned int *precalc_err_col1_R; int colorRGB444_packed; int colorsRGB444_packed[2]; int best_colorsRGB444_packed[2]; unsigned int best_error_using_Tmode; // First compress block quickly to a resonable quality so that we can // rule out all blocks that are of worse quality than that. best_error_using_Tmode = (unsigned int) compressBlockTHUMB59TFastestOnlyColorPerceptual1000(img, width, height, startx, starty, best_colorsRGB444_packed); if(best_error_using_Tmode < best_error_so_far) best_error_so_far = best_error_using_Tmode; // Color numbering is reversed between the above function and the precalc functions below; swap colors. int temp = best_colorsRGB444_packed[0]; best_colorsRGB444_packed[0] = best_colorsRGB444_packed[1]; best_colorsRGB444_packed[1] = temp; int xx,yy,count = 0; // Use 4 bytes per pixel to make it 32-word aligned. for(xx = 0; xx<4; xx++) { for(yy=0; yy<4; yy++) { block[(count)*4] = img[((starty+yy)*width+(startx+xx))*3]; block[(count)*4+1] = img[((starty+yy)*width+(startx+xx))*3+1]; block[(count)*4+2] = img[((starty+yy)*width+(startx+xx))*3+2]; block[(count)*4+3] = 0; count++; } } // Precalculate error for color 0 (which produces the upper half of the T) precalc_err_col0_RGB = (unsigned int*) malloc(4096*8*16*sizeof(unsigned int)); if(!precalc_err_col0_RGB){printf("Out of memory allocating \n");exit(1);} for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed++) { precalcError59T_col0_RGBpercep1000(block, colorRGB444_packed, precalc_err_col0_RGB); } // Precalculate error for color 1 (which produces the lower half of the T -- the lone color) precalc_err_col1_RGB = (unsigned int*) malloc(4096*16*sizeof(unsigned int)); if(!precalc_err_col1_RGB){printf("Out of memory allocating \n");exit(1);} for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed++) { precalcError59T_col1_RGBpercep1000(block, colorRGB444_packed, precalc_err_col1_RGB); } precalc_err_col0_RG = (unsigned int*) malloc(16*16*8*16*sizeof(unsigned int)); if(!precalc_err_col0_RG){printf("Out of memory allocating \n");exit(1);} for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed+=16) { precalcError59T_col0_RGpercep1000(block, colorRGB444_packed, precalc_err_col0_RG); } precalc_err_col1_RG = (unsigned int*) malloc(16*16*16*sizeof(unsigned int)); if(!precalc_err_col1_RG){printf("Out of memory allocating \n");exit(1);} for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed+=16) { precalcError59T_col1_RGpercep1000(block, colorRGB444_packed, precalc_err_col1_RG); } precalc_err_col0_R = (unsigned int*) malloc(16*8*16*sizeof(unsigned int)); if(!precalc_err_col0_R){printf("Out of memory allocating \n");exit(1);} for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed+=16*16) { precalcError59T_col0_Rpercep1000(block, colorRGB444_packed, precalc_err_col0_R); } precalc_err_col1_R = (unsigned int*) malloc(16*16*sizeof(unsigned int)); if(!precalc_err_col1_R){printf("Out of memory allocating \n");exit(1);} for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed+=16*16) { precalcError59T_col1_Rpercep1000(block, colorRGB444_packed, precalc_err_col1_R); } unsigned int error; unsigned int avoided = 0; unsigned int notavoided = 0; for(colorsRGB444[0][0] = 0; colorsRGB444[0][0] < 16; colorsRGB444[0][0]++) { for(colorsRGB444[1][0] = 0; colorsRGB444[1][0] < 16; colorsRGB444[1][0]++) { colorsRGB444_packed[0] = (colorsRGB444[0][0] << 8); colorsRGB444_packed[1] = (colorsRGB444[1][0] << 8); error = calculateError59TusingPrecalcRperceptual1000(block, colorsRGB444_packed, precalc_err_col0_R, precalc_err_col1_R, best_error_so_far); if(error < best_error_so_far) { notavoided = notavoided + 1; for(colorsRGB444[0][1] = 0; colorsRGB444[0][1] < 16; colorsRGB444[0][1]++) { colorsRGB444_packed[0] = (colorsRGB444[0][0] << 8) + (colorsRGB444[0][1] <<4); for(colorsRGB444[1][1] = 0; colorsRGB444[1][1] < 16; colorsRGB444[1][1]++) { colorsRGB444_packed[1] = (colorsRGB444[1][0] << 8) + (colorsRGB444[1][1] <<4); error = calculateError59TusingPrecalcRGperceptual1000(block, colorsRGB444_packed, precalc_err_col0_RG, precalc_err_col1_RG, best_error_so_far); if(error < best_error_so_far) { for(colorsRGB444[0][2] = 0; colorsRGB444[0][2] < 16; colorsRGB444[0][2]++) { colorsRGB444_packed[0] = (colorsRGB444[0][0] << 8) + (colorsRGB444[0][1] <<4) + colorsRGB444[0][2]; for(colorsRGB444[1][2] = 0; colorsRGB444[1][2] < 16; colorsRGB444[1][2]++) { colorsRGB444_packed[1] = (colorsRGB444[1][0] << 8) + (colorsRGB444[1][1] <<4) + colorsRGB444[1][2]; error = calculateError59TusingPrecalcRGBperceptual1000(block, colorsRGB444_packed, precalc_err_col0_RGB, precalc_err_col1_RGB, best_error_so_far); if(error < best_error_so_far) { best_error_so_far = error; best_error_using_Tmode = error; best_colorsRGB444_packed[0] = colorsRGB444_packed[0]; best_colorsRGB444_packed[1] = colorsRGB444_packed[1]; } } } } } } } } } free(precalc_err_col0_RGB); free(precalc_err_col1_RGB); free(precalc_err_col0_RG); free(precalc_err_col1_RG); free(precalc_err_col0_R); free(precalc_err_col1_R); // We have got the two best colors. Now find the best distance and pixel indices. // Color numbering are reversed between precalc and noSwap colorsRGB444[0][0] = (best_colorsRGB444_packed[1] >> 8) & 0xf; colorsRGB444[0][1] = (best_colorsRGB444_packed[1] >> 4) & 0xf; colorsRGB444[0][2] = (best_colorsRGB444_packed[1] >> 0) & 0xf; colorsRGB444[1][0] = (best_colorsRGB444_packed[0] >> 8) & 0xf; colorsRGB444[1][1] = (best_colorsRGB444_packed[0] >> 4) & 0xf; colorsRGB444[1][2] = (best_colorsRGB444_packed[0] >> 0) & 0xf; calculateError59TnoSwapPerceptual1000(img, width, startx, starty, colorsRGB444, distance, pixel_indices); // Put the compress params into the compression block packBlock59T(colorsRGB444, distance, pixel_indices, compressed1, compressed2); return best_error_using_Tmode; } #endif #if EXHAUSTIVE_CODE_ACTIVE // The below code should compress the block to 59 bits. // This is supposed to match the first of the three modes in TWOTIMER. // //|63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 40 39|38 37 36 35|34 33 32| //|----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|--dist--| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // // Note that this method might not return the best possible compression for the T-mode. It will only do so if the best possible T-representation // is less than best_error_so_far. To guarantee that the best possible T-representation is found, the function should be called using // best_error_so_far = 255*255*3*16, which is the maximum error for a block. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int compressBlockTHUMB59TExhaustive(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2, unsigned int best_error_so_far) { uint8 colorsRGB444[2][3]; unsigned int pixel_indices; uint8 distance; uint8 block[4*4*4]; unsigned int *precalc_err_col0_RGB; unsigned int *precalc_err_col1_RGB; unsigned int *precalc_err_col0_RG; unsigned int *precalc_err_col1_RG; unsigned int *precalc_err_col0_R; unsigned int *precalc_err_col1_R; int colorRGB444_packed; int colorsRGB444_packed[2]; int best_colorsRGB444_packed[2]; unsigned int best_error_using_Tmode; // First compress block quickly to a resonable quality so that we can // rule out all blocks that are of worse quality than that. best_error_using_Tmode = (unsigned int) compressBlockTHUMB59TFastestOnlyColor(img, width, height, startx, starty, best_colorsRGB444_packed); if(best_error_using_Tmode < best_error_so_far) best_error_so_far = best_error_using_Tmode; // Colors numbering is reversed between the above function and the precalc below: int temp = best_colorsRGB444_packed[0]; best_colorsRGB444_packed[0] = best_colorsRGB444_packed[1]; best_colorsRGB444_packed[1] = temp; int xx,yy,count = 0; // Use 4 bytes per pixel to make it 32-word aligned. for(xx = 0; xx<4; xx++) { for(yy=0; yy<4; yy++) { block[(count)*4] = img[((starty+yy)*width+(startx+xx))*3]; block[(count)*4+1] = img[((starty+yy)*width+(startx+xx))*3+1]; block[(count)*4+2] = img[((starty+yy)*width+(startx+xx))*3+2]; block[(count)*4+3] = 0; count++; } } // Precalculate error for color 0 (which produces the upper half of the T) precalc_err_col0_RGB = (unsigned int*) malloc(4096*8*16*sizeof(unsigned int)); if(!precalc_err_col0_RGB){printf("Out of memory allocating \n");exit(1);} for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed++) { precalcError59T_col0_RGB(block, colorRGB444_packed, precalc_err_col0_RGB); } // Precalculate error for color 1 (which produces the lower half of the T -- the lone color) precalc_err_col1_RGB = (unsigned int*) malloc(4096*16*sizeof(unsigned int)); if(!precalc_err_col1_RGB){printf("Out of memory allocating \n");exit(1);} for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed++) { precalcError59T_col1_RGB(block, colorRGB444_packed, precalc_err_col1_RGB); } precalc_err_col0_RG = (unsigned int*) malloc(16*16*8*16*sizeof(unsigned int)); if(!precalc_err_col0_RG){printf("Out of memory allocating \n");exit(1);} for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed+=16) { precalcError59T_col0_RG(block, colorRGB444_packed, precalc_err_col0_RG); } precalc_err_col1_RG = (unsigned int*) malloc(16*16*16*sizeof(unsigned int)); if(!precalc_err_col1_RG){printf("Out of memory allocating \n");exit(1);} for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed+=16) { precalcError59T_col1_RG(block, colorRGB444_packed, precalc_err_col1_RG); } precalc_err_col0_R = (unsigned int*) malloc(16*8*16*sizeof(unsigned int)); if(!precalc_err_col0_R){printf("Out of memory allocating \n");exit(1);} for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed+=16*16) { precalcError59T_col0_R(block, colorRGB444_packed, precalc_err_col0_R); } precalc_err_col1_R = (unsigned int*) malloc(16*16*sizeof(unsigned int)); if(!precalc_err_col1_R){printf("Out of memory allocating \n");exit(1);} for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed+=16*16) { precalcError59T_col1_R(block, colorRGB444_packed, precalc_err_col1_R); } unsigned int error; unsigned int avoided = 0; unsigned int notavoided = 0; for(colorsRGB444[0][0] = 0; colorsRGB444[0][0] < 16; colorsRGB444[0][0]++) { for(colorsRGB444[1][0] = 0; colorsRGB444[1][0] < 16; colorsRGB444[1][0]++) { colorsRGB444_packed[0] = (colorsRGB444[0][0] << 8); colorsRGB444_packed[1] = (colorsRGB444[1][0] << 8); error = calculateError59TusingPrecalcR(block, colorsRGB444_packed, precalc_err_col0_R, precalc_err_col1_R, best_error_so_far); if(error < best_error_so_far) { notavoided = notavoided + 1; for(colorsRGB444[0][1] = 0; colorsRGB444[0][1] < 16; colorsRGB444[0][1]++) { colorsRGB444_packed[0] = (colorsRGB444[0][0] << 8) + (colorsRGB444[0][1] <<4); for(colorsRGB444[1][1] = 0; colorsRGB444[1][1] < 16; colorsRGB444[1][1]++) { colorsRGB444_packed[1] = (colorsRGB444[1][0] << 8) + (colorsRGB444[1][1] <<4); error = calculateError59TusingPrecalcRG(block, colorsRGB444_packed, precalc_err_col0_RG, precalc_err_col1_RG, best_error_so_far); if(error < best_error_so_far) { for(colorsRGB444[0][2] = 0; colorsRGB444[0][2] < 16; colorsRGB444[0][2]++) { colorsRGB444_packed[0] = (colorsRGB444[0][0] << 8) + (colorsRGB444[0][1] <<4) + colorsRGB444[0][2]; for(colorsRGB444[1][2] = 0; colorsRGB444[1][2] < 16; colorsRGB444[1][2]++) { colorsRGB444_packed[1] = (colorsRGB444[1][0] << 8) + (colorsRGB444[1][1] <<4) + colorsRGB444[1][2]; error = calculateError59TusingPrecalcRGB(block, colorsRGB444_packed, precalc_err_col0_RGB, precalc_err_col1_RGB, best_error_so_far); if(error < best_error_so_far) { best_error_so_far = error; best_error_using_Tmode = error; best_colorsRGB444_packed[0] = colorsRGB444_packed[0]; best_colorsRGB444_packed[1] = colorsRGB444_packed[1]; } } } } } } } } } free(precalc_err_col0_RGB); free(precalc_err_col1_RGB); free(precalc_err_col0_RG); free(precalc_err_col1_RG); free(precalc_err_col0_R); free(precalc_err_col1_R); // We have got the two best colors. Now find the best distance and pixel indices. // Color numbering are reversed between precalc and noSwap colorsRGB444[0][0] = (best_colorsRGB444_packed[1] >> 8) & 0xf; colorsRGB444[0][1] = (best_colorsRGB444_packed[1] >> 4) & 0xf; colorsRGB444[0][2] = (best_colorsRGB444_packed[1] >> 0) & 0xf; colorsRGB444[1][0] = (best_colorsRGB444_packed[0] >> 8) & 0xf; colorsRGB444[1][1] = (best_colorsRGB444_packed[0] >> 4) & 0xf; colorsRGB444[1][2] = (best_colorsRGB444_packed[0] >> 0) & 0xf; calculateError59TnoSwap(img, width, startx, starty, colorsRGB444, distance, pixel_indices); // Put the compress params into the compression block packBlock59T(colorsRGB444, distance, pixel_indices, compressed1, compressed2); return best_error_using_Tmode; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates tables used in the exhaustive compression of the H-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcErrorR_58Hperceptual1000(uint8* srcimg, int width, int startx, int starty, uint8 (colorsRGB444)[2][3],int colorRGB444_packed, unsigned int *precalc_errR) { unsigned int block_error = 0, best_block_error = MAXERR1000, pixel_error, best_pixel_error; int diff[3]; unsigned int pixel_colors; uint8 possible_colors[2][3]; uint8 colors[2][3]; decompressColor(R_BITS58H, G_BITS58H, B_BITS58H, colorsRGB444, colors); // Test all distances for (uint8 d = 0; d < BINPOW(TABLE_BITS_58H); ++d) { possible_colors[0][R] = CLAMP(0,colors[0][R] - table58H[d],255); possible_colors[1][R] = CLAMP(0,colors[0][R] + table58H[d],255); block_error = 0; pixel_colors = 0; // Loop block for (size_t y = 0; y < BLOCKHEIGHT; ++y) { for (size_t x = 0; x < BLOCKWIDTH; ++x) { best_pixel_error = MAXERR1000; // Loop possible block colors for (uint8 c = 0; c < 2; ++c) { diff[R] = srcimg[3*((starty+y)*width+startx+x)+R] - CLAMP(0,possible_colors[c][R],255); pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*SQUARE(diff[R]); // Choose best error if (pixel_error < best_pixel_error) { best_pixel_error = pixel_error; } } precalc_errR[((colorRGB444_packed>>8)*8 + d)*16 + (y*4)+x] = (unsigned int) best_pixel_error; } } } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates tables used in the exhaustive compression of the H-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcErrorR_58H(uint8* srcimg, int width, int startx, int starty, uint8 (colorsRGB444)[2][3],int colorRGB444_packed, unsigned int *precalc_errR) { double block_error = 0, best_block_error = MAXIMUM_ERROR, pixel_error, best_pixel_error; int diff[3]; unsigned int pixel_colors; uint8 possible_colors[2][3]; uint8 colors[2][3]; decompressColor(R_BITS58H, G_BITS58H, B_BITS58H, colorsRGB444, colors); // Test all distances for (uint8 d = 0; d < BINPOW(TABLE_BITS_58H); ++d) { possible_colors[0][R] = CLAMP(0,colors[0][R] - table58H[d],255); possible_colors[1][R] = CLAMP(0,colors[0][R] + table58H[d],255); block_error = 0; pixel_colors = 0; // Loop block for (size_t y = 0; y < BLOCKHEIGHT; ++y) { for (size_t x = 0; x < BLOCKWIDTH; ++x) { best_pixel_error = MAXIMUM_ERROR; // Loop possible block colors for (uint8 c = 0; c < 2; ++c) { diff[R] = srcimg[3*((starty+y)*width+startx+x)+R] - CLAMP(0,possible_colors[c][R],255); pixel_error = weight[R]*SQUARE(diff[R]); // Choose best error if (pixel_error < best_pixel_error) { best_pixel_error = pixel_error; } } precalc_errR[((colorRGB444_packed>>8)*8 + d)*16 + (y*4)+x] = (unsigned int) best_pixel_error; } } } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates tables used in the exhaustive compression of the H-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcErrorRG_58Hperceptual1000(uint8* srcimg, int width, int startx, int starty, uint8 (colorsRGB444)[2][3],int colorRGB444_packed, unsigned int *precalc_errRG) { unsigned int block_error = 0, best_block_error = MAXERR1000, pixel_error, best_pixel_error; int diff[3]; unsigned int pixel_colors; uint8 possible_colors[2][3]; uint8 colors[2][3]; decompressColor(R_BITS58H, G_BITS58H, B_BITS58H, colorsRGB444, colors); // Test all distances for (uint8 d = 0; d < BINPOW(TABLE_BITS_58H); ++d) { possible_colors[0][R] = CLAMP(0,colors[0][R] - table58H[d],255); possible_colors[0][G] = CLAMP(0,colors[0][G] - table58H[d],255); possible_colors[1][R] = CLAMP(0,colors[0][R] + table58H[d],255); possible_colors[1][G] = CLAMP(0,colors[0][G] + table58H[d],255); block_error = 0; pixel_colors = 0; // Loop block for (size_t y = 0; y < BLOCKHEIGHT; ++y) { for (size_t x = 0; x < BLOCKWIDTH; ++x) { best_pixel_error = MAXERR1000; // Loop possible block colors for (uint8 c = 0; c < 2; ++c) { diff[R] = srcimg[3*((starty+y)*width+startx+x)+R] - CLAMP(0,possible_colors[c][R],255); diff[G] = srcimg[3*((starty+y)*width+startx+x)+G] - CLAMP(0,possible_colors[c][G],255); pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*SQUARE(diff[R]) + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000*SQUARE(diff[G]); // Choose best error if (pixel_error < best_pixel_error) { best_pixel_error = pixel_error; } } precalc_errRG[((colorRGB444_packed>>4)*8 + d)*16 + (y*4)+x] = (unsigned int) best_pixel_error; } } } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates tables used in the exhaustive compression of the H-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcErrorRG_58H(uint8* srcimg, int width, int startx, int starty, uint8 (colorsRGB444)[2][3],int colorRGB444_packed, unsigned int *precalc_errRG) { double block_error = 0, best_block_error = MAXIMUM_ERROR, pixel_error, best_pixel_error; int diff[3]; unsigned int pixel_colors; uint8 possible_colors[2][3]; uint8 colors[2][3]; decompressColor(R_BITS58H, G_BITS58H, B_BITS58H, colorsRGB444, colors); // Test all distances for (uint8 d = 0; d < BINPOW(TABLE_BITS_58H); ++d) { possible_colors[0][R] = CLAMP(0,colors[0][R] - table58H[d],255); possible_colors[0][G] = CLAMP(0,colors[0][G] - table58H[d],255); possible_colors[1][R] = CLAMP(0,colors[0][R] + table58H[d],255); possible_colors[1][G] = CLAMP(0,colors[0][G] + table58H[d],255); block_error = 0; pixel_colors = 0; // Loop block for (size_t y = 0; y < BLOCKHEIGHT; ++y) { for (size_t x = 0; x < BLOCKWIDTH; ++x) { best_pixel_error = MAXIMUM_ERROR; // Loop possible block colors for (uint8 c = 0; c < 2; ++c) { diff[R] = srcimg[3*((starty+y)*width+startx+x)+R] - CLAMP(0,possible_colors[c][R],255); diff[G] = srcimg[3*((starty+y)*width+startx+x)+G] - CLAMP(0,possible_colors[c][G],255); pixel_error = weight[R]*SQUARE(diff[R]) + weight[G]*SQUARE(diff[G]); // Choose best error if (pixel_error < best_pixel_error) { best_pixel_error = pixel_error; } } precalc_errRG[((colorRGB444_packed>>4)*8 + d)*16 + (y*4)+x] = (unsigned int) best_pixel_error; } } } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates a table used in the exhaustive compression of the H-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcError58Hperceptual1000(uint8* block, uint8 (colorsRGB444)[2][3],int colorRGB444_packed, unsigned int *precalc_err) { unsigned int pixel_error, best_pixel_error; int possible_colors[2][3]; uint8 colors[2][3]; unsigned int *precalc_err_tab; int red_original; int green_original; int blue_original; #define PRECALC_ONE_58H_PERCEP(qvalue)\ red_original = block[qvalue*4];\ green_original = block[qvalue*4+1];\ blue_original = block[qvalue*4+2];\ /* unroll loop for (color = 0; color< 2; color++) */\ best_pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*square_table[(possible_colors[0][R] - red_original)] \ + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000*square_table[(possible_colors[0][G] - green_original)]\ + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[(possible_colors[0][B] - blue_original)];\ pixel_error = PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000*square_table[(possible_colors[1][R] - red_original)]\ + PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000*square_table[(possible_colors[1][G] - green_original)]\ + PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000*square_table[(possible_colors[1][B] - blue_original)];\ if (pixel_error < best_pixel_error)\ best_pixel_error = pixel_error;\ /* end unroll loop */\ precalc_err_tab[qvalue] = best_pixel_error;\ #define PRECALC_ONE_TABLE_58H_PERCEP(dvalue)\ precalc_err_tab = &precalc_err[((colorRGB444_packed*8)+dvalue)*16];\ possible_colors[0][R] = CLAMP_LEFT_ZERO(colors[0][R] - table58H[dvalue])+255;\ possible_colors[0][G] = CLAMP_LEFT_ZERO(colors[0][G] - table58H[dvalue])+255;\ possible_colors[0][B] = CLAMP_LEFT_ZERO(colors[0][B] - table58H[dvalue])+255;\ possible_colors[1][R] = CLAMP_RIGHT_255(colors[0][R] + table58H[dvalue])+255;\ possible_colors[1][G] = CLAMP_RIGHT_255(colors[0][G] + table58H[dvalue])+255;\ possible_colors[1][B] = CLAMP_RIGHT_255(colors[0][B] + table58H[dvalue])+255;\ /* unrolled loop for(q = 0; q<16; q++)*/\ PRECALC_ONE_58H_PERCEP(0)\ PRECALC_ONE_58H_PERCEP(1)\ PRECALC_ONE_58H_PERCEP(2)\ PRECALC_ONE_58H_PERCEP(3)\ PRECALC_ONE_58H_PERCEP(4)\ PRECALC_ONE_58H_PERCEP(5)\ PRECALC_ONE_58H_PERCEP(6)\ PRECALC_ONE_58H_PERCEP(7)\ PRECALC_ONE_58H_PERCEP(8)\ PRECALC_ONE_58H_PERCEP(9)\ PRECALC_ONE_58H_PERCEP(10)\ PRECALC_ONE_58H_PERCEP(11)\ PRECALC_ONE_58H_PERCEP(12)\ PRECALC_ONE_58H_PERCEP(13)\ PRECALC_ONE_58H_PERCEP(14)\ PRECALC_ONE_58H_PERCEP(15)\ /* end unroll loop */\ colors[0][R] = (colorsRGB444[0][R] << 4) | colorsRGB444[0][R]; colors[0][G] = (colorsRGB444[0][G] << 4) | colorsRGB444[0][G]; colors[0][B] = (colorsRGB444[0][B] << 4) | colorsRGB444[0][B]; // Test all distances /* unroll loop for (uint8 d = 0; d < 8; ++d) */ PRECALC_ONE_TABLE_58H_PERCEP(0) PRECALC_ONE_TABLE_58H_PERCEP(1) PRECALC_ONE_TABLE_58H_PERCEP(2) PRECALC_ONE_TABLE_58H_PERCEP(3) PRECALC_ONE_TABLE_58H_PERCEP(4) PRECALC_ONE_TABLE_58H_PERCEP(5) PRECALC_ONE_TABLE_58H_PERCEP(6) PRECALC_ONE_TABLE_58H_PERCEP(7) /* end unroll loop */ } #endif #if EXHAUSTIVE_CODE_ACTIVE // Precalculates a table used in the exhaustive compression of the H-mode. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void precalcError58H(uint8* block, uint8 (colorsRGB444)[2][3],int colorRGB444_packed, unsigned int *precalc_err) { unsigned int pixel_error, best_pixel_error; int possible_colors[2][3]; uint8 colors[2][3]; unsigned int *precalc_err_tab; int red_original; int green_original; int blue_original; #define PRECALC_ONE_58H(qvalue)\ red_original = block[qvalue*4];\ green_original = block[qvalue*4+1];\ blue_original = block[qvalue*4+2];\ /* unroll loop for (color = 0; color< 2; color++) */\ best_pixel_error = square_table[(possible_colors[0][R] - red_original)] + square_table[(possible_colors[0][G] - green_original)] + square_table[(possible_colors[0][B] - blue_original)];\ pixel_error = square_table[(possible_colors[1][R] - red_original)] + square_table[(possible_colors[1][G] - green_original)] + square_table[(possible_colors[1][B] - blue_original)];\ if (pixel_error < best_pixel_error)\ best_pixel_error = pixel_error;\ /* end unroll loop */\ precalc_err_tab[qvalue] = best_pixel_error;\ #define PRECALC_ONE_TABLE_58H(dvalue)\ precalc_err_tab = &precalc_err[((colorRGB444_packed*8)+dvalue)*16];\ possible_colors[0][R] = CLAMP_LEFT_ZERO(colors[0][R] - table58H[dvalue])+255;\ possible_colors[0][G] = CLAMP_LEFT_ZERO(colors[0][G] - table58H[dvalue])+255;\ possible_colors[0][B] = CLAMP_LEFT_ZERO(colors[0][B] - table58H[dvalue])+255;\ possible_colors[1][R] = CLAMP_RIGHT_255(colors[0][R] + table58H[dvalue])+255;\ possible_colors[1][G] = CLAMP_RIGHT_255(colors[0][G] + table58H[dvalue])+255;\ possible_colors[1][B] = CLAMP_RIGHT_255(colors[0][B] + table58H[dvalue])+255;\ /* unrolled loop for(q = 0; q<16; q++)*/\ PRECALC_ONE_58H(0)\ PRECALC_ONE_58H(1)\ PRECALC_ONE_58H(2)\ PRECALC_ONE_58H(3)\ PRECALC_ONE_58H(4)\ PRECALC_ONE_58H(5)\ PRECALC_ONE_58H(6)\ PRECALC_ONE_58H(7)\ PRECALC_ONE_58H(8)\ PRECALC_ONE_58H(9)\ PRECALC_ONE_58H(10)\ PRECALC_ONE_58H(11)\ PRECALC_ONE_58H(12)\ PRECALC_ONE_58H(13)\ PRECALC_ONE_58H(14)\ PRECALC_ONE_58H(15)\ /* end unroll loop */\ colors[0][R] = (colorsRGB444[0][R] << 4) | colorsRGB444[0][R]; colors[0][G] = (colorsRGB444[0][G] << 4) | colorsRGB444[0][G]; colors[0][B] = (colorsRGB444[0][B] << 4) | colorsRGB444[0][B]; // Test all distances /* unroll loop for (uint8 d = 0; d < 8; ++d) */ PRECALC_ONE_TABLE_58H(0) PRECALC_ONE_TABLE_58H(1) PRECALC_ONE_TABLE_58H(2) PRECALC_ONE_TABLE_58H(3) PRECALC_ONE_TABLE_58H(4) PRECALC_ONE_TABLE_58H(5) PRECALC_ONE_TABLE_58H(6) PRECALC_ONE_TABLE_58H(7) /* end unroll loop */ } #endif #if EXHAUSTIVE_CODE_ACTIVE // Calculate a minimum error for the H-mode when doing exhaustive compression. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateErrorFromPrecalcR58Hperceptual1000(int *colorsRGB444_packed, unsigned int *precalc_errR, unsigned int best_err_so_far) { unsigned int block_error = 0; unsigned int best_block_error = MAXERR1000; unsigned int *precalc_col1, *precalc_col2; unsigned int *precalc_col1tab, *precalc_col2tab; precalc_col1 = &precalc_errR[(colorsRGB444_packed[0]>>8)*8*16]; precalc_col2 = &precalc_errR[(colorsRGB444_packed[1]>>8)*8*16]; #define CHOICE_R58H_PERCEP(value)\ if(precalc_col1tab[value] < precalc_col2tab[value])\ block_error += precalc_col1tab[value];\ else\ block_error += precalc_col2tab[value];\ // Test all distances for (uint8 d = 0; d < 8; ++d) { block_error = 0; precalc_col1tab = &precalc_col1[d*16]; precalc_col2tab = &precalc_col2[d*16]; // Loop block /* unroll loop for(q = 0; q<16 && block_error < best_err_so_far; q++) */ CHOICE_R58H_PERCEP(0) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(1) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(2) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(3) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(4) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(5) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(6) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(7) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(8) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(9) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(10) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(11) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(12) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(13) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(14) if( block_error < best_err_so_far ) { CHOICE_R58H_PERCEP(15) } } } } } } } } } } } } } } } /* end unroll loop */ if (block_error < best_block_error) best_block_error = block_error; } return best_block_error; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Calculate a minimum error for the H-mode when doing exhaustive compression. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateErrorFromPrecalcR58H(int *colorsRGB444_packed, unsigned int *precalc_errR, unsigned int best_err_so_far) { unsigned int block_error = 0; unsigned int best_block_error = MAXIMUM_ERROR; unsigned int *precalc_col1, *precalc_col2; unsigned int *precalc_col1tab, *precalc_col2tab; precalc_col1 = &precalc_errR[(colorsRGB444_packed[0]>>8)*8*16]; precalc_col2 = &precalc_errR[(colorsRGB444_packed[1]>>8)*8*16]; #define CHOICE_R58H(value)\ if(precalc_col1tab[value] < precalc_col2tab[value])\ block_error += precalc_col1tab[value];\ else\ block_error += precalc_col2tab[value];\ // Test all distances for (uint8 d = 0; d < 8; ++d) { block_error = 0; precalc_col1tab = &precalc_col1[d*16]; precalc_col2tab = &precalc_col2[d*16]; // Loop block /* unroll loop for(q = 0; q<16 && block_error < best_err_so_far; q++) */ CHOICE_R58H(0) if( block_error < best_err_so_far ) { CHOICE_R58H(1) if( block_error < best_err_so_far ) { CHOICE_R58H(2) if( block_error < best_err_so_far ) { CHOICE_R58H(3) if( block_error < best_err_so_far ) { CHOICE_R58H(4) if( block_error < best_err_so_far ) { CHOICE_R58H(5) if( block_error < best_err_so_far ) { CHOICE_R58H(6) if( block_error < best_err_so_far ) { CHOICE_R58H(7) if( block_error < best_err_so_far ) { CHOICE_R58H(8) if( block_error < best_err_so_far ) { CHOICE_R58H(9) if( block_error < best_err_so_far ) { CHOICE_R58H(10) if( block_error < best_err_so_far ) { CHOICE_R58H(11) if( block_error < best_err_so_far ) { CHOICE_R58H(12) if( block_error < best_err_so_far ) { CHOICE_R58H(13) if( block_error < best_err_so_far ) { CHOICE_R58H(14) if( block_error < best_err_so_far ) { CHOICE_R58H(15) } } } } } } } } } } } } } } } /* end unroll loop */ if (block_error < best_block_error) best_block_error = block_error; } return best_block_error; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Calculate a minimum error for the H-mode when doing exhaustive compression. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateErrorFromPrecalcRG58Hperceptual1000(int *colorsRGB444_packed, unsigned int *precalc_errRG, unsigned int best_err_so_far) { unsigned int block_error = 0; unsigned int best_block_error = MAXIMUM_ERROR; unsigned int *precalc_col1, *precalc_col2; unsigned int *precalc_col1tab, *precalc_col2tab; precalc_col1 = &precalc_errRG[(colorsRGB444_packed[0]>>4)*8*16]; precalc_col2 = &precalc_errRG[(colorsRGB444_packed[1]>>4)*8*16]; #define CHOICE_RG58H_PERCEP(value)\ if(precalc_col1tab[value] < precalc_col2tab[value])\ block_error += precalc_col1tab[value];\ else\ block_error += precalc_col2tab[value];\ // Test all distances for (uint8 d = 0; d < 8; ++d) { block_error = 0; precalc_col1tab = &precalc_col1[d*16]; precalc_col2tab = &precalc_col2[d*16]; // Loop block /* unroll loop for(q = 0; q<16 && block_error < best_err_so_far; q++) */ CHOICE_RG58H_PERCEP(0) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(1) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(2) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(3) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(4) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(5) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(6) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(7) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(8) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(9) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(10) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(11) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(12) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(13) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(14) if( block_error < best_err_so_far ) { CHOICE_RG58H_PERCEP(15) } } } } } } } } } } } } } } } /* end unroll loop */ if (block_error < best_block_error) best_block_error = block_error; } return best_block_error; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Calculate a minimum error for the H-mode when doing exhaustive compression. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateErrorFromPrecalcRG58H(int *colorsRGB444_packed, unsigned int *precalc_errRG, unsigned int best_err_so_far) { unsigned int block_error = 0; unsigned int best_block_error = MAXIMUM_ERROR; unsigned int *precalc_col1, *precalc_col2; unsigned int *precalc_col1tab, *precalc_col2tab; precalc_col1 = &precalc_errRG[(colorsRGB444_packed[0]>>4)*8*16]; precalc_col2 = &precalc_errRG[(colorsRGB444_packed[1]>>4)*8*16]; #define CHOICE_RG58H(value)\ if(precalc_col1tab[value] < precalc_col2tab[value])\ block_error += precalc_col1tab[value];\ else\ block_error += precalc_col2tab[value];\ // Test all distances for (uint8 d = 0; d < 8; ++d) { block_error = 0; precalc_col1tab = &precalc_col1[d*16]; precalc_col2tab = &precalc_col2[d*16]; // Loop block /* unroll loop for(q = 0; q<16 && block_error < best_err_so_far; q++) */ CHOICE_RG58H(0) if( block_error < best_err_so_far ) { CHOICE_RG58H(1) if( block_error < best_err_so_far ) { CHOICE_RG58H(2) if( block_error < best_err_so_far ) { CHOICE_RG58H(3) if( block_error < best_err_so_far ) { CHOICE_RG58H(4) if( block_error < best_err_so_far ) { CHOICE_RG58H(5) if( block_error < best_err_so_far ) { CHOICE_RG58H(6) if( block_error < best_err_so_far ) { CHOICE_RG58H(7) if( block_error < best_err_so_far ) { CHOICE_RG58H(8) if( block_error < best_err_so_far ) { CHOICE_RG58H(9) if( block_error < best_err_so_far ) { CHOICE_RG58H(10) if( block_error < best_err_so_far ) { CHOICE_RG58H(11) if( block_error < best_err_so_far ) { CHOICE_RG58H(12) if( block_error < best_err_so_far ) { CHOICE_RG58H(13) if( block_error < best_err_so_far ) { CHOICE_RG58H(14) if( block_error < best_err_so_far ) { CHOICE_RG58H(15) } } } } } } } } } } } } } } } /* end unroll loop */ if (block_error < best_block_error) best_block_error = block_error; } return best_block_error; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Calculate a minimum error for the H-mode when doing exhaustive compression. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateErrorFromPrecalc58Hperceptual1000(int *colorsRGB444_packed, unsigned int *precalc_err, unsigned int total_best_err) { unsigned int block_error;\ unsigned int *precalc_col1, *precalc_col2;\ unsigned int *precalc_col1tab, *precalc_col2tab;\ unsigned int error; #define FIRSTCHOICE_RGB58H_PERCEP(value)\ if(precalc_col1tab[value] < precalc_col2tab[value])\ block_error = precalc_col1tab[value];\ else\ block_error = precalc_col2tab[value];\ #define CHOICE_RGB58H_PERCEP(value)\ if(precalc_col1tab[value] < precalc_col2tab[value])\ block_error += precalc_col1tab[value];\ else\ block_error += precalc_col2tab[value];\ #define ONETABLE_RGB58H_PERCEP(distance)\ precalc_col1tab = &precalc_col1[distance*16];\ precalc_col2tab = &precalc_col2[distance*16];\ /* unroll loop for(q = 0; q<16 && block_error < total_best_err; q++) */\ FIRSTCHOICE_RGB58H_PERCEP(0)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H_PERCEP(1)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H_PERCEP(2)\ CHOICE_RGB58H_PERCEP(3)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H_PERCEP(4)\ CHOICE_RGB58H_PERCEP(5)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H_PERCEP(6)\ CHOICE_RGB58H_PERCEP(7)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H_PERCEP(8)\ CHOICE_RGB58H_PERCEP(9)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H_PERCEP(10)\ CHOICE_RGB58H_PERCEP(11)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H_PERCEP(12)\ CHOICE_RGB58H_PERCEP(13)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H_PERCEP(14)\ CHOICE_RGB58H_PERCEP(15)\ }\ }\ }\ }\ }\ }\ }\ }\ /* end unroll loop */\ if (block_error < error)\ error = block_error;\ #define CALCULATE_ERROR_FROM_PRECALC_RGB58H_PERCEP\ error = MAXERR1000;\ precalc_col1 = &precalc_err[colorsRGB444_packed[0]*8*16];\ precalc_col2 = &precalc_err[colorsRGB444_packed[1]*8*16];\ /* Test all distances*/\ /* unroll loop for (uint8 d = 0; d < 8; ++d) */\ ONETABLE_RGB58H_PERCEP(0)\ ONETABLE_RGB58H_PERCEP(1)\ ONETABLE_RGB58H_PERCEP(2)\ ONETABLE_RGB58H_PERCEP(3)\ ONETABLE_RGB58H_PERCEP(4)\ ONETABLE_RGB58H_PERCEP(5)\ ONETABLE_RGB58H_PERCEP(6)\ ONETABLE_RGB58H_PERCEP(7)\ /* end unroll loop */\ CALCULATE_ERROR_FROM_PRECALC_RGB58H_PERCEP return error;\ } #endif #if EXHAUSTIVE_CODE_ACTIVE // Calculate a minimum error for the H-mode when doing exhaustive compression. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int calculateErrorFromPrecalc58H(int *colorsRGB444_packed, unsigned int *precalc_err, unsigned int total_best_err) { unsigned int block_error;\ unsigned int *precalc_col1, *precalc_col2;\ unsigned int *precalc_col1tab, *precalc_col2tab;\ unsigned int error; #define FIRSTCHOICE_RGB58H(value)\ if(precalc_col1tab[value] < precalc_col2tab[value])\ block_error = precalc_col1tab[value];\ else\ block_error = precalc_col2tab[value];\ #define CHOICE_RGB58H(value)\ if(precalc_col1tab[value] < precalc_col2tab[value])\ block_error += precalc_col1tab[value];\ else\ block_error += precalc_col2tab[value];\ #define ONETABLE_RGB58H(distance)\ precalc_col1tab = &precalc_col1[distance*16];\ precalc_col2tab = &precalc_col2[distance*16];\ /* unroll loop for(q = 0; q<16 && block_error < total_best_err; q++) */\ FIRSTCHOICE_RGB58H(0)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H(1)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H(2)\ CHOICE_RGB58H(3)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H(4)\ CHOICE_RGB58H(5)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H(6)\ CHOICE_RGB58H(7)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H(8)\ CHOICE_RGB58H(9)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H(10)\ CHOICE_RGB58H(11)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H(12)\ CHOICE_RGB58H(13)\ if( block_error < total_best_err)\ {\ CHOICE_RGB58H(14)\ CHOICE_RGB58H(15)\ }\ }\ }\ }\ }\ }\ }\ }\ /* end unroll loop */\ if (block_error < error)\ error = block_error;\ #define CALCULATE_ERROR_FROM_PRECALC_RGB58H\ error = MAXIMUM_ERROR;\ precalc_col1 = &precalc_err[colorsRGB444_packed[0]*8*16];\ precalc_col2 = &precalc_err[colorsRGB444_packed[1]*8*16];\ /* Test all distances*/\ /* unroll loop for (uint8 d = 0; d < 8; ++d) */\ ONETABLE_RGB58H(0)\ ONETABLE_RGB58H(1)\ ONETABLE_RGB58H(2)\ ONETABLE_RGB58H(3)\ ONETABLE_RGB58H(4)\ ONETABLE_RGB58H(5)\ ONETABLE_RGB58H(6)\ ONETABLE_RGB58H(7)\ /* end unroll loop */\ CALCULATE_ERROR_FROM_PRECALC_RGB58H return error;\ } #endif #if EXHAUSTIVE_CODE_ACTIVE // The below code should compress the block to 58 bits. // This is supposed to match the first of the three modes in TWOTIMER. // The bit layout is thought to be: // //|63 62 61 60 59 58|57 56 55 54|53 52 51 50|49 48 47 46|45 44 43 42|41 40 39 38|37 36 35 34|33 32| //|-------empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|d2 d1| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // // The distance d is three bits, d2 (MSB), d1 and d0 (LSB). d0 is not stored explicitly. // Instead if the 12-bit word red0,green0,blue0 < red1,green1,blue1, d0 is assumed to be 0. // Else, it is assumed to be 1. // The below code should compress the block to 58 bits. // This is supposed to match the first of the three modes in TWOTIMER. // The bit layout is thought to be: // //|63 62 61 60 59 58|57 56 55 54|53 52 51 50|49 48 47 46|45 44 43 42|41 40 39 38|37 36 35 34|33 32| //|-------empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|d2 d1| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // // The distance d is three bits, d2 (MSB), d1 and d0 (LSB). d0 is not stored explicitly. // Instead if the 12-bit word red0,green0,blue0 < red1,green1,blue1, d0 is assumed to be 0. // Else, it is assumed to be 1. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int compressBlockTHUMB58HExhaustivePerceptual(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2, unsigned int best_error_so_far) { unsigned int best_error_using_Hmode; uint8 best_colorsRGB444[2][3]; unsigned int best_pixel_indices; uint8 best_distance; unsigned int error; uint8 colorsRGB444[2][3]; int colorsRGB444_packed[2]; int best_colorsRGB444_packed[2]; int colorRGB444_packed; unsigned int pixel_indices; uint8 distance; unsigned int *precalc_err; // smallest error per color, table and pixel unsigned int *precalc_err_RG; // smallest pixel error for an entire table unsigned int *precalc_err_R; // smallest pixel error for an entire table uint8 block[4*4*4]; best_error_using_Hmode = MAXERR1000; precalc_err = (unsigned int*) malloc(4096*8*16*sizeof(unsigned int)); if(!precalc_err){printf("Out of memory allocating \n");exit(1);} precalc_err_RG = (unsigned int*) malloc(16*16*8*16*sizeof(unsigned int)); if(!precalc_err_RG){printf("Out of memory allocating \n");exit(1);} precalc_err_R = (unsigned int*) malloc(16*8*16*sizeof(unsigned int)); if(!precalc_err_R){printf("Out of memory allocating \n");exit(1);} unsigned int test1, test2; best_error_using_Hmode = (unsigned int)compressBlockTHUMB58HFastestPerceptual1000(img,width, height, startx, starty, test1, test2); best_colorsRGB444_packed[0] = 0; best_colorsRGB444_packed[0] = GETBITSHIGH(test1, 12, 57); best_colorsRGB444_packed[1] = 0; best_colorsRGB444_packed[1] = GETBITSHIGH(test1, 12, 45); if(best_error_using_Hmode < best_error_so_far) best_error_so_far = best_error_using_Hmode; int xx,yy,count = 0; // Use 4 bytes per pixel to make it 32-word aligned. for(xx = 0; xx<4; xx++) { for(yy=0; yy<4; yy++) { block[(count)*4] = img[((starty+yy)*width+(startx+xx))*3]; block[(count)*4+1] = img[((starty+yy)*width+(startx+xx))*3+1]; block[(count)*4+2] = img[((starty+yy)*width+(startx+xx))*3+2]; block[(count)*4+3] = 0; count++; } } for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed++) { colorsRGB444[0][0] = (colorRGB444_packed >> 8) & 0xf; colorsRGB444[0][1] = (colorRGB444_packed >> 4) & 0xf; colorsRGB444[0][2] = (colorRGB444_packed) & 0xf; precalcError58Hperceptual1000(block, colorsRGB444, colorRGB444_packed, precalc_err); } for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed+=16) { colorsRGB444[0][0] = (colorRGB444_packed >> 8) & 0xf; colorsRGB444[0][1] = (colorRGB444_packed >> 4) & 0xf; colorsRGB444[0][2] = (colorRGB444_packed) & 0xf; precalcErrorRG_58Hperceptual1000(img, width, startx, starty, colorsRGB444, colorRGB444_packed, precalc_err_RG); } for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed+=16*16) { colorsRGB444[0][0] = (colorRGB444_packed >> 8) & 0xf; colorsRGB444[0][1] = (colorRGB444_packed >> 4) & 0xf; colorsRGB444[0][2] = (colorRGB444_packed) & 0xf; precalcErrorR_58Hperceptual1000(img, width, startx, starty, colorsRGB444, colorRGB444_packed, precalc_err_R); } int trycols = 0; int allcols = 0; for( colorsRGB444[0][0] = 0; colorsRGB444[0][0] <16; colorsRGB444[0][0]++) { colorsRGB444_packed[0] = colorsRGB444[0][0]*256; for( colorsRGB444[1][0] = 0; colorsRGB444[1][0] <16; colorsRGB444[1][0]++) { colorsRGB444_packed[1] = colorsRGB444[1][0]*256; if(colorsRGB444_packed[0] <= colorsRGB444_packed[1]) { error = calculateErrorFromPrecalcR58Hperceptual1000(colorsRGB444_packed, precalc_err_R, best_error_so_far); if(error < best_error_so_far) { for( colorsRGB444[0][1] = 0; colorsRGB444[0][1] <16; colorsRGB444[0][1]++) { colorsRGB444_packed[0] = colorsRGB444[0][0]*256 + colorsRGB444[0][1]*16; for( colorsRGB444[1][1] = 0; colorsRGB444[1][1] <16; colorsRGB444[1][1]++) { colorsRGB444_packed[1] = colorsRGB444[1][0]*256 + colorsRGB444[1][1]*16; if(colorsRGB444_packed[0] <= colorsRGB444_packed[1]) { error = calculateErrorFromPrecalcRG58Hperceptual1000(colorsRGB444_packed, precalc_err_RG, best_error_so_far); if(error < best_error_so_far) { for( colorsRGB444[0][2] = 0; colorsRGB444[0][2] <16; colorsRGB444[0][2]++) { colorsRGB444_packed[0] = colorsRGB444[0][0]*256 + colorsRGB444[0][1]*16 + colorsRGB444[0][2]; for( colorsRGB444[1][2] = 0; colorsRGB444[1][2] <16; colorsRGB444[1][2]++) { colorsRGB444_packed[1] = colorsRGB444[1][0]*256 + colorsRGB444[1][1]*16 + colorsRGB444[1][2]; if(colorsRGB444_packed[0] < colorsRGB444_packed[1]) { error = calculateErrorFromPrecalc58Hperceptual1000(colorsRGB444_packed, precalc_err, best_error_so_far); if(error < best_error_so_far) { best_error_so_far = error; best_error_using_Hmode = error; best_colorsRGB444_packed[0] = colorsRGB444_packed[0]; best_colorsRGB444_packed[1] = colorsRGB444_packed[1]; } } } } } } } } } } } } best_colorsRGB444[0][0] = (best_colorsRGB444_packed[0] >> 8) & 0xf; best_colorsRGB444[0][1] = (best_colorsRGB444_packed[0] >> 4) & 0xf; best_colorsRGB444[0][2] = (best_colorsRGB444_packed[0]) & 0xf; best_colorsRGB444[1][0] = (best_colorsRGB444_packed[1] >> 8) & 0xf; best_colorsRGB444[1][1] = (best_colorsRGB444_packed[1] >> 4) & 0xf; best_colorsRGB444[1][2] = (best_colorsRGB444_packed[1]) & 0xf; free(precalc_err); free(precalc_err_RG); free(precalc_err_R); error = (unsigned int) calculateErrorAndCompress58Hperceptual1000(img, width, startx, starty, best_colorsRGB444, distance, pixel_indices); best_distance = distance; best_pixel_indices = pixel_indices; // | col0 >= col1 col0 < col1 //------------------------------------------------------ // (dist & 1) = 1 | no need to swap | need to swap // |-----------------+---------------- // (dist & 1) = 0 | need to swap | no need to swap // // This can be done with an xor test. best_colorsRGB444_packed[0] = (best_colorsRGB444[0][R] << 8) + (best_colorsRGB444[0][G] << 4) + best_colorsRGB444[0][B]; best_colorsRGB444_packed[1] = (best_colorsRGB444[1][R] << 8) + (best_colorsRGB444[1][G] << 4) + best_colorsRGB444[1][B]; if( (best_colorsRGB444_packed[0] >= best_colorsRGB444_packed[1]) ^ ((best_distance & 1)==1) ) { swapColors(best_colorsRGB444); // Reshuffle pixel indices to to exchange C1 with C3, and C2 with C4 best_pixel_indices = (0x55555555 & best_pixel_indices) | (0xaaaaaaaa & (~best_pixel_indices)); } // Put the compress params into the compression block compressed1 = 0; PUTBITSHIGH( compressed1, best_colorsRGB444[0][R], 4, 57); PUTBITSHIGH( compressed1, best_colorsRGB444[0][G], 4, 53); PUTBITSHIGH( compressed1, best_colorsRGB444[0][B], 4, 49); PUTBITSHIGH( compressed1, best_colorsRGB444[1][R], 4, 45); PUTBITSHIGH( compressed1, best_colorsRGB444[1][G], 4, 41); PUTBITSHIGH( compressed1, best_colorsRGB444[1][B], 4, 37); PUTBITSHIGH( compressed1, (best_distance >> 1), 2, 33); best_pixel_indices=indexConversion(best_pixel_indices); compressed2 = 0; PUTBITS( compressed2, best_pixel_indices, 32, 31); return best_error_using_Hmode; } #endif #if EXHAUSTIVE_CODE_ACTIVE // The below code should compress the block to 58 bits. // This is supposed to match the first of the three modes in TWOTIMER. // The bit layout is thought to be: // //|63 62 61 60 59 58|57 56 55 54|53 52 51 50|49 48 47 46|45 44 43 42|41 40 39 38|37 36 35 34|33 32| //|-------empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|d2 d1| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // // The distance d is three bits, d2 (MSB), d1 and d0 (LSB). d0 is not stored explicitly. // Instead if the 12-bit word red0,green0,blue0 < red1,green1,blue1, d0 is assumed to be 0. // Else, it is assumed to be 1. // The below code should compress the block to 58 bits. // This is supposed to match the first of the three modes in TWOTIMER. // The bit layout is thought to be: // //|63 62 61 60 59 58|57 56 55 54|53 52 51 50|49 48 47 46|45 44 43 42|41 40 39 38|37 36 35 34|33 32| //|-------empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|d2 d1| // //|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00| //|----------------------------------------index bits---------------------------------------------| // // The distance d is three bits, d2 (MSB), d1 and d0 (LSB). d0 is not stored explicitly. // Instead if the 12-bit word red0,green0,blue0 < red1,green1,blue1, d0 is assumed to be 0. // Else, it is assumed to be 1. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. unsigned int compressBlockTHUMB58HExhaustive(uint8 *img,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2, unsigned int best_error_so_far) { unsigned int best_error_using_Hmode; uint8 best_colorsRGB444[2][3]; unsigned int best_pixel_indices; uint8 best_distance; unsigned int error; uint8 colorsRGB444[2][3]; int colorsRGB444_packed[2]; int best_colorsRGB444_packed[2]; int colorRGB444_packed; unsigned int pixel_indices; uint8 distance; unsigned int *precalc_err; // smallest error per color, table and pixel unsigned int *precalc_err_RG; // smallest pixel error for an entire table unsigned int *precalc_err_R; // smallest pixel error for an entire table uint8 block[4*4*4]; best_error_using_Hmode = MAXIMUM_ERROR; precalc_err = (unsigned int*) malloc(4096*8*16*sizeof(unsigned int)); if(!precalc_err){printf("Out of memory allocating \n");exit(1);} precalc_err_RG = (unsigned int*) malloc(16*16*8*16*sizeof(unsigned int)); if(!precalc_err_RG){printf("Out of memory allocating \n");exit(1);} precalc_err_R = (unsigned int*) malloc(16*8*16*sizeof(unsigned int)); if(!precalc_err_R){printf("Out of memory allocating \n");exit(1);} unsigned int test1, test2; best_error_using_Hmode = (unsigned int)compressBlockTHUMB58HFastest(img,width, height, startx, starty, test1, test2); best_colorsRGB444_packed[0] = 0; best_colorsRGB444_packed[0] = GETBITSHIGH(test1, 12, 57); best_colorsRGB444_packed[1] = 0; best_colorsRGB444_packed[1] = GETBITSHIGH(test1, 12, 45); if(best_error_using_Hmode < best_error_so_far) best_error_so_far = best_error_using_Hmode; int xx,yy,count = 0; // Reshuffle pixels so that the top left 2x2 pixels arrive first, then the top right 2x2 pixels etc. Also put use 4 bytes per pixel to make it 32-word aligned. for(xx = 0; xx<4; xx++) { for(yy=0; yy<4; yy++) { block[(count)*4] = img[((starty+yy)*width+(startx+xx))*3]; block[(count)*4+1] = img[((starty+yy)*width+(startx+xx))*3+1]; block[(count)*4+2] = img[((starty+yy)*width+(startx+xx))*3+2]; block[(count)*4+3] = 0; count++; } } for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed++) { colorsRGB444[0][0] = (colorRGB444_packed >> 8) & 0xf; colorsRGB444[0][1] = (colorRGB444_packed >> 4) & 0xf; colorsRGB444[0][2] = (colorRGB444_packed) & 0xf; precalcError58H(block, colorsRGB444, colorRGB444_packed, precalc_err); } for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed+=16) { colorsRGB444[0][0] = (colorRGB444_packed >> 8) & 0xf; colorsRGB444[0][1] = (colorRGB444_packed >> 4) & 0xf; colorsRGB444[0][2] = (colorRGB444_packed) & 0xf; precalcErrorRG_58H(img, width, startx, starty, colorsRGB444, colorRGB444_packed, precalc_err_RG); } for( colorRGB444_packed = 0; colorRGB444_packed<16*16*16; colorRGB444_packed+=16*16) { colorsRGB444[0][0] = (colorRGB444_packed >> 8) & 0xf; colorsRGB444[0][1] = (colorRGB444_packed >> 4) & 0xf; colorsRGB444[0][2] = (colorRGB444_packed) & 0xf; precalcErrorR_58H(img, width, startx, starty, colorsRGB444, colorRGB444_packed, precalc_err_R); } int trycols = 0; int allcols = 0; for( colorsRGB444[0][0] = 0; colorsRGB444[0][0] <16; colorsRGB444[0][0]++) { colorsRGB444_packed[0] = colorsRGB444[0][0]*256; for( colorsRGB444[1][0] = 0; colorsRGB444[1][0] <16; colorsRGB444[1][0]++) { colorsRGB444_packed[1] = colorsRGB444[1][0]*256; if(colorsRGB444_packed[0] <= colorsRGB444_packed[1]) { error = calculateErrorFromPrecalcR58H(colorsRGB444_packed, precalc_err_R, best_error_so_far); if(error < best_error_so_far) { for( colorsRGB444[0][1] = 0; colorsRGB444[0][1] <16; colorsRGB444[0][1]++) { colorsRGB444_packed[0] = colorsRGB444[0][0]*256 + colorsRGB444[0][1]*16; for( colorsRGB444[1][1] = 0; colorsRGB444[1][1] <16; colorsRGB444[1][1]++) { colorsRGB444_packed[1] = colorsRGB444[1][0]*256 + colorsRGB444[1][1]*16; if(colorsRGB444_packed[0] <= colorsRGB444_packed[1]) { error = calculateErrorFromPrecalcRG58H(colorsRGB444_packed, precalc_err_RG, best_error_so_far); if(error < best_error_so_far) { for( colorsRGB444[0][2] = 0; colorsRGB444[0][2] <16; colorsRGB444[0][2]++) { colorsRGB444_packed[0] = colorsRGB444[0][0]*256 + colorsRGB444[0][1]*16 + colorsRGB444[0][2]; for( colorsRGB444[1][2] = 0; colorsRGB444[1][2] <16; colorsRGB444[1][2]++) { colorsRGB444_packed[1] = colorsRGB444[1][0]*256 + colorsRGB444[1][1]*16 + colorsRGB444[1][2]; if(colorsRGB444_packed[0] < colorsRGB444_packed[1]) { error = calculateErrorFromPrecalc58H(colorsRGB444_packed, precalc_err, best_error_so_far); if(error < best_error_so_far) { best_error_so_far = error; best_error_using_Hmode = error; best_colorsRGB444_packed[0] = colorsRGB444_packed[0]; best_colorsRGB444_packed[1] = colorsRGB444_packed[1]; } } } } } } } } } } } } best_colorsRGB444[0][0] = (best_colorsRGB444_packed[0] >> 8) & 0xf; best_colorsRGB444[0][1] = (best_colorsRGB444_packed[0] >> 4) & 0xf; best_colorsRGB444[0][2] = (best_colorsRGB444_packed[0]) & 0xf; best_colorsRGB444[1][0] = (best_colorsRGB444_packed[1] >> 8) & 0xf; best_colorsRGB444[1][1] = (best_colorsRGB444_packed[1] >> 4) & 0xf; best_colorsRGB444[1][2] = (best_colorsRGB444_packed[1]) & 0xf; free(precalc_err); free(precalc_err_RG); free(precalc_err_R); error = (unsigned int) calculateErrorAndCompress58H(img, width, startx, starty, best_colorsRGB444, distance, pixel_indices); best_distance = distance; best_pixel_indices = pixel_indices; // | col0 >= col1 col0 < col1 //------------------------------------------------------ // (dist & 1) = 1 | no need to swap | need to swap // |-----------------+---------------- // (dist & 1) = 0 | need to swap | no need to swap // // This can be done with an xor test. best_colorsRGB444_packed[0] = (best_colorsRGB444[0][R] << 8) + (best_colorsRGB444[0][G] << 4) + best_colorsRGB444[0][B]; best_colorsRGB444_packed[1] = (best_colorsRGB444[1][R] << 8) + (best_colorsRGB444[1][G] << 4) + best_colorsRGB444[1][B]; if( (best_colorsRGB444_packed[0] >= best_colorsRGB444_packed[1]) ^ ((best_distance & 1)==1) ) { swapColors(best_colorsRGB444); // Reshuffle pixel indices to to exchange C1 with C3, and C2 with C4 best_pixel_indices = (0x55555555 & best_pixel_indices) | (0xaaaaaaaa & (~best_pixel_indices)); } // Put the compress params into the compression block compressed1 = 0; PUTBITSHIGH( compressed1, best_colorsRGB444[0][R], 4, 57); PUTBITSHIGH( compressed1, best_colorsRGB444[0][G], 4, 53); PUTBITSHIGH( compressed1, best_colorsRGB444[0][B], 4, 49); PUTBITSHIGH( compressed1, best_colorsRGB444[1][R], 4, 45); PUTBITSHIGH( compressed1, best_colorsRGB444[1][G], 4, 41); PUTBITSHIGH( compressed1, best_colorsRGB444[1][B], 4, 37); PUTBITSHIGH( compressed1, (best_distance >> 1), 2, 33); best_pixel_indices=indexConversion(best_pixel_indices); compressed2 = 0; PUTBITS( compressed2, best_pixel_indices, 32, 31); return best_error_using_Hmode; } #endif #if EXHAUSTIVE_CODE_ACTIVE // Compress a block exhaustively for the ETC1 codec. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressBlockETC1Exhaustive(uint8 *img, uint8 *imgdec,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { unsigned int error_currently_best; unsigned int etc1_differential_word1; unsigned int etc1_differential_word2; unsigned int error_etc1_differential; unsigned int etc1_individual_word1; unsigned int etc1_individual_word2; unsigned int error_etc1_individual; unsigned int error_best; signed char best_char; int best_mode; error_currently_best = 255*255*16*3; // First pass -- quickly find a low error so that we can later cull away a lot of // calculations later that are guaranteed to be higher than that error. unsigned int error_etc1; unsigned int etc1_word1; unsigned int etc1_word2; error_etc1 = (unsigned int) compressBlockDiffFlipFast(img, imgdec, width, height, startx, starty, etc1_word1, etc1_word2); if(error_etc1 < error_currently_best) error_currently_best = error_etc1; error_etc1_individual = compressBlockIndividualExhaustive(img, width, height, startx, starty, etc1_individual_word1, etc1_individual_word2, error_currently_best); if(error_etc1_individual < error_currently_best) error_currently_best = error_etc1_individual; error_etc1_differential = compressBlockDifferentialExhaustive(img, width, height, startx, starty, etc1_differential_word1, etc1_differential_word2, error_currently_best); if(error_etc1_differential < error_currently_best) error_currently_best = error_etc1_differential; error_best = error_etc1_differential; compressed1 = etc1_differential_word1; compressed2 = etc1_differential_word2; best_char = '.'; best_mode = MODE_ETC1; if(error_etc1_individual < error_best) { compressed1 = etc1_individual_word1; compressed2 = etc1_individual_word2; best_char = ','; error_best = error_etc1_individual; best_mode = MODE_ETC1; } if(error_etc1 < error_best) { compressed1 = etc1_word1; compressed2 = etc1_word2; best_char = '.'; error_best = error_etc1; best_mode = MODE_ETC1; } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Compress a block exhaustively for the ETC1 codec using perceptual error measure. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressBlockETC1ExhaustivePerceptual(uint8 *img, uint8 *imgdec,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { unsigned int error_currently_best; unsigned int etc1_differential_word1; unsigned int etc1_differential_word2; unsigned int error_etc1_differential; unsigned int etc1_individual_word1; unsigned int etc1_individual_word2; unsigned int error_etc1_individual; unsigned int error_best; signed char best_char; int best_mode; error_currently_best = 255*255*16*1000; // First pass -- quickly find a low error so that we can later cull away a lot of // calculations later that are guaranteed to be higher than that error. unsigned int error_etc1; unsigned int etc1_word1; unsigned int etc1_word2; compressBlockDiffFlipFastPerceptual(img, imgdec, width, height, startx, starty, etc1_word1, etc1_word2); decompressBlockDiffFlip(etc1_word1, etc1_word2, imgdec, width, height, startx, starty); error_etc1 = 1000*calcBlockPerceptualErrorRGB(img, imgdec, width, height, startx, starty); if(error_etc1 < error_currently_best) error_currently_best = error_etc1; // Second pass --- now find the lowest error, but only if it is lower than error_currently_best error_etc1_differential = compressBlockDifferentialExhaustivePerceptual(img, width, height, startx, starty, etc1_differential_word1, etc1_differential_word2, error_currently_best); if(error_etc1_differential < error_currently_best) error_currently_best = error_etc1_differential; error_etc1_individual = compressBlockIndividualExhaustivePerceptual(img, width, height, startx, starty, etc1_individual_word1, etc1_individual_word2, error_currently_best); if(error_etc1_individual < error_currently_best) error_currently_best = error_etc1_individual; // Now find the best error. error_best = error_etc1; compressed1 = etc1_word1; compressed2 = etc1_word2; best_char = '.'; best_mode = MODE_ETC1; if(error_etc1_differential < error_best) { error_best = error_etc1_differential; compressed1 = etc1_differential_word1; compressed2 = etc1_differential_word2; best_char = '.'; best_mode = MODE_ETC1; } if(error_etc1_individual < error_best) { compressed1 = etc1_individual_word1; compressed2 = etc1_individual_word2; best_char = ','; error_best = error_etc1_individual; best_mode = MODE_ETC1; } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Compress a block exhaustively for the ETC2 RGB codec using perceptual error measure. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressBlockETC2ExhaustivePerceptual(uint8 *img, uint8 *imgdec,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { unsigned int error_currently_best; unsigned int etc1_differential_word1; unsigned int etc1_differential_word2; unsigned int error_etc1_differential; unsigned int etc1_individual_word1; unsigned int etc1_individual_word2; unsigned int error_etc1_individual; unsigned int planar57_word1; unsigned int planar57_word2; unsigned int planar_word1; unsigned int planar_word2; double error_planar; unsigned int error_planar_red, error_planar_green, error_planar_blue; unsigned int thumbH58_word1; unsigned int thumbH58_word2; unsigned int thumbH_word1; unsigned int thumbH_word2; unsigned int error_thumbH; unsigned int thumbT59_word1; unsigned int thumbT59_word2; unsigned int thumbT_word1; unsigned int thumbT_word2; unsigned int error_thumbT; unsigned int error_best; signed char best_char; int best_mode; error_currently_best = 255*255*16*1000; // First pass -- quickly find a low error so that we can later cull away a lot of // calculations later that are guaranteed to be higher than that error. unsigned int error_etc1; unsigned int etc1_word1; unsigned int etc1_word2; compressBlockDiffFlipFastPerceptual(img, imgdec, width, height, startx, starty, etc1_word1, etc1_word2); decompressBlockDiffFlip(etc1_word1, etc1_word2, imgdec, width, height, startx, starty); error_etc1 = 1000*calcBlockPerceptualErrorRGB(img, imgdec, width, height, startx, starty); if(error_etc1 < error_currently_best) error_currently_best = error_etc1; // The planar mode treats every channel independently and should not be affected by the weights in the error measure. // We can hence use the nonperceptual version of the encoder also to find the best perceptual description of the block. compressBlockPlanar57(img, width, height, startx, starty, planar57_word1, planar57_word2); decompressBlockPlanar57errorPerComponent(planar57_word1, planar57_word2, imgdec, width, height, startx, starty, img, error_planar_red, error_planar_green, error_planar_blue); error_planar = 1000*calcBlockPerceptualErrorRGB(img, imgdec, width, height, startx, starty); stuff57bits(planar57_word1, planar57_word2, planar_word1, planar_word2); if(error_planar < error_currently_best) error_currently_best = (unsigned int) error_planar; error_thumbT = (unsigned int) compressBlockTHUMB59TFastestPerceptual1000(img,width, height, startx, starty, thumbT59_word1, thumbT59_word2); stuff59bits(thumbT59_word1, thumbT59_word2, thumbT_word1, thumbT_word2); if(error_thumbT < error_currently_best) error_currently_best = error_thumbT; error_thumbH = (unsigned int) compressBlockTHUMB58HFastestPerceptual1000(img,width,height,startx, starty, thumbH58_word1, thumbH58_word2); stuff58bits(thumbH58_word1, thumbH58_word2, thumbH_word1, thumbH_word2); if(error_thumbH < error_currently_best) error_currently_best = error_thumbH; // Second pass --- now find the lowest error, but only if it is lower than error_currently_best // Correct the individual errors for the different planes so that they sum to 1000 instead of 1. error_planar_red *=PERCEPTUAL_WEIGHT_R_SQUARED_TIMES1000; error_planar_green *=PERCEPTUAL_WEIGHT_G_SQUARED_TIMES1000; error_planar_blue *=PERCEPTUAL_WEIGHT_B_SQUARED_TIMES1000; compressBlockPlanar57ExhaustivePerceptual(img, width, height, startx, starty, planar57_word1, planar57_word2, error_currently_best, error_planar_red, error_planar_green, error_planar_blue); decompressBlockPlanar57(planar57_word1, planar57_word2, imgdec, width, height, startx, starty); error_planar = 1000*calcBlockPerceptualErrorRGB(img, imgdec, width, height, startx, starty); stuff57bits(planar57_word1, planar57_word2, planar_word1, planar_word2); if(error_planar < error_currently_best) error_currently_best = (unsigned int) error_planar; error_etc1_differential = compressBlockDifferentialExhaustivePerceptual(img, width, height, startx, starty, etc1_differential_word1, etc1_differential_word2, error_currently_best); if(error_etc1_differential < error_currently_best) error_currently_best = error_etc1_differential; error_etc1_individual = compressBlockIndividualExhaustivePerceptual(img, width, height, startx, starty, etc1_individual_word1, etc1_individual_word2, error_currently_best); if(error_etc1_individual < error_currently_best) error_currently_best = error_etc1_individual; error_thumbH = compressBlockTHUMB58HExhaustivePerceptual(img,width,height,startx, starty, thumbH58_word1, thumbH58_word2, error_currently_best); stuff58bits(thumbH58_word1, thumbH58_word2, thumbH_word1, thumbH_word2); if( error_thumbH < error_currently_best) error_currently_best = error_thumbH; error_thumbT = compressBlockTHUMB59TExhaustivePerceptual(img,width, height, startx, starty, thumbT59_word1, thumbT59_word2, error_currently_best); stuff59bits(thumbT59_word1, thumbT59_word2, thumbT_word1, thumbT_word2); if(error_thumbT < error_currently_best) error_currently_best = error_thumbT; // Now find the best error. error_best = error_etc1; compressed1 = etc1_word1; compressed2 = etc1_word2; best_char = '.'; best_mode = MODE_ETC1; if(error_etc1_differential < error_best) { error_best = error_etc1_differential; compressed1 = etc1_differential_word1; compressed2 = etc1_differential_word2; best_char = '.'; best_mode = MODE_ETC1; } if(error_etc1_individual < error_best) { compressed1 = etc1_individual_word1; compressed2 = etc1_individual_word2; best_char = ','; error_best = error_etc1_individual; best_mode = MODE_ETC1; } if(error_planar < error_best) { compressed1 = planar_word1; compressed2 = planar_word2; best_char = 'p'; error_best = (unsigned int) error_planar; best_mode = MODE_PLANAR; } if(error_thumbH < error_best) { compressed1 = thumbH_word1; compressed2 = thumbH_word2; best_char = 'H'; error_best = error_thumbH; best_mode = MODE_THUMB_H; } if(error_thumbT < error_best) { compressed1 = thumbT_word1; compressed2 = thumbT_word2; best_char = 'T'; error_best = error_thumbT; best_mode = MODE_THUMB_T; } } #endif #if EXHAUSTIVE_CODE_ACTIVE // Compress a block exhaustively for the ETC2 RGB codec. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressBlockETC2Exhaustive(uint8 *img, uint8 *imgdec,int width,int height,int startx,int starty, unsigned int &compressed1, unsigned int &compressed2) { unsigned int error_currently_best; unsigned int etc1_differential_word1; unsigned int etc1_differential_word2; unsigned int error_etc1_differential; unsigned int etc1_individual_word1; unsigned int etc1_individual_word2; unsigned int error_etc1_individual; unsigned int planar57_word1; unsigned int planar57_word2; unsigned int planar_word1; unsigned int planar_word2; double error_planar; unsigned int error_planar_red; unsigned int error_planar_green; unsigned int error_planar_blue; unsigned int thumbH58_word1; unsigned int thumbH58_word2; unsigned int thumbH_word1; unsigned int thumbH_word2; unsigned int error_thumbH; unsigned int thumbT59_word1; unsigned int thumbT59_word2; unsigned int thumbT_word1; unsigned int thumbT_word2; unsigned int error_thumbT; unsigned int error_best; signed char best_char; int best_mode; error_currently_best = 255*255*16*3; // First pass -- quickly find a low error so that we can later cull away a lot of // calculations later that are guaranteed to be higher than that error. unsigned int error_etc1; unsigned int etc1_word1; unsigned int etc1_word2; error_etc1 = (unsigned int) compressBlockDiffFlipFast(img, imgdec, width, height, startx, starty, etc1_word1, etc1_word2); if(error_etc1 < error_currently_best) error_currently_best = error_etc1; compressBlockPlanar57(img, width, height, startx, starty, planar57_word1, planar57_word2); decompressBlockPlanar57errorPerComponent(planar57_word1, planar57_word2, imgdec, width, height, startx, starty, img, error_planar_red, error_planar_green, error_planar_blue); error_planar = calcBlockErrorRGB(img, imgdec, width, height, startx, starty); stuff57bits(planar57_word1, planar57_word2, planar_word1, planar_word2); if(error_planar < error_currently_best) error_currently_best = (unsigned int) error_planar; error_thumbT = (unsigned int) compressBlockTHUMB59TFastest(img,width, height, startx, starty, thumbT59_word1, thumbT59_word2); stuff59bits(thumbT59_word1, thumbT59_word2, thumbT_word1, thumbT_word2); if(error_thumbT < error_currently_best) error_currently_best = error_thumbT; error_thumbH = (unsigned int) compressBlockTHUMB58HFastest(img,width,height,startx, starty, thumbH58_word1, thumbH58_word2); stuff58bits(thumbH58_word1, thumbH58_word2, thumbH_word1, thumbH_word2); if(error_thumbH < error_currently_best) error_currently_best = error_thumbH; // Second pass --- now find the lowest error, but only if it is lower than error_currently_best error_etc1_differential = compressBlockDifferentialExhaustive(img, width, height, startx, starty, etc1_differential_word1, etc1_differential_word2, error_currently_best); if(error_etc1_differential < error_currently_best) error_currently_best = error_etc1_differential; compressBlockPlanar57Exhaustive(img, width, height, startx, starty, planar57_word1, planar57_word2, error_currently_best, error_planar_red, error_planar_green, error_planar_blue); decompressBlockPlanar57(planar57_word1, planar57_word2, imgdec, width, height, startx, starty); error_planar = calcBlockErrorRGB(img, imgdec, width, height, startx, starty); stuff57bits(planar57_word1, planar57_word2, planar_word1, planar_word2); if(error_planar < error_currently_best) error_currently_best = (unsigned int) error_planar; error_etc1_individual = compressBlockIndividualExhaustive(img, width, height, startx, starty, etc1_individual_word1, etc1_individual_word2, error_currently_best); if(error_etc1_individual < error_currently_best) error_currently_best = error_etc1_individual; error_thumbH = compressBlockTHUMB58HExhaustive(img,width,height,startx, starty, thumbH58_word1, thumbH58_word2, error_currently_best); if( error_thumbH < error_currently_best) error_currently_best = error_thumbH; stuff58bits(thumbH58_word1, thumbH58_word2, thumbH_word1, thumbH_word2); error_thumbT = compressBlockTHUMB59TExhaustive(img,width, height, startx, starty, thumbT59_word1, thumbT59_word2, error_currently_best); if(error_thumbT < error_currently_best) error_currently_best = error_thumbT; stuff59bits(thumbT59_word1, thumbT59_word2, thumbT_word1, thumbT_word2); error_best = 255*255*3*16; // Now find the best error. error_best = error_etc1; compressed1 = etc1_word1; compressed2 = etc1_word2; best_char = '.'; best_mode = MODE_ETC1; if(error_etc1_differential < error_best) { error_best = error_etc1_differential; compressed1 = etc1_differential_word1; compressed2 = etc1_differential_word2; best_char = '.'; best_mode = MODE_ETC1; } if(error_etc1_individual < error_best) { compressed1 = etc1_individual_word1; compressed2 = etc1_individual_word2; best_char = ','; error_best = error_etc1_individual; best_mode = MODE_ETC1; } if(error_planar < error_best) { compressed1 = planar_word1; compressed2 = planar_word2; best_char = 'p'; error_best = (unsigned int) error_planar; best_mode = MODE_PLANAR; } if(error_thumbH < error_best) { compressed1 = thumbH_word1; compressed2 = thumbH_word2; best_char = 'H'; error_best = error_thumbH; best_mode = MODE_THUMB_H; } if(error_thumbT < error_best) { compressed1 = thumbT_word1; compressed2 = thumbT_word2; best_char = 'T'; error_best = error_thumbT; best_mode = MODE_THUMB_T; } } #endif //// Exhaustive code ends here. // Compress an image file. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressImageFile(uint8 *img, uint8 *alphaimg,int width,int height,char *dstfile, int expandedwidth, int expandedheight) { FILE *f; int x,y,w,h; unsigned int block1, block2; unsigned short wi, hi; unsigned char magic[4]; unsigned char version[2]; unsigned short texture_type=format; uint8 *imgdec; uint8* alphaimg2; imgdec = (unsigned char*) malloc(expandedwidth*expandedheight*3); if(!imgdec) { printf("Could not allocate decompression buffer --- exiting\n"); } magic[0] = 'P'; magic[1] = 'K'; magic[2] = 'M'; magic[3] = ' '; if(codec==CODEC_ETC2) { version[0] = '2'; version[1] = '0'; } else { version[0] = '1'; version[1] = '0'; } if(f=fopen(dstfile,"wb")) { w=expandedwidth/4; w*=4; h=expandedheight/4; h*=4; wi = w; hi = h; if(ktxFile) { //.ktx file: KTX header followed by compressed binary data. KTX_header header; //identifier for(int i=0; i<12; i++) { header.identifier[i]=ktx_identifier[i]; } //endianess int.. if this comes out reversed, all of the other ints will too. header.endianness=KTX_ENDIAN_REF; //these values are always 0/1 for compressed textures. header.glType=0; header.glTypeSize=1; header.glFormat=0; header.pixelWidth=width; header.pixelHeight=height; header.pixelDepth=0; //we only support single non-mipmapped non-cubemap textures.. header.numberOfArrayElements=0; header.numberOfFaces=1; header.numberOfMipmapLevels=1; //and no metadata.. header.bytesOfKeyValueData=0; int halfbytes=1; //header.glInternalFormat=? //header.glBaseInternalFormat=? if(format==ETC2PACKAGE_R_NO_MIPMAPS) { header.glBaseInternalFormat=GL_R; if(formatSigned) header.glInternalFormat=GL_COMPRESSED_SIGNED_R11_EAC; else header.glInternalFormat=GL_COMPRESSED_R11_EAC; } else if(format==ETC2PACKAGE_RG_NO_MIPMAPS) { halfbytes=2; header.glBaseInternalFormat=GL_RG; if(formatSigned) header.glInternalFormat=GL_COMPRESSED_SIGNED_RG11_EAC; else header.glInternalFormat=GL_COMPRESSED_RG11_EAC; } else if(format==ETC2PACKAGE_RGB_NO_MIPMAPS) { header.glBaseInternalFormat=GL_RGB; header.glInternalFormat=GL_COMPRESSED_RGB8_ETC2; } else if(format==ETC2PACKAGE_sRGB_NO_MIPMAPS) { header.glBaseInternalFormat=GL_SRGB; header.glInternalFormat=GL_COMPRESSED_SRGB8_ETC2; } else if(format==ETC2PACKAGE_RGBA_NO_MIPMAPS) { halfbytes=2; header.glBaseInternalFormat=GL_RGBA; header.glInternalFormat=GL_COMPRESSED_RGBA8_ETC2_EAC; } else if(format==ETC2PACKAGE_sRGBA_NO_MIPMAPS) { halfbytes=2; header.glBaseInternalFormat=GL_SRGB8_ALPHA8; header.glInternalFormat=GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; } else if(format==ETC2PACKAGE_RGBA1_NO_MIPMAPS) { header.glBaseInternalFormat=GL_RGBA; header.glInternalFormat=GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; } else if(format==ETC2PACKAGE_sRGBA1_NO_MIPMAPS) { header.glBaseInternalFormat=GL_SRGB8_ALPHA8; header.glInternalFormat=GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2; } else if(format==ETC1_RGB_NO_MIPMAPS) { header.glBaseInternalFormat=GL_RGB; header.glInternalFormat=GL_ETC1_RGB8_OES; } else { printf("internal error: bad format!\n"); exit(1); } //write header fwrite(&header,sizeof(KTX_header),1,f); //write size of compressed data.. which depend on the expanded size.. unsigned int imagesize=(w*h*halfbytes)/2; fwrite(&imagesize,sizeof(int),1,f); } else { //.pkm file, contains small header.. // Write magic number fwrite(&magic[0], sizeof(unsigned char), 1, f); fwrite(&magic[1], sizeof(unsigned char), 1, f); fwrite(&magic[2], sizeof(unsigned char), 1, f); fwrite(&magic[3], sizeof(unsigned char), 1, f); // Write version fwrite(&version[0], sizeof(unsigned char), 1, f); fwrite(&version[1], sizeof(unsigned char), 1, f); // Write texture type if(texture_type==ETC2PACKAGE_RG_NO_MIPMAPS&&formatSigned) { unsigned short temp = ETC2PACKAGE_RG_SIGNED_NO_MIPMAPS; write_big_endian_2byte_word(&temp,f); } else if(texture_type==ETC2PACKAGE_R_NO_MIPMAPS&&formatSigned) { unsigned short temp = ETC2PACKAGE_R_SIGNED_NO_MIPMAPS; write_big_endian_2byte_word(&temp,f); } else write_big_endian_2byte_word(&texture_type, f); // Write binary header: the width and height as unsigned 16-bit words write_big_endian_2byte_word(&wi, f); write_big_endian_2byte_word(&hi, f); // Also write the active pixels. For instance, if we want to compress // a 128 x 129 image, we have to extend it to 128 x 132 pixels. // Then the wi and hi written above will be 128 and 132, but the // additional information that we write below will be 128 and 129, // to indicate that it is only the top 129 lines of data in the // decompressed image that will be valid data, and the rest will // be just garbage. unsigned short activew, activeh; activew = width; activeh = height; write_big_endian_2byte_word(&activew, f); write_big_endian_2byte_word(&activeh, f); } int totblocks = expandedheight/4 * expandedwidth/4; int countblocks = 0; double percentageblocks=-1.0; double oldpercentageblocks; if(format==ETC2PACKAGE_RG_NO_MIPMAPS) { //extract data from red and green channel into two alpha channels. //note that the image will be 16-bit per channel in this case. alphaimg= (unsigned char*)malloc(expandedwidth*expandedheight*2); alphaimg2=(unsigned char*)malloc(expandedwidth*expandedheight*2); setupAlphaTableAndValtab(); if(!alphaimg||!alphaimg2) { printf("failed allocating space for alpha buffers!\n"); exit(1); } for(y=0;y.\n",dstfile); } } #if 0 // Compress an file. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. void compressFile(char *srcfile,char *dstfile) { uint8 *srcimg; int width,height; int extendedwidth, extendedheight; struct _timeb tstruct; int tstart; int tstop; // 0: compress from .any to .pkm with SPEED_FAST, METRIC_NONPERCEPTUAL, ETC // 1: compress from .any to .pkm with SPEED_MEDIUM, METRIC_NONPERCEPTUAL, ETC // 2: compress from .any to .pkm with SPEED_SLOW, METRIC_NONPERCEPTUAL, ETC // 3: compress from .any to .pkm with SPEED_FAST, METRIC_PERCEPTUAL, ETC // 4: compress from .any to .pkm with SPEED_MEDIUM, METRIC_PERCEPTUAL, ETC // 5: compress from .any to .pkm with SPEED_SLOW, METRIC_PERCEPTUAL, ETC // 6: decompress from .pkm to .any // 7: calculate PSNR between .any and .any // 8: compress from .any to .pkm with SPEED_FAST, METRIC_NONPERCEPTUAL, ETC2 // 9: compress from .any to .pkm with SPEED_MEDIUM, METRIC_NONPERCEPTUAL, ETC2 //10: compress from .any to .pkm with SPEED_SLOW, METRIC_NONPERCEPTUAL, ETC2 //11: compress from .any to .pkm with SPEED_FAST, METRIC_PERCEPTUAL, ETC2 //12: compress from .any to .pkm with SPEED_MEDIUM, METRIC_PERCEPTUAL, ETC2 //13: compress from .any to .pkm with SPEED_SLOW, METRIC_PERCEPTUAL, ETC2 printf("\n"); if(codec==CODEC_ETC) printf("ETC codec, "); else printf("ETC2 codec, "); if(speed==SPEED_FAST) printf("using FAST compression mode and "); else if(speed==SPEED_MEDIUM) printf("using MEDIUM compression mode and "); else printf("using SLOW compression mode and "); if(metric==METRIC_PERCEPTUAL) printf("PERCEPTUAL error metric, "); else printf("NONPERCEPTUAL error metric, "); if(format==ETC2PACKAGE_RGBA_NO_MIPMAPS) printf("in RGBA format"); else if(format==ETC2PACKAGE_sRGBA_NO_MIPMAPS) printf("in sRGBA format"); else if(format==ETC2PACKAGE_RGBA1_NO_MIPMAPS) printf("in RGB + punch-through alpha format"); else if(format==ETC2PACKAGE_sRGBA1_NO_MIPMAPS) printf("in sRGB + punch-through alpha format"); else if(format==ETC2PACKAGE_R_NO_MIPMAPS) printf("in R format"); else if(format==ETC2PACKAGE_RGB_NO_MIPMAPS||format==ETC1_RGB_NO_MIPMAPS) printf("in RGB format"); else if(format==ETC2PACKAGE_RG_NO_MIPMAPS) printf("in RG format"); else printf("in OTHER format"); printf("\n"); if(readCompressParams()) { if(format==ETC2PACKAGE_R_NO_MIPMAPS||readSrcFile(srcfile,srcimg,width,height,extendedwidth, extendedheight)) { //make sure that alphasrcimg contains the alpha channel or is null here, and pass it to compressimagefile uint8* alphaimg=NULL; if(format==ETC2PACKAGE_RGBA_NO_MIPMAPS||format==ETC2PACKAGE_RGBA1_NO_MIPMAPS||format==ETC2PACKAGE_sRGBA_NO_MIPMAPS||format==ETC2PACKAGE_sRGBA1_NO_MIPMAPS) { char str[300]; //printf("reading alpha channel...."); sprintf(str,"imconv %s -alpha extract alpha.pgm\n",srcfile); system(str); readAlpha(alphaimg,width,height,extendedwidth,extendedheight); printf("ok!\n"); setupAlphaTableAndValtab(); } else if(format==ETC2PACKAGE_R_NO_MIPMAPS) { char str[300]; sprintf(str,"imconv %s alpha.pgm\n",srcfile); system(str); readAlpha(alphaimg,width,height,extendedwidth,extendedheight); printf("read alpha ok, size is %d,%d (%d,%d)",width,height,extendedwidth,extendedheight); setupAlphaTableAndValtab(); } printf("Compressing...\n"); tstart=time(NULL); _ftime( &tstruct ); tstart=tstart*1000+tstruct.millitm; compressImageFile(srcimg,alphaimg,width,height,dstfile,extendedwidth, extendedheight); tstop = time(NULL); _ftime( &tstruct ); tstop = tstop*1000+tstruct.millitm; printf( "It took %u milliseconds to compress:\n", tstop - tstart); calculatePSNRfile(dstfile,srcimg,alphaimg); } } } // Calculates the PSNR between two files. // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. double calculatePSNRTwoFiles(char *srcfile1,char *srcfile2) { uint8 *srcimg1; uint8 *srcimg2; int width1, height1; int width2, height2; double PSNR; double perceptually_weighted_PSNR; if(readSrcFileNoExpand(srcfile1,srcimg1,width1,height1)) { if(readSrcFileNoExpand(srcfile2,srcimg2,width2,height2)) { if((width1 == width2) && (height1 == height2)) { PSNR = calculatePSNR(srcimg1, srcimg2, width1, height1); printf("%f\n",PSNR); perceptually_weighted_PSNR = calculateWeightedPSNR(srcimg1, srcimg2, width1, height1, 0.299, 0.587, 0.114); } else { printf("\n Width and height do no not match for image: width, height = (%d, %d) and (%d, %d)\n",width1,height1, width2, height2); } } else { printf("Couldn't open file %s.\n",srcfile2); } } else { printf("Couldn't open file %s.\n",srcfile1); } return PSNR; } // Main function // NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved. int main(int argc,char *argv[]) { if(argc==3 || argc==4 || argc == 5 || argc == 7 || argc == 9 || argc == 11 || argc == 13) { // The source file is always the second last one. char srcfile[200]; char dstfile[200]; readArguments(argc,argv,srcfile,dstfile); int q = find_pos_of_extension(srcfile); int q2 = find_pos_of_extension(dstfile); if(!fileExist(srcfile)) { printf("Error: file <%s> does not exist.\n",srcfile); exit(0); } if(mode==MODE_UNCOMPRESS) { printf("Decompressing .pkm/.ktx file ...\n"); uint8* alphaimg=NULL, *img; int w, h; uncompressFile(srcfile,img,alphaimg,w,h); writeOutputFile(dstfile,img,alphaimg,w,h); } else if(mode==MODE_PSNR) { calculatePSNRTwoFiles(srcfile,dstfile); } else { compressFile(srcfile, dstfile); } } else { printf("ETCPACK v2.74 For ETC and ETC2\n"); printf("Compresses and decompresses images using the Ericsson Texture Compression (ETC) version 1.0 and 2.0.\n\nUsage: etcpack srcfile dstfile\n\n"); printf(" -s {fast|slow} Compression speed. Slow = exhaustive \n"); printf(" search for optimal quality\n"); printf(" (default: fast)\n"); printf(" -e {perceptual|nonperceptual} Error metric: Perceptual (nicest) or \n"); printf(" nonperceptual (highest PSNR)\n"); printf(" (default: perceptual)\n"); printf(" -c {etc1|etc2} Codec: etc1 (most compatible) or \n"); printf(" etc2 (highest quality)\n"); printf(" (default: etc2)\n"); printf(" -f {R|R_signed|RG|RG_signed| Format: one, two, three or four \n"); printf(" RGB|RGBA1|RGBA8| channels, and 1 or 8 bits for alpha\n"); printf(" sRGB|sRGBA1|sRGBA8|} RGB or sRGB.\n"); printf(" (1 equals punchthrough)\n"); printf(" (default: RGB)\n"); printf(" -v {on|off} Detailed progress info. (default on)\n"); printf(" \n"); printf("Examples: \n"); printf(" etcpack img.ppm img.pkm Compresses img.ppm to img.pkm in\n"); printf(" ETC2 RGB format\n"); printf(" etcpack img.ppm img.ktx Compresses img.ppm to img.ktx in\n"); printf(" ETC2 RGB format\n"); printf(" etcpack img.pkm img_copy.ppm Decompresses img.pkm to img_copy.ppm\n"); printf(" etcpack -s slow img.ppm img.pkm Compress using the slow mode.\n"); printf(" etcpack -p orig.ppm copy.ppm Calculate PSNR between orig and copy\n"); printf(" etcpack -f RGBA8 img.tga img.pkm Compresses img.tga to img.pkm, using \n"); printf(" etc2 + alpha.\n"); printf(" etcpack -f RG img.ppm img.pkm Compresses red and green channels of\n"); printf(" img.ppm\n"); } return 0; } #endif // 0