// #define TEST
#define X	100
#define Y	100

//#define USE_DBL
#ifdef USE_DBL
#define TYPE_FLT  double
#define TYPE_INT  long
#define MASK      0xFFFF
#define SHIFT     16
#define EPSILSON  4.94065645841247E-324
#else
#define TYPE_FLT  float
#define TYPE_INT  int
#define MASK      0x00FF
#define SHIFT     8
#define EPSILSON  1.401298E-45
#endif

constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE |
                                CLK_ADDRESS_CLAMP_TO_EDGE |
                                CLK_FILTER_LINEAR;


struct input {
  int gray_map_selector;
};

TYPE_FLT read_data(image2d_t input_frame, int x, int z)
{
  int2 gid = (int2)(x, z);
  uint4 pixel = read_imageui(input_frame, sampler, gid);
  TYPE_INT temp =  (TYPE_INT)((TYPE_INT)pixel.x & MASK) | 
                    (TYPE_INT)(((TYPE_INT)pixel.y & MASK) << SHIFT) |
                    (TYPE_INT)(((TYPE_INT)pixel.z & MASK) << (SHIFT * 2)) | 
                    (TYPE_INT)(((TYPE_INT)pixel.w & MASK) << (SHIFT * 3));
  TYPE_FLT raw_data = *((TYPE_FLT*)(&temp));
  return raw_data;
}


kernel void GrayMap(read_only image2d_t input_frame, read_write image2d_t output_frame, struct input params) 
{
  int2 gid = (int2)(get_global_id(0), get_global_id(1));
  TYPE_FLT input = read_data(input_frame, gid.x, gid.y);
  TYPE_FLT output_data = 0;

  double gama[17] = {0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.67, 0.75, 1, 1.33, 1.5, 2, 2.5, 3.33, 5, 10, 20};

  if(params.gray_map_selector == 17)
  {
    output_data = 255 * log2(input / 255 + 1);
  }
  else
  {
    output_data = 255 * pow((input / 255.0), gama[params.gray_map_selector]);
  }

  uchar out = (uchar)output_data;

#ifdef TEST
  if(gid.x == X && gid.y == Y)
    printf("%u ---", out);
#endif

  uint4 pixel;
  pixel.x = out;
  pixel.y = out;
  pixel.z = out;
  pixel.w = 255;

  write_imageui(output_frame, gid, pixel);
}