#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <gl/image.h>

GLfloat viewRotY = 0, viewRotX = 0, cameraDistance = 5;

GLuint textureID1;

GLUquadricObj * quadric;

void drawEverything(void);
void defineTexture(char *);
void initLight(void);
void readSGIImage(char *filename,int *xdim,int *ydim,unsigned long **image);
void checkGLError(char *);
void key(unsigned char k, int x, int y);
void specialkey(int k, int x, int y);


int main(int argc, char *argv[])
    {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(512,512);
    glutCreateWindow("example");
    glutDisplayFunc(drawEverything);
    glutKeyboardFunc(key);
    glutSpecialFunc(specialkey);
    quadric = gluNewQuadric();
    gluQuadricTexture(quadric, GL_TRUE);
    if (argc > 1)
        defineTexture(argv[1]);
    else
        defineTexture("texture.sgi");
    glutMainLoop();
    return 0;
    }


void drawEverything(void)
    {
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(50.0, 1.0, 0.1, 100.0);
    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

    glTranslatef(0.0, 0.0, -cameraDistance);
    glRotatef(viewRotX, 1.0, 0.0, 0.0);
    glRotatef(viewRotY, 0.0, 1.0, 0.0);

    initLight();
    
    glEnable(GL_TEXTURE_2D);
    glColor3f(1.0, 1.0, 1.0);

    glBindTexture(GL_TEXTURE_2D, textureID1);
    glPushMatrix();
     glRotatef(-90.0, 1.0, 0.0, 0.0);
     gluSphere(quadric, 1.0, 16, 8);
    glPopMatrix();
    glBindTexture(GL_TEXTURE_2D, 0);

    glDisable(GL_TEXTURE_2D);
    
    glutSwapBuffers();

    checkGLError("end-of-frame");
    }


void defineTexture(char *filename)
    {
    int xdim, ydim;
    unsigned long *image;
    readSGIImage(filename, &xdim, &ydim, &image);
    glGenTextures(1, &textureID1);
    glBindTexture(GL_TEXTURE_2D, textureID1);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, xdim, ydim,
                0, GL_RGBA, GL_UNSIGNED_BYTE, image);
    glBindTexture(GL_TEXTURE_2D, 0);
    }


void initLight(void)
    {
    GLfloat white[4] = { 1, 1, 1, 1 };
    GLfloat grey20[4] = { 0.2, 0.2, 0.2, 1 };
    GLfloat lightPos[4] = {-1, 1, 2, 0};
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, white);
    glLightfv(GL_LIGHT0, GL_AMBIENT, grey20);
    glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
    }


void readSGIImage(char *filename,int *xdim,int *ydim,unsigned long **image)
    {
    unsigned short *img_rbuf, *img_gbuf, *img_bbuf, *img_abuf;
    IMAGE *imagefp;
    int x,y;
    unsigned long *p;
    if ((imagefp=iopen(filename,"r")) == NULL)
        {
        fprintf(stderr,"createTexture: can't open input file %s\n",
            filename);
        exit(1);
        }
    *xdim = imagefp->xsize;
    *ydim = imagefp->ysize;
    img_rbuf = (unsigned short *) malloc(imagefp->xsize*sizeof(unsigned short));
    img_gbuf = (unsigned short *) malloc(imagefp->xsize*sizeof(unsigned short));
    img_bbuf = (unsigned short *) malloc(imagefp->xsize*sizeof(unsigned short));
    img_abuf = (unsigned short *) malloc(imagefp->xsize*sizeof(unsigned short));
    p = *image = (unsigned long *) malloc((*xdim)*(*ydim)*sizeof(unsigned long));
    for (y=0; y < imagefp->ysize; y++)
        {
        getrow(imagefp,img_rbuf,y,0);
        getrow(imagefp,img_gbuf,y,1);
        getrow(imagefp,img_bbuf,y,2);
        if (imagefp->zsize > 3)
            {
            getrow(imagefp,img_abuf,y,3);
            for (x=0; x < imagefp->xsize; x++)
                *p++ = img_rbuf[x] | (img_gbuf[x]<<8) |
                    (img_bbuf[x]<<16) | (img_abuf[x]<<24);
            }
        else
            {
            for (x=0; x < imagefp->xsize; x++)
                *p++ = img_rbuf[x] | (img_gbuf[x]<<8) |
                    (img_bbuf[x]<<16) | (0xff000000);
            }
        }
    iclose(imagefp);
    free(img_abuf);
    free(img_bbuf);
    free(img_gbuf);
    free(img_rbuf);
    }



void checkGLError(char *prefix)
    {
    GLenum err = glGetError();
    if (err != GL_NO_ERROR)
        printf("%s GL error '%s'\n",prefix,gluErrorString(err));
    }


void key(unsigned char k, int x, int y)
    {
    if (k == 27)
        exit(0);
    else if (k == '-')
        cameraDistance += 1;
    else if (k == '=')
        cameraDistance -= 1;
    glutPostRedisplay();
    }


void specialkey(int k, int x, int y)
    {
    if (k == GLUT_KEY_LEFT)
        viewRotY += 3;
    else if (k == GLUT_KEY_RIGHT)
        viewRotY -= 3;
    else if (k == GLUT_KEY_UP)
        viewRotX += 3;
    else if (k == GLUT_KEY_DOWN)
        viewRotX -= 3;
    glutPostRedisplay();
    }

