#include <stdio.h>
#include <stdlib.h>

GLuint texture[32];

struct Image {
    unsigned long sizeX;
    unsigned long sizeY;
    char *data;
};
typedef struct Image Image;

static unsigned int getint(FILE *fp)
{
    int c, c1, c2, c3;

    // get 4 bytes
    c = getc(fp);
    c1 = getc(fp);
    c2 = getc(fp);
    c3 = getc(fp);

    return ((unsigned int) c) +
        (((unsigned int) c1) << 8) +
        (((unsigned int) c2) << 16) +
        (((unsigned int) c3) << 24);
}

static unsigned int getshort(FILE *fp)
{
    int c, c1;

    // get 2 bytes
    c = getc(fp);
    c1 = getc(fp);

    return ((unsigned int) c) + (((unsigned int) c1) << 8);
}


/* quick and dirty bitmap loader...for 24 bit bitmaps with 1 plane only.  */
/* See http://www.dcs.ed.ac.uk/~mxr/gfx/2d/BMP.txt for more info.*/

int ImageLoad(char *filename, Image *image)
{
    FILE *file;
    unsigned long size;        // size of the image in bytes.
    unsigned long i;           // standard counter.
    unsigned short int planes; // number of planes in image (must be 1)
    unsigned short int bpp;    // number of bits per pixel (must be 24)
    char temp;                 // temporary color storage for bgr-rgb conversion.

    // The job of this code is to
    // load in a bitmap file. If the file doesn't exist NULL is sent back
    // meaning the texture couldn't be loaded. Before I start explaining the
    // code there are a few VERY important things you need to know about the
    // images you plan to use as textures. The image height and width MUST be a
    // power of 2. The width and height must be at least 64 pixels, and for
    // compatibility reasons, shouldn't be more than 256 pixels. If the image
    // you want to use is not 64, 128 or 256 pixels on the width or height,
    // resize it in an art program. There are ways around this limitation, but
    // for now we'll just stick to standard texture sizes.

    // make sure the file is there.

    if ((file = fopen(filename, "rb"))==NULL) {
        printf("File Not Found : %s\n",filename);
        return 0;
    }

    // seek through the bmp header, up to the width/height:
    fseek(file, 18, SEEK_CUR);

    // No 100% errorchecking anymore!!!

    // read the width
    image->sizeX = getint (file);
    printf("Width of %s: %lu\n", filename, image->sizeX);

    // read the height
    image->sizeY = getint (file);
    printf("Height of %s: %lu\n", filename, image->sizeY);

    // calculate the size (assuming 24 bits or 3 bytes per pixel).
    size = image->sizeX * image->sizeY * 3;

    // read the planes
    planes = getshort(file);
    if (planes != 1) {
        printf("Planes from %s is not 1: %u\n", filename, planes);
        return 0;
    }

    // read the bpp
    bpp = getshort(file);
    if (bpp != 24) {
        printf("Bpp from %s is not 24: %u\n", filename, bpp);
        return 0;
    }

    // seek past the rest of the bitmap header.
    fseek(file, 24, SEEK_CUR);

    // read the data.
    image->data = (char *) malloc(size);
    if (image->data == NULL) {
        printf("Error allocating memory for color-corrected image data");
        return 0;
    }

    if ((i = fread(image->data, size, 1, file)) != 1) {
        printf("Error reading image data from %s.\n", filename);
        return 0;
    }

    for (i=0;i<size;i+=3) { // reverse all of the colors. (bgr -> rgb)
        temp = image->data[i];
        image->data[i] = image->data[i+2];
        image->data[i+2] = temp;
    }

    // we're done.
    return 1;
}

// Load Bitmaps And Convert To Textures
void load_GL_textures(char *filename, int texture_num)
{
    // Load Texture
    Image *image1;

    // allocate space for texture
    image1 = (Image *) malloc(sizeof(Image));
    if (image1 == NULL) {
        printf("Error allocating space for image");
        exit(0);
    }

    if (!ImageLoad(filename, image1)) {
        exit(1);
    }

    // Create Texture
    glGenTextures(1, &texture[texture_num]);
    // 2d texture (x and y size)
    glBindTexture(GL_TEXTURE_2D, texture[texture_num]);

    // scale linearly when image bigger than texture
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);

    // scale linearly when image smalled than texture
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

    // 2d texture, level of detail 0 (normal), 3 components
    // (red, green, blue), x size from image, y size from image,
    // border 0 (normal), rgb color data, unsigned byte data, and
    // finally the data itself.

    glTexImage2D(GL_TEXTURE_2D, 0, 3, image1->sizeX, image1->sizeY, 0,
        GL_RGB, GL_UNSIGNED_BYTE, image1->data);
}
