#include <stdio.h>
#include <stdint.h>

/*
 The function converts a 16bit GRBG 2x2 CFA coded image into an 8bit
 RGB image by setting the missing RGB values to zero.
 */
void debayer_grbg16_simple (uint16_t * src, int src_w, int src_h,
			    uint8_t  * dst, int dst_w, int dst_h) {
  
  // GG RR
  // BB GG
  uint16_t t;
  uint8_t r, g, b;
  int ys, yd, xs, xd;

  for (ys = 0, yd = 0; ys < src_h && yd < dst_h; ys++, yd++) {
    for (xs = 0, xd = 0; xs < src_w; xs++) {

      /* read the pixel but only the higher 8bit, assuming data is little endian */
      t = (*(src++) >> 8) & 0xff;
      
      if (xs & 1) {
	if (ys & 1) {
	  // lower right green pixel
	  b = 0; g = t; r = 0;
	} else {
	  // upper right red pixel
	  b = 0; g = 0; r = t;
	}
      } else {
	if (ys & 1) {
	  // lower left blue pixel
	  b = t; g = 0; r = 0;
	} else {
	  // upper left green pixel
	  b = 0; g = t; r = 0;
	}
      }
      
      /* only paint the image if the source is within the destination */
      if (xd < dst_w) {
	/* set the pixel */
	*(dst++) = r;
	*(dst++) = g;
	*(dst++) = b;
	xd++;
      }
    }
    
    /* if the source image is too small ignore the other places */
    if (xd < dst_w)
      dst += 3 * (dst_w - xd);
  }
}

// macros to make code better readable
#define CE (*(src))
#define UP (*(src-src_w))
#define DN (*(src+src_w))
#define LE (*(src-1))
#define RI (*(src+1))
#define UPLE (*(src-src_w-1))
#define UPRI (*(src-src_w+1))
#define DNLE (*(src+src_w-1))
#define DNRI (*(src+src_w+1))

#define BITCONV(d) ((d>>8) & 0xff)
#define STORE  *(dst++) = BITCONV(r); *(dst++) = BITCONV(g); *(dst++) = BITCONV(b); src++;
#define STORE8 *(dst++) = (r & 0xff); *(dst++) = (g & 0xff); *(dst++) = (b & 0xff); src++;


/*
 The function converts a 16bit GRBG 2x2 CFA coded image into an 8bit
 RGB image by bilinear interpolation.
 */
void debayer_grbg16_bilinear (uint16_t * src, int src_w, int src_h,
			      uint8_t  * dst, int dst_w, int dst_h) {
  
  // GG RR GG RR
  // BB GG BB GG
  // GG RR GG RR
  // BB GG BB GG
  uint32_t r, g, b;
  int xs, ys;

  // start with upper left pixel (green)
  r = RI;
  g = CE;
  b = DN;
  STORE;

  // upper first line, starts with RR GG RR ...
  for (xs = 1; xs < src_w - 1; xs+=2) {
    // red pixel
    r = CE;
    g = (LE + RI + DN) / 3;
    b = (DNLE + DNRI) / 2;
    STORE;
    // green pixel
    r = (LE + RI) / 2;
    g = CE;
    b = DN;
    STORE;
  }

  // upper right pixel (red)
  r = CE;
  g = (DN + LE) / 2;
  b = DNLE;
  STORE;

  // go through the "body" of the image
  for (ys = 1; ys < src_h - 1; ys+=2) {

    // every second line with BB GG BB GG (start at 2nd line)

    // left hand pixel (blue)
    r = (UPRI + DNRI) / 2;
    g = (UP + DN + RI) / 3;
    b = CE;
    STORE;
    for (xs = 1; xs < src_w - 1; xs+=2) {
      // green pixel
      r = (UP + DN) / 2;
      g = CE;
      b = (LE + RI) / 2;
      STORE;
      // blue pixel
      r = (UPLE + UPRI + DNLE + DNRI) / 4;
      g = (LE + RI + UP + DN) / 4;
      b = CE;
      STORE;
    }
    // last pixel in line (green)
    r = (UP + DN) / 2;
    g = CE;
    b = LE;
    STORE;

    // every second line with GG RR GG RR ... (start at 3rd line)

    // left hand pixel (green)
    r = RI;
    g = CE;
    b = (UP + DN) / 2;
    STORE;
    for (xs = 1; xs < src_w - 1; xs+=2) {
      // red pixel
      r = CE;
      g = (LE + RI + UP + DN) / 4;
      b = (UPLE + UPRI + DNLE + DNRI) / 4;
      STORE;
      // green pixel
      r = (LE + RI) / 2;
      g = CE;
      b = (UP + DN) / 2;
      STORE;
    }
    // last pixel in line (red)
    r = CE;
    g = (UP + DN + LE) / 3;
    b = (UPLE + DNLE) / 2;
    STORE;
  }

  // bottom left pixel
  r = UPRI;
  g = (UP + RI) / 2;
  b = CE;
  STORE;

  // last line starting with GG BB GG ...
  for (xs = 1; xs < src_w - 1; xs+=2) {
    // green pixel
    r = UP;
    g = CE;
    b = (LE + RI) / 2;
    STORE;
    // blue pixel
    r = (UPLE + UPRI) / 2;
    g = (LE + UP + RI) / 2;
    b = CE;
    STORE;
  }
  
  // bottom right pixel (green)
  r = UP;
  g = CE;
  b = LE;
  STORE;
}

/*
 The function converts a 8bit GRBG 2x2 CFA coded image into an 8bit
 RGB image by setting the missing RGB values to zero.
 */
void debayer_grbg8_simple (uint8_t * src, int src_w, int src_h,
			   uint8_t * dst, int dst_w, int dst_h) {
  
  // GG RR
  // BB GG
  uint8_t t;
  uint8_t r, g, b;
  int ys, yd, xs, xd;

  for (ys = 0, yd = 0; ys < src_h && yd < dst_h; ys++, yd++) {
    for (xs = 0, xd = 0; xs < src_w; xs++) {

      /* read the pixel but only the higher 8bit, assuming data is little endian */
      t = *(src++);
      
      if (xs & 1) {
	if (ys & 1) {
	  // lower right green pixel
	  b = 0; g = t; r = 0;
	} else {
	  // upper right red pixel
	  b = 0; g = 0; r = t;
	}
      } else {
	if (ys & 1) {
	  // lower left blue pixel
	  b = t; g = 0; r = 0;
	} else {
	  // upper left green pixel
	  b = 0; g = t; r = 0;
	}
      }
      
      /* only paint the image if the source is within the destination */
      if (xd < dst_w) {
	/* set the pixel */
	*(dst++) = r;
	*(dst++) = g;
	*(dst++) = b;
	xd++;
      }
    }
    
    /* if the source image is too small ignore the other places */
    if (xd < dst_w)
      dst += 3 * (dst_w - xd);
  }
}

/*
 The function converts a 8bit GRBG 2x2 CFA coded image into an 8bit
 RGB image by bilinear interpolation.
 */
void debayer_grbg8_bilinear (uint8_t * src, int src_w, int src_h,
			     uint8_t * dst, int dst_w, int dst_h) {
  
  // GG RR GG RR
  // BB GG BB GG
  // GG RR GG RR
  // BB GG BB GG
  uint16_t r, g, b;
  int xs, ys;

  // start with upper left pixel (green)
  r = RI;
  g = CE;
  b = DN;
  STORE8;

  // upper first line, starts with RR GG RR ...
  for (xs = 1; xs < src_w - 1; xs+=2) {
    // red pixel
    r = CE;
    g = (LE + RI + DN) / 3;
    b = (DNLE + DNRI) / 2;
    STORE8;
    // green pixel
    r = (LE + RI) / 2;
    g = CE;
    b = DN;
    STORE8;
  }

  // upper right pixel (red)
  r = CE;
  g = (DN + LE) / 2;
  b = DNLE;
  STORE8;

  // go through the "body" of the image
  for (ys = 1; ys < src_h - 1; ys+=2) {

    // every second line with BB GG BB GG (start at 2nd line)

    // left hand pixel (blue)
    r = (UPRI + DNRI) / 2;
    g = (UP + DN + RI) / 3;
    b = CE;
    STORE8;
    for (xs = 1; xs < src_w - 1; xs+=2) {
      // green pixel
      r = (UP + DN) / 2;
      g = CE;
      b = (LE + RI) / 2;
      STORE8;
      // blue pixel
      r = (UPLE + UPRI + DNLE + DNRI) / 4;
      g = (LE + RI + UP + DN) / 4;
      b = CE;
      STORE8;
    }
    // last pixel in line (green)
    r = (UP + DN) / 2;
    g = CE;
    b = LE;
    STORE8;

    // every second line with GG RR GG RR ... (start at 3rd line)

    // left hand pixel (green)
    r = RI;
    g = CE;
    b = (UP + DN) / 2;
    STORE8;
    for (xs = 1; xs < src_w - 1; xs+=2) {
      // red pixel
      r = CE;
      g = (LE + RI + UP + DN) / 4;
      b = (UPLE + UPRI + DNLE + DNRI) / 4;
      STORE8;
      // green pixel
      r = (LE + RI) / 2;
      g = CE;
      b = (UP + DN) / 2;
      STORE8;
    }
    // last pixel in line (red)
    r = CE;
    g = (UP + DN + LE) / 3;
    b = (UPLE + DNLE) / 2;
    STORE8;
  }

  // bottom left pixel
  r = UPRI;
  g = (UP + RI) / 2;
  b = CE;
  STORE8;

  // last line starting with GG BB GG ...
  for (xs = 1; xs < src_w - 1; xs+=2) {
    // green pixel
    r = UP;
    g = CE;
    b = (LE + RI) / 2;
    STORE8;
    // blue pixel
    r = (UPLE + UPRI) / 2;
    g = (LE + UP + RI) / 2;
    b = CE;
    STORE8;
  }
  
  // bottom right pixel (green)
  r = UP;
  g = CE;
  b = LE;
  STORE8;
}
