
#include "stdafx.h"

#include "Texture.h"
#include <iostream>
#include <assert.h>

#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>


TGAHeader tgaheader;									// TGA header
TGA tga;												// TGA image data

GLubyte uTGAcompare[12] = {0,0,2,0,0,0,0,0,0,0,0,0};	// Uncompressed TGA Header
GLubyte cTGAcompare[12] = {0,0,10,0,0,0,0,0,0,0,0,0};	// Compressed TGA Header	

bool LoadTGA(Texture * texture, char * filename)				// Load a TGA file
{
    std::cout << "load TGA" << std::endl;
        FILE * fTGA;												// File pointer to texture file
        fTGA = fopen(filename, "rb");								// Open file for reading
        assert(fTGA);

        if(fread(&tgaheader, sizeof(TGAHeader), 1, fTGA) == 0)					// Attempt to read 12 byte header from file
        {

//            //MessageBox(NULL, "Could not read file header", "ERROR", MB_OK);		// If it fails, display an error message
                if(fTGA != NULL)													// Check to seeiffile is still open
                {
                        fclose(fTGA);													// If it is, close it
                }
                return false;														// Exit function
        }

        if(memcmp(uTGAcompare, &tgaheader, sizeof(tgaheader)) == 0)				// See if header matches the predefined header of
        {																		// an Uncompressed TGA image
            std::cout << "load Un TGA" << std::endl;
            LoadUncompressedTGA(texture, filename, fTGA);						// If so, jump to Uncompressed TGA loading code
        }
        else if(memcmp(cTGAcompare, &tgaheader, sizeof(tgaheader)) == 0)		// See if header matches the predefined header of
        {																		// an RLE compressed TGA image
            std::cout << "load TGA compress" << std::endl;
            LoadCompressedTGA(texture, filename, fTGA);							// If so, jump to Compressed TGA loading code
        }
        else																	// If header matches neither type
        {
            std::cout << "load Unknown file" << std::endl;
                //MessageBox(NULL, "TGA file be type 2 or type 10 ", "Invalid Image", MB_OK);	// Display an error
                fclose(fTGA);
                return false;																// Exit function
        }
        return true;															// All went well, continue on
}

bool LoadUncompressedTGA(Texture * texture, char * filename, FILE * fTGA)	// Load an uncompressed TGA (note, much of this code is based on NeHe's
{																			// TGA Loading code nehe.gamedev.net)
        if(fread(tga.header, sizeof(tga.header), 1, fTGA) == 0)					// Read TGA header
        {
                //MessageBox(NULL, "Could not read info header", "ERROR", MB_OK);		// Display error
                if(fTGA != NULL)													// if file is still open
                {
                        fclose(fTGA);													// Close it
                }
                return false;														// Return failular
        }

        texture->width  = tga.header[1] * 256 + tga.header[0];					// Determine The TGA Width	(highbyte*256+lowbyte)
        texture->height = tga.header[3] * 256 + tga.header[2];					// Determine The TGA Height	(highbyte*256+lowbyte)
        texture->bpp	= tga.header[4];										// Determine the bits per pixel

        tga.Width		= texture->width;										// Copy width into local structure
        tga.Height		= texture->height;										// Copy height into local structure
        tga.Bpp			= texture->bpp;											// Copy BPP into local structure

        if((texture->width <= 0) || (texture->height <= 0) || ((texture->bpp != 24) && (texture->bpp !=32)))	// Make sure all information is valid
        {
                //MessageBox(NULL, "Invalid texture information", "ERROR", MB_OK);	// Display Error
                if(fTGA != NULL)													// Check if file is still open
                {
                        fclose(fTGA);													// If so, close it
                }
                return false;														// Return failed
        }

        if(texture->bpp == 24)													// If the BPP of the image is 24...
                texture->type	= GL_RGB;											// Set Image type to GL_RGB
        else																	// Else if its 32 BPP
                texture->type	= GL_RGBA;											// Set image type to GL_RGBA

        tga.bytesPerPixel	= (tga.Bpp / 8); // tga.Bpp = Bits per pixels.									// Compute the number of BYTES per pixel
        tga.imageSize		= (tga.bytesPerPixel * tga.Width * tga.Height);		// Compute the total amout ofmemory needed to store data
//        texture->imageData	= (GLubyte *)malloc(tga.imageSize);
        texture->imageData	= (char *)malloc(tga.imageSize);
        // Allocate that much memory

        if(texture->imageData == NULL)											// If no space was allocated
        {
                //MessageBox(NULL, "Could not allocate memory for image", "ERROR", MB_OK);	// Display Error
                fclose(fTGA);														// Close the file
                return false;														// Return failed
        }

        if(fread(texture->imageData, 1, tga.imageSize, fTGA) != tga.imageSize)	// Attempt to read image data
        {
                //MessageBox(NULL, "Could not read image data", "ERROR", MB_OK);		// Display Error
                if(texture->imageData != NULL)										// If imagedata has data in it
                {
                        free(texture->imageData);										// Delete data from memory
                }
                fclose(fTGA);														// Close file
                return false;														// Return failed
        }

        // Byte Swapping Optimized By Steve Thomas
        for(GLuint cswap = 0; cswap < (int)tga.imageSize; cswap += tga.bytesPerPixel)
        {
                texture->imageData[cswap] ^= texture->imageData[cswap+2] ^=
                texture->imageData[cswap] ^= texture->imageData[cswap+2];
        }

        fclose(fTGA);															// Close file
        return true;															// Return success
}

