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

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

GLuint textureID1, textureID2;

void drawEverything(void);
void defineTextures(void);
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);
    defineTextures();
    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);
    
    glEnable(GL_TEXTURE_2D);
    glColor3f(1.0, 1.0, 1.0);

    glBindTexture(GL_TEXTURE_2D, textureID1);
    glBegin(GL_QUADS);
     glTexCoord2i(0,0);
     glVertex3f(-1.0, -1.0, 0.0);
     glTexCoord2i(1,0);
     glVertex3f(1.0, -1.0, 0.0);
     glTexCoord2i(1,1);
     glVertex3f(1.0, 1.0, 0.0);
     glTexCoord2i(0,1);
     glVertex3f(-1.0, 1.0, 0.0);
    glEnd();

    glBindTexture(GL_TEXTURE_2D, textureID2);
    glBegin(GL_QUADS);
     glTexCoord2i(0,0);
     glVertex3f(-2.0, 1.10, -0.5);
     glTexCoord2i(1,0);
     glVertex3f(2.0, 1.1, -0.5);
     glTexCoord2i(1,1);
     glVertex3f(2.0, 2.1, -0.5);
     glTexCoord2i(0,1);
     glVertex3f(-2.0, 2.1, -0.5);
    glEnd();

    glDisable(GL_TEXTURE_2D);
    
    glutSwapBuffers();

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


#define IMAGE1_HEIGHT 128
#define IMAGE1_WIDTH 128
GLubyte textureImage1[IMAGE1_HEIGHT][IMAGE1_WIDTH][3];
#define IMAGE2_HEIGHT 64
#define IMAGE2_WIDTH 64
GLubyte textureImage2[IMAGE2_HEIGHT][IMAGE2_WIDTH][3];

void defineTextures(void)
    {
    int i,j;
    for (i=0; i < IMAGE1_HEIGHT; i++)
        for (j=0; j < IMAGE1_WIDTH; j++)
            {
            textureImage1[i][j][0] = (i>j) * 255;
            textureImage1[i][j][1] = ((IMAGE1_HEIGHT-i) > j) * 255;
            textureImage1[i][j][2] = (j >= (IMAGE1_WIDTH/2)) * 255;
            }
    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_RGB, IMAGE1_WIDTH, IMAGE1_HEIGHT,
                0, GL_RGB, GL_UNSIGNED_BYTE, textureImage1);
    for (i=0; i < IMAGE2_HEIGHT; i++)
        for (j=0; j < IMAGE2_WIDTH; j++)
            {
            textureImage2[i][j][0] = (((i&8)==0)^((j&8)==0))*255;
            textureImage2[i][j][1] = (((i&8)==0)^((j&8)==0))*255;
            textureImage2[i][j][2] = (((i&8)==0)^((j&8)==0))*255;
            }
    glGenTextures(1, &textureID2);
    glBindTexture(GL_TEXTURE_2D, textureID2);
    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_RGB, IMAGE2_WIDTH, IMAGE2_HEIGHT,
                0, GL_RGB, GL_UNSIGNED_BYTE, textureImage2);
    glBindTexture(GL_TEXTURE_2D, 0);
    }


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();
    }
