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

#define GAMMA_LEVELS 31

static const double gamma_levels[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 };

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    ", 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_LEVELS/2);
    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_LEVELS/2);
    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_LEVELS/2);
    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;
}
