#include <string.h>
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include "png.h"
#include "readpng.h"

#define LOAD4444(r,g,b,a) ( ((b<<4)&0xf00)  | (g&0xf0) | ((r>>4)&0xf) | ((a<<8) & 0xf000) )
#define LOAD8888(r,g,b,a) ( (b<<16) | (g<<8) | (r) | (a<<24) )
#define LOAD565(r,g,b) ( ((b<<8) & 0xf800) | ((g<<3) & 0x7e0) | ((r>>3) & 0x1F) )
#define LOAD5551(r,g,b,a) ( ((b<<7) & 0x7c00) | ((g<<2) & 0x3e0) | ((r>>3) & 0x1F) | ((a<<8) & 0x8000) )

void _png_copy(u8 *buffer, void *temp_tex,
                      u32 channels, u32 stride,
                      u32 w, u32 h, u32 fmt)
                                            
{

  u32 i,j;   
  u8 *pRow;  
  u8 r,g,b,a;

  u16 *pxls16 = (u16*)temp_tex;
  u32 *pxls32 = (u32*)temp_tex;

  for(i = 0; i < h; i++)
  {
    pRow = &buffer[i*stride];
    
    for(j=0; j<w; j++) {
      if (channels == 3) {
        r = pRow[j*3]; g = pRow[j*3+1]; b = pRow[j*3+2]; a = 0xff;
      } else if (channels == 4) {
        r = pRow[j*4]; g = pRow[j*4+1]; b = pRow[j*4+2]; a = pRow[j*4+3];
      } else if (channels == 1) {
        r = g = b = a = pRow[j];
      } else {
        r = g = b = a = 0xff;
      }
      switch(fmt) {
       case 8888: pxls32[i*w+j] = LOAD8888(r,g,b,a); break;
       case 4444: pxls16[i*w+j] = LOAD4444(r,g,b,a); break;
       case 5650: pxls16[i*w+j] = LOAD565(r,g,b); break;
       case 5551: pxls16[i*w+j] = LOAD5551(r,g,b,a); break;
      }
    }
  }
}

int main(int argc, char **argv) {
  FILE    *infile, *outfile;
  u8      *buffer;
  void    *outbuffer;
  u32     row_stride;
  u32     channels;
  u32     w, h, byte_count;
  int     fmt = 4444;
  void    *strs; 
  int     s = 2;

  if(argc<3) {
    printf("Syntax: %s <in.png> <out.16> [fmt]\n", argv[0]);
    printf("\t\tfmt is one of 4444 5650 5551\n");
    return 0;
  }

  if(argc>3)
    fmt = atoi(argv[3]);

  if(fmt == 8888) s = 4;
    
  if ((infile = fopen(argv[1], "rb")) == 0) {
    printf("%s: can't open %s\n", argv[0], argv[1]);
    return -1;
  }

  if ((outfile = fopen(argv[2], "wb")) == 0) {
    printf("%s: can't open %s\n", argv[0], argv[1]);
    fclose(infile);
    return -1;
  }

  /* Step 1: Initialize loader */
  strs = readpng_init(infile);   
  if (!strs) {
    fclose(infile);
    fclose(outfile);
    return -2;
  }

  buffer = readpng_get_image(strs,&channels, &row_stride, &w, &h);

  byte_count = s * w * h;

  outbuffer = malloc(byte_count);

  _png_copy(buffer, outbuffer, channels, row_stride, w, h, fmt);

  fwrite(outbuffer, w*s, h, outfile);

  free(outbuffer);

  fclose(outfile);
  fclose(infile);

  return 0;
}