bool LoadCompressedTGA(Texture * texture, char * filename, FILE * fTGA)		// Load COMPRESSED TGAs
{
        if(fread(tga.header, sizeof(tga.header), 1, fTGA) == 0)					// Attempt to read header
        {
                //MessageBox(NULL, "Could not read info header", "ERROR", MB_OK);		// Display Error
                if(fTGA != NULL)													// If file is open
                {
                        fclose(fTGA);													// Close it
                }
                return false;														// Return failed
        }

        texture->width  = tga.header[1] * 256 + tga.header[0];					// Determine The TGA Width	(highbyte*256+lowbyte)
        texture->height = tga.header[3] * 256 + tga.header[2];					// Determine The TGA Height	(highbyte*256+lowbyte)
        texture->bpp	= tga.header[4];										// Determine Bits Per Pixel
        tga.Width		= texture->width;										// Copy width to local structure
        tga.Height		= texture->height;										// Copy width to local structure
        tga.Bpp			= texture->bpp;											// Copy width to local structure

        if((texture->width <= 0) || (texture->height <= 0) || ((texture->bpp != 24) && (texture->bpp !=32)))	//Make sure all texture info is ok
        {
                //MessageBox(NULL, "Invalid texture information", "ERROR", MB_OK);	// If it isnt...Display error
                if(fTGA != NULL)													// Check if file is open
                {
                        fclose(fTGA);													// Ifit is, close it
                }
                return false;														// Return failed
        }

        if(texture->bpp == 24)													// If the BPP of the image is 24...
                texture->type	= GL_RGB;											// Set Image type to GL_RGB
        else																	// Else if its 32 BPP
                texture->type	= GL_RGBA;											// Set image type to GL_RGBA

        tga.bytesPerPixel	= (tga.Bpp / 8);									// Compute BYTES per pixel
        tga.imageSize		= (tga.bytesPerPixel * tga.Width * tga.Height);		// Compute amout of memory needed to store image
        texture->imageData	= (char *)malloc(tga.imageSize);					// Allocate that much memory

        if(texture->imageData == NULL)											// If it wasnt allocated correctly..
        {
                //MessageBox(NULL, "Could not allocate memory for image", "ERROR", MB_OK);	// Display Error
                fclose(fTGA);														// Close file
                return false;														// Return failed
        }

        GLuint pixelcount	= tga.Height * tga.Width;							// Nuber of pixels in the image
        GLuint currentpixel	= 0;												// Current pixel being read
        GLuint currentbyte	= 0;												// Current byte
        GLubyte * colorbuffer = (GLubyte *)malloc(tga.bytesPerPixel);			// Storage for 1 pixel

        do
        {
                GLubyte chunkheader = 0;											// Storage for "chunk" header

                if(fread(&chunkheader, sizeof(GLubyte), 1, fTGA) == 0)				// Read in the 1 byte header
                {
                        //MessageBox(NULL, "Could not read RLE header", "ERROR", MB_OK);	// Display Error
                        if(fTGA != NULL)												// If file is open
                        {
                                fclose(fTGA);												// Close file
                        }
                        if(texture->imageData != NULL)									// If there is stored image data
                        {
                                free(texture->imageData);									// Delete image data
                        }
                        return false;													// Return failed
                }

                if(chunkheader < 128)												// If the ehader is < 128, it means the that is the number of RAW color packets minus 1
                {																	// that follow the header
                        chunkheader++;													// add 1 to get number of following color values
                        for(short counter = 0; counter < chunkheader; counter++)		// Read RAW color values
                        {
                                if(fread(colorbuffer, 1, tga.bytesPerPixel, fTGA) != tga.bytesPerPixel) // Try to read 1 pixel
                                {
                                        //MessageBox(NULL, "Could not read image data", "ERROR", MB_OK);		// IF we cant, display an error

                                        if(fTGA != NULL)													// See if file is open
                                        {
                                                fclose(fTGA);													// If so, close file
                                        }

                                        if(colorbuffer != NULL)												// See if colorbuffer has data in it
                                        {
                                                free(colorbuffer);												// If so, delete it
                                        }

                                        if(texture->imageData != NULL)										// See if there is stored Image data
                                        {
                                                free(texture->imageData);										// If so, delete it too
                                        }

                                        return false;														// Return failed
                                }
                                                                                                                                                                                // write to memory
                                texture->imageData[currentbyte		] = colorbuffer[2];				    // Flip R and B vcolor values around in the process
                                texture->imageData[currentbyte + 1	] = colorbuffer[1];
                                texture->imageData[currentbyte + 2	] = colorbuffer[0];

                                if(tga.bytesPerPixel == 4)												// if its a 32 bpp image
                                {
                                        texture->imageData[currentbyte + 3] = colorbuffer[3];				// copy the 4th byte
                                }

                                currentbyte += tga.bytesPerPixel;										// Increase thecurrent byte by the number of bytes per pixel
                                currentpixel++;															// Increase current pixel by 1

                                if(currentpixel > pixelcount)											// Make sure we havent read too many pixels
                                {
                                        //MessageBox(NULL, "Too many pixels read", "ERROR", NULL);			// if there is too many... Display an error!

                                        if(fTGA != NULL)													// If there is a file open
                                        {
                                                fclose(fTGA);													// Close file
                                        }

                                        if(colorbuffer != NULL)												// If there is data in colorbuffer
                                        {
                                                free(colorbuffer);												// Delete it
                                        }

                                        if(texture->imageData != NULL)										// If there is Image data
                                        {
                                                free(texture->imageData);										// delete it
                                        }

                                        return false;														// Return failed
                                }
                        }
                }
                else																			// chunkheader > 128 RLE data, next color reapeated chunkheader - 127 times
                {
                        chunkheader -= 127;															// Subteact 127 to get rid of the ID bit
                        if(fread(colorbuffer, 1, tga.bytesPerPixel, fTGA) != tga.bytesPerPixel)		// Attempt to read following color values
                        {
                                //MessageBox(NULL, "Could not read from file", "ERROR", MB_OK);			// If attempt fails.. Display error (again)

                                if(fTGA != NULL)														// If thereis a file open
                                {
                                        fclose(fTGA);														// Close it
                                }

                                if(colorbuffer != NULL)													// If there is data in the colorbuffer
                                {
                                        free(colorbuffer);													// delete it
                                }

                                if(texture->imageData != NULL)											// If thereis image data
                                {
                                        free(texture->imageData);											// delete it
                                }

                                return false;															// return failed
                        }

                        for(short counter = 0; counter < chunkheader; counter++)					// copy the color into the image data as many times as dictated
                        {																			// by the header
                                texture->imageData[currentbyte		] = colorbuffer[2];					// switch R and B bytes areound while copying
                                texture->imageData[currentbyte + 1	] = colorbuffer[1];
                                texture->imageData[currentbyte + 2	] = colorbuffer[0];

                                if(tga.bytesPerPixel == 4)												// If TGA images is 32 bpp
                                {
                                        texture->imageData[currentbyte + 3] = colorbuffer[3];				// Copy 4th byte
                                }

                                currentbyte += tga.bytesPerPixel;										// Increase current byte by the number of bytes per pixel
                                currentpixel++;															// Increase pixel count by 1

                                if(currentpixel > pixelcount)											// Make sure we havent written too many pixels
                                {
                                        //MessageBox(NULL, "Too many pixels read", "ERROR", NULL);			// if there is too many... Display an error!

                                        if(fTGA != NULL)													// If there is a file open
                                        {
                                                fclose(fTGA);													// Close file
                                        }

                                        if(colorbuffer != NULL)												// If there is data in colorbuffer
                                        {
                                                free(colorbuffer);												// Delete it
                                        }

                                        if(texture->imageData != NULL)										// If there is Image data
                                        {
                                                free(texture->imageData);										// delete it
                                        }

                                        return false;														// Return failed
                                }
                        }
                }
        }

        while(currentpixel < pixelcount);													// Loop while there are still pixels left
        fclose(fTGA);																		// Close the file
        return true;																		// return success
}
#define PNG_SIGNATURE_SIZE 8

