/*
 * (C) Copyright Chris B. Kaynor 2006
 * All Rights Reserved.
*/

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <math.h>

#ifdef __linux__
	#include <GL/glut.h>
	#include <GL/glext.h>
	#include <png.h>
#else
	#include "png.h"
	#include "glut.h"
	#include "glext.h"
#endif

#include "data.h"
#include "vector.h"
#include "LoadImage.h"

int LoadImage(GLenum target, GLuint level, GLenum internal_format, const char *filename)
{
   FILE *fp = fopen(filename, "rb");
   png_bytep *row_pointers;
   unsigned i;
   unsigned height;
   unsigned width;
   png_byte color_type;
   GLenum format;
   
   if (fp == NULL) {
      return 0;
   }
   
   png_structp png_ptr = png_create_read_struct
       (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
   if (!png_ptr) {
      fclose(fp);
      return 0;
   }

   png_infop info_ptr = png_create_info_struct(png_ptr);
   if (!info_ptr) {
      png_destroy_read_struct(&png_ptr, NULL, NULL);
      fclose(fp);
      return 0;
   }

   png_infop end_info = png_create_info_struct(png_ptr);
   if (!end_info)
   {
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
      fclose(fp);
      return 0;
   }
   
   png_set_read_fn(png_ptr, (void *)fp, fake_read_fn);
   
   png_read_png(png_ptr, info_ptr, 0, NULL);
   
   row_pointers = png_get_rows(png_ptr, info_ptr);
   
   height = png_get_image_height(png_ptr, info_ptr);
   width = png_get_image_width(png_ptr, info_ptr);

   /* This should be made a LOT more robust.
    *
    * First of all, it should verify that the image has power-of-two
    * dimensions.  If not, the size of the texture should be rounded up.
    * 
    * Secondly, it should not assume that the incoming image is 8-bit per
    * channel RGBA.  Just like the dimensions are queried above, the image
    * format can be queries.  In fact, if the image format isn't quite what
    * we want, we can instruct libpng to massage it into a better format for
    * us while it loads.
    */
   color_type = png_get_color_type(png_ptr, info_ptr);
   format = ((color_type & PNG_COLOR_MASK_ALPHA) != 0) ? GL_RGBA : GL_RGB;
   glTexImage2D(target, level, internal_format,
		width, height, 0, format, GL_UNSIGNED_BYTE,
		NULL);
   
   for (i = 0; i < height; i++) {
      glTexSubImage2D(target, level, 0, i,
		      width, 1, format, GL_UNSIGNED_BYTE,
		      row_pointers[i]);
   }

   png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
   fclose(fp);
   return 1;
}

void fake_read_fn(png_structp png_ptr, png_bytep data, png_size_t count)
{
   FILE *fp = (FILE *) png_get_io_ptr(png_ptr);
   fread(data, 1, count, fp);
}