// Cool Reader Engine 
// generator for glyph gamma correction tables
// (c) Vadim Lopatin, 2011
// this program is distributed under the terms of GNU GPL2 license

#include <stdio.h>
#include <math.h>

static const double gamma_levels[] = { 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 0.98, 1, 1.02, 1.05, 1.1, 1.15, 1.2, 1.25, 1.3, 1.35, 1.4, 1.45, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.5, 4, 4.5, 5, 5.5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };

#define GAMMA_NORMAL 15
#define GAMMA_LEVELS ((int)(sizeof(gamma_levels)/sizeof(gamma_levels[0])))

void genTable( FILE * out, double gamma, int index ) {
    fprintf(out, "static const unsigned char gamma_table_%d[256] = { // gamma=%f\n    ", index, gamma);
    for ( int i=0; i<=255; i++ ) {
        double v = (255-i) / 255.0;
        v = pow(v, gamma);
        int n = (int)round(v * 255);
        n = 255 - n;
	fprintf(out, "%3d, ", n);
	if ( i%22==21 )
	    fprintf(out, "\n    ");
    }
    fprintf(out, "};\n");
}

/// generation of 
int main(int argc, const char ** argv)
{
    if ( argc<2 ) {
	printf("USAGE: gammagen <filename>\n");
	return -1;
    }
    const char * filename = argv[1];
    FILE * out = fopen(filename, "wt");
    if ( !out ) {
	printf("Cannot create file %s\n", filename);
	return -1;
    }
    fprintf(out, "// Gamma tables for using with freetype\n");
    fprintf(out, "// don't edit: this file is generated by crengine/Tools/GammaGen/gammagen.cpp\n");
    fprintf(out, "// to rebuild, run crengine/Tools/GammaGen/gen.sh\n");
    fprintf(out, "// \n");
    fprintf(out, "#define GAMMA_LEVELS %d\n", GAMMA_LEVELS);
    fprintf(out, "\n\n");
    
    fprintf(out, "// gamma correction tables, 0..%d\n", GAMMA_LEVELS-1);
    fprintf(out, "extern const unsigned char * cr_gamma_tables[GAMMA_LEVELS];\n");
    fprintf(out, "// gamma correction levels table 0..%d\n", GAMMA_LEVELS-1);
    fprintf(out, "extern const double cr_gamma_levels[GAMMA_LEVELS];\n");
    fprintf(out, "// corrects gamma for value 0..255, gamma_index must be 0..%d (%d means no correction)\n", GAMMA_LEVELS-1, GAMMA_NORMAL);
    fprintf(out, "inline unsigned char cr_correct_gamma( unsigned char value, int gamma_index ) { return cr_gamma_tables[gamma_index][value]; } \n");
    fprintf(out, "// corrects gamma for byte buffer; gamma_index must be 0..%d (%d means no correction)\n", GAMMA_LEVELS-1, GAMMA_NORMAL);
    fprintf(out, "void cr_correct_gamma_buf( unsigned char * buf, int size, int gamma_index );\n");
    fprintf(out, "\n\n");
         
    fprintf(out, "#ifdef GAMMA_TABLES_IMPL\n");
    
    int i;
    for ( i=0; i<GAMMA_LEVELS; i++ ) {
	genTable(out, gamma_levels[i], i);
    }
    fprintf(out, "\n");
    fprintf(out, "const unsigned char * cr_gamma_tables[GAMMA_LEVELS] = {\n");
    for ( i=0; i<GAMMA_LEVELS; i++ ) {
        fprintf(out, "    gamma_table_%d, // %f \n", i, gamma_levels[i]);
    }
    fprintf(out, "};\n\n");
    fprintf(out, "\n");
    fprintf(out, "const double cr_gamma_levels[GAMMA_LEVELS] = {\n");
    for ( i=0; i<GAMMA_LEVELS; i++ ) {
        fprintf(out, "    %f,\n", gamma_levels[i]);
    }
    fprintf(out, "};\n\n");

    fprintf(out, "// corrects gamma for byte buffer; gamma_index must be 0..%d (%d means no correction)\n", GAMMA_LEVELS-1, GAMMA_NORMAL);
    fprintf(out, "void cr_correct_gamma_buf( unsigned char * buf, int size, int gamma_index ) {\n"
                 "    const unsigned char * table = cr_gamma_tables[gamma_index];\n"
                 "    for ( int i=0; i<size; i++ )\n"
                 "        buf[i] = table[buf[i]];\n"
                 "}\n");
 
    fprintf(out, "\n#endif\n");
    

    fclose(out);
    return 0;
}