static void premultiplyData (png_structp   png,
                 png_row_infop row_info,
                 png_bytep     data)
{
    unsigned int i;

    for (i = 0; i < row_info->rowbytes; i += 4)
    {
        unsigned char *base = &data[i];
        unsigned char blue  = base[0];
        unsigned char green = base[1];
        unsigned char red   = base[2];
        unsigned char alpha = base[3];
        int	      p;

        red   = (unsigned) red   * (unsigned) alpha / 255;
        green = (unsigned) green * (unsigned) alpha / 255;
        blue  = (unsigned) blue  * (unsigned) alpha / 255;

        p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
        memcpy (base, &p, sizeof (int));
    }
}

static void stdioReadFunc (png_structp png,
               png_bytep   data,
               png_size_t  size)
{
    std::ifstream *file = (std::ifstream *) png_get_io_ptr (png);

    file->read ((char *) data, size);
    if (file->fail ())
        png_error (png, "Read Error");
}
bool readPngData ( Texture* texture,png_struct *png,
                        png_info   *info)
{
    png_uint_32	 pngWidth, pngHeight;
    int		 depth, colorType, interlace;
    unsigned int pixelSize, i;
    png_byte	 **rowPointers;
     char	 *d;

    png_read_info (png, info);

    png_get_IHDR (png, info,
                  &pngWidth, &pngHeight, &depth,
                  &colorType, &interlace, NULL, NULL);

//    std::cout << "Load image : w = "<< pngWidth << " h = " << pngHeight << std::endl;
    texture->height = pngHeight;
    texture->width = pngWidth;

//    size.setWidth (pngWidth);
//    size.setHeight (pngHeight);

    /* convert palette/gray image to rgb */
//    std::cout << "Load image : colortype = "<< colorType << " depth=" << depth<< std::endl;
    if (colorType == PNG_COLOR_TYPE_PALETTE) //1
        png_set_palette_to_rgb (png);

    /* expand gray bit depth if needed */
    if (colorType == PNG_COLOR_TYPE_GRAY && depth < 8) // 0
        png_set_expand_gray_1_2_4_to_8 (png);

    /* transform transparency to alpha */
    if (png_get_valid (png, info, PNG_INFO_tRNS))
        png_set_tRNS_to_alpha (png);

    if (depth == 16)
        png_set_strip_16 (png);

    if (depth < 8)
        png_set_packing (png);

    /* convert grayscale to RGB */

    if (colorType == PNG_COLOR_TYPE_GRAY ||
            colorType == PNG_COLOR_TYPE_GRAY_ALPHA)        
        png_set_gray_to_rgb (png);

    if (interlace != PNG_INTERLACE_NONE)
        png_set_interlace_handling (png);

    //png_set_bgr (png);
    png_set_filler (png, 0xff, PNG_FILLER_AFTER);

    png_set_read_user_transform_fn (png, premultiplyData);

    png_read_update_info (png, info);

    pixelSize = 4;//4
    d = ( char *) malloc (pngWidth * pngHeight * pixelSize);
    if (!d)
        return false;
    texture->bpp = 8;
    texture->imageData = d;
    texture->type = GL_RGBA;
    rowPointers = new png_byte *[pngHeight];
    if (!rowPointers)
    {
        free (d);
        return false;
    }

    for (i = 0; i < pngHeight; i++)
        rowPointers[i] = (png_byte *) (d + i * pngWidth * pixelSize);

    png_read_image (png, rowPointers);
    png_read_end (png, info);

    delete [] rowPointers;

    return true;
}


bool LoadPNG(Texture *texture, char *filename){
//    std::cout << "Read file" << std::endl;
    std::ifstream         infile;
    /* Open the file. */
    infile.open(filename,std::ifstream::in);
    if (!infile) {
        return 0;
    }
//    std::cout << "Read file / OK" << std::endl;
    unsigned char png_sig[PNG_SIGNATURE_SIZE];
    png_struct	  *png;
    png_info	  *info;
    bool	  status;

//    std::cout << "Read file: check file" << std::endl;
    infile.read ((char *) png_sig, PNG_SIGNATURE_SIZE);
    if (infile.fail ())
        return false;
    if (png_sig_cmp (png_sig, 0, PNG_SIGNATURE_SIZE) != 0)
        return false;

    png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png)
        return false;

    info = png_create_info_struct (png);
    if (!info)
    {
        png_destroy_read_struct (&png, NULL, NULL);
        return false;
    }
//    std::cout << "Read file: check OK" << std::endl;
    png_set_read_fn (png, &infile, stdioReadFunc);
    png_set_sig_bytes (png, PNG_SIGNATURE_SIZE);
//    std::cout << "Read file: read data" << std::endl;
    status = readPngData (texture,png, info);
//    std::cout << "Read file: read data OK" << std::endl;
    png_destroy_read_struct (&png, &info, NULL);

    infile.close();
    return status;


}
bool LoadJPG(Texture *texture, char *filename){
//    struct jpeg_decompress_struct cinfo;
//    struct jpeg_error_mgr jerr;
//    FILE *file;
//    int gris = 256;
//    unsigned char *ligne;

//    cinfo.err = jpeg_std_error(&jerr);
//    jpeg_create_decompress(&cinfo);
//    file=fopen(filename,"rb");

//    jpeg_stdio_src(&cinfo, file);
//    jpeg_read_header(&cinfo, TRUE);

//    jpeg_start_decompress(&cinfo);

//    texture->height = cinfo.output_height;
//    texture->width = cinfo.output_width;

//    ligne=image;
//    while (cinfo.output_scanline<cinfo.output_height)
//    {
//        ligne=image+3*gris*cinfo.output_scanline;
//        jpeg_read_scanlines(&cinfo,&ligne,1);
//    }
//    jpeg_finish_decompress(&cinfo);
//    jpeg_destroy_decompress(&cinfo);

}
bool LoadBMP(Texture* texture, char *filename){

}
