//---------------------------------------------------------------------
// Ukazkovy priklad cislo 31
// Autor: Pavel Tisnovsky
//
// Tento priklad svym ovladanim navazuje na priklad cislo 28, ktery byl
// prezentovany v minulem dilu tohoto serialu. Funkcni zustavaji veskere
// klavesove kombinace i ovladani, je pouze pridano submenu pro
// povoleni, zakazani a nastaveni jedne orezavaci roviny. Narozdil od
// predchoziho prikladu je orezavaci rovina nastavena az po nastaveni
// vsech projekcnich matic.
//
// Program lze ovladat kombinaci mysi a klavesnice. Pomoci leveho
// tlacitka mysi se aplikuje nektera operace, prave tlacitko mysi slouzi
// k zobrazeni kontextoveho menu. Zakladni udaje o scene se vypisuji
// primo do okna aplikace.
//
// Funkce klaves v tomto programu:
// ESC - ukonceni aplikace
// 'q' - ukonceni aplikace
// 'r' - rezim rotace objektu
// 't' - rezim posunu objektu dale/blize ke kamere
// 'z' - rezim posunu blizke orezavaci roviny
// 'x' - rezim posunu vzdalene orezavaci roviny
// 'f' - prepnuti do rezimu full-screen
// 'w' - prepnuti zpet do okna
// 'e' - povoleni testu pameti hloubky
// 'd' - zakazani testu pameti hloubky
// '[' - povoleni orezavani
// ']' - zakaz orezavani
// '.' - zmenseni zorneho uhlu
// ',' - zvetseni zorneho uhlu
// '>' - rychlejsi zmenseni zorneho uhlu
// '<' - rychlejsi zvetseni zorneho uhlu
// '0'-'9' - zmena rezimu vykreslovani prednich a zadnich stran polygonu
//---------------------------------------------------------------------

#include <GL/glut.h>                            // hlavickovy soubor funkci GLUTu a OpenGL
#include <stdio.h>
#include <stdlib.h>



enum {                                          // operace, ktere se mohou provadet s mysi
    ROTATE,
    TRANSLATE,
    NEAR_PLANE,
    FAR_PLANE
} operation=ROTATE;

enum {                                          // prikazy z kontextoveho menu
    COMMAND_ROTATE,
    COMMAND_TRANSLATE,
    COMMAND_NEAR_PLANE,
    COMMAND_FAR_PLANE,
    COMMAND_FRONT_FACE_DISABLE,
    COMMAND_FRONT_FACE_ENABLE,
    COMMAND_FRONT_FACE_POINTS,
    COMMAND_FRONT_FACE_LINES,
    COMMAND_FRONT_FACE_POLYGONS,
    COMMAND_BACK_FACE_DISABLE,
    COMMAND_BACK_FACE_ENABLE,
    COMMAND_BACK_FACE_POINTS,
    COMMAND_BACK_FACE_LINES,
    COMMAND_BACK_FACE_POLYGONS,
    COMMAND_ENABLE_DEPTH_TEST,
    COMMAND_DISABLE_DEPTH_TEST,
    COMMAND_DEPTH_FUNC_NEVER,
    COMMAND_DEPTH_FUNC_LESS,
    COMMAND_DEPTH_FUNC_LEQUAL,
    COMMAND_DEPTH_FUNC_EQUAL,
    COMMAND_DEPTH_FUNC_GEQUAL,
    COMMAND_DEPTH_FUNC_GREATER,
    COMMAND_DEPTH_FUNC_NOTEQUAL,
    COMMAND_DEPTH_FUNC_ALWAYS,
    COMMAND_FULL_SCREEN,
    COMMAND_WINDOW,
    COMMAND_CLIP_PLANE_ENABLE,
    COMMAND_CLIP_PLANE_DISABLE,
    COMMAND_CLIP_PLANE_XY,
    COMMAND_CLIP_PLANE_XZ,
    COMMAND_CLIP_PLANE_YZ,
    COMMAND_CLIP_PLANE_POSITIVE_DIRECTION,
    COMMAND_CLIP_PLANE_NEGATIVE_DIRECTION,
    COMMAND_CLIP_PLANE_DIST_0,
    COMMAND_CLIP_PLANE_DIST_1,
    COMMAND_CLIP_PLANE_DIST_2,
    COMMAND_CLIP_PLANE_DIST_3,
    COMMAND_CLIP_PLANE_DIST_4,
    COMMAND_CLIP_PLANE_DIST_5,
    COMMAND_QUIT,
    COMMAND_NONE
} command;

int   xnew=0, ynew=0, znew=0;                   // soucasna pozice mysi, ze ktere se pocitaji rotace a posuvy
int   xold=0, yold=0, zold=0;                   // minula pozice mysi, ze ktere se pocitaji rotace a posuvy
int   xx, yy, zz;                               // bod, ve kterem se nachazi kurzor mysi
int   np_old=1, np_new=1, npp=1;                // priznaky blizke orezavaci roviny
int   fp_old=900, fp_new=900, fpp=900;          // priznaky vzdalene orezavaci roviny

float fov=70.0;                                 // hodnota zorneho uhlu - field of view
float nearPlane=0.1;                            // blizsi orezavaci rovina
float farPlane=90.0;                            // vzdalenejsi orezavaci rovina
int   windowWidth;                              // sirka okna
int   windowHeight;                             // vyska okna
int   depthBufferEnabled=1;                     // priznak, zda je povolena pamet hloubky
int   frontFaceEnabled=1;                       // priznak viditelnosti prednich sten
int   backFaceEnabled=1;                        // priznak viditelnosti zadnich sten
int   clipPlaneNormal=COMMAND_CLIP_PLANE_XY;    // normala orezavaci roviny
int   clipPlaneDirection=COMMAND_CLIP_PLANE_POSITIVE_DIRECTION;// orientace normaly
int   clipPlaneDistance=COMMAND_CLIP_PLANE_DIST_0;// vzdalenost orezavaci roviny od pocatku



//---------------------------------------------------------------------
// Funkce, ktera je zavolana pri vyberu prikazu z kontextoveho menu
//---------------------------------------------------------------------
void onMenu(int command)
{
    switch (command) {                          // rozeskok podle vybraneho prikazu
        case COMMAND_ROTATE:              operation=ROTATE;     break;
        case COMMAND_TRANSLATE:           operation=TRANSLATE;  break;
        case COMMAND_NEAR_PLANE:          operation=NEAR_PLANE; break;
        case COMMAND_FAR_PLANE:           operation=FAR_PLANE;  break;
        case COMMAND_FRONT_FACE_DISABLE:  glCullFace(GL_FRONT); glEnable(GL_CULL_FACE); glutPostRedisplay(); break;
        case COMMAND_FRONT_FACE_ENABLE:   glDisable(GL_CULL_FACE); glutPostRedisplay(); break;
        case COMMAND_FRONT_FACE_POINTS:   glPolygonMode(GL_FRONT, GL_POINT); glutPostRedisplay(); break;
        case COMMAND_FRONT_FACE_LINES:    glPolygonMode(GL_FRONT, GL_LINE); glutPostRedisplay(); break;
        case COMMAND_FRONT_FACE_POLYGONS: glPolygonMode(GL_FRONT, GL_FILL); glutPostRedisplay(); break;
        case COMMAND_BACK_FACE_DISABLE:   glCullFace(GL_BACK); glEnable(GL_CULL_FACE); glutPostRedisplay(); break;
        case COMMAND_BACK_FACE_ENABLE:    glDisable(GL_CULL_FACE); glutPostRedisplay(); break;
        case COMMAND_BACK_FACE_POINTS:    glPolygonMode(GL_BACK, GL_POINT); glutPostRedisplay(); break;
        case COMMAND_BACK_FACE_LINES:     glPolygonMode(GL_BACK, GL_LINE); glutPostRedisplay(); break;
        case COMMAND_BACK_FACE_POLYGONS:  glutPostRedisplay(); glPolygonMode(GL_BACK, GL_FILL); break;
        case COMMAND_ENABLE_DEPTH_TEST:   depthBufferEnabled=1; glEnable(GL_DEPTH_TEST); glutPostRedisplay(); break;
        case COMMAND_DISABLE_DEPTH_TEST:  depthBufferEnabled=0; glDisable(GL_DEPTH_TEST); glutPostRedisplay(); break;
        case COMMAND_DEPTH_FUNC_NEVER:    glDepthFunc(GL_NEVER); glutPostRedisplay(); break;
        case COMMAND_DEPTH_FUNC_LESS:     glDepthFunc(GL_LESS); glutPostRedisplay(); break;
        case COMMAND_DEPTH_FUNC_LEQUAL:   glDepthFunc(GL_LEQUAL); glutPostRedisplay(); break;
        case COMMAND_DEPTH_FUNC_EQUAL:    glDepthFunc(GL_EQUAL); glutPostRedisplay(); break;
        case COMMAND_DEPTH_FUNC_GEQUAL:   glDepthFunc(GL_GEQUAL); glutPostRedisplay(); break;
        case COMMAND_DEPTH_FUNC_GREATER:  glDepthFunc(GL_GREATER); glutPostRedisplay(); break;
        case COMMAND_DEPTH_FUNC_NOTEQUAL: glDepthFunc(GL_NOTEQUAL); glutPostRedisplay(); break;
        case COMMAND_DEPTH_FUNC_ALWAYS:   glDepthFunc(GL_ALWAYS); glutPostRedisplay(); break;
        case COMMAND_FULL_SCREEN:         glutFullScreen(); break;
        case COMMAND_WINDOW:              glutReshapeWindow(500, 500); break;
        case COMMAND_CLIP_PLANE_ENABLE:   glEnable(GL_CLIP_PLANE0); glutPostRedisplay(); break;
        case COMMAND_CLIP_PLANE_DISABLE:  glDisable(GL_CLIP_PLANE0); glutPostRedisplay(); break;
        case COMMAND_CLIP_PLANE_XY:
        case COMMAND_CLIP_PLANE_XZ:
        case COMMAND_CLIP_PLANE_YZ:       clipPlaneNormal=command; glutPostRedisplay(); break;
        case COMMAND_CLIP_PLANE_POSITIVE_DIRECTION:
        case COMMAND_CLIP_PLANE_NEGATIVE_DIRECTION: clipPlaneDirection=command; glutPostRedisplay(); break;
        case COMMAND_CLIP_PLANE_DIST_0:
        case COMMAND_CLIP_PLANE_DIST_1:
        case COMMAND_CLIP_PLANE_DIST_2:
        case COMMAND_CLIP_PLANE_DIST_3:
        case COMMAND_CLIP_PLANE_DIST_4:
        case COMMAND_CLIP_PLANE_DIST_5:
                                          clipPlaneDistance=command; glutPostRedisplay(); break;
        case COMMAND_QUIT:                exit(0); break;
        case COMMAND_NONE: break;
    }
}



//---------------------------------------------------------------------
// Funkce pro inicializaci vykreslovani
//---------------------------------------------------------------------
void onInit(void)
{
    GLdouble equation[]={0.0, 1.0, 0.0, 0.0};
    int menu;                                   // identifikatory jednotlivych menu a submenu
    int menuMode;
    int menuDepth;
    int menuDFunc;
    int menuFrontFace;
    int menuBackFace;
    int menuClipping, menuClipNormal, menuClipDirection, menuClipDistance;
    int menuQuit;

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);       // barva pozadi obrazku
    glClearDepth(1.0f);                         // implicitni hloubka ulozena v pameti hloubky
    glEnable(GL_DEPTH_TEST);                    // povoleni funkce pro testovani hodnot v pameti hloubky
    glDepthFunc(GL_LESS);                       // funkce pro testovani fragmentu
    glShadeModel(GL_SMOOTH);                    // nastaveni stinovaciho rezimu
    glPolygonMode(GL_FRONT, GL_FILL);           // nastaveni rezimu vykresleni modelu
    glPolygonMode(GL_BACK, GL_FILL);            // jak pro predni tak pro zadni steny
    glPointSize(3.0f);                          // body zobrazovat s prumerem 3 pixely
    glEnable(GL_POINT_SMOOTH);                  // povoleni antialiasingu bodu
    glLineWidth(1.0f);                          // usecky zobrazovat siroke 1 pixel
    glEnable(GL_LINE_SMOOTH);                   // povoleni antialiasingu usecek
    glDisable(GL_CULL_FACE);                    // zadne hrany ani steny se nebudou odstranovat
    glClipPlane(GL_CLIP_PLANE0, equation);

    menuMode=glutCreateMenu(onMenu);            // vytvoreni kontextoveho menu a jeho submenu
    glutSetMenu(menuMode);
    glutAddMenuEntry("Rotate object\tR", COMMAND_ROTATE);
    glutAddMenuEntry("Translate object\tT", COMMAND_TRANSLATE);
    glutAddMenuEntry("Translate near clipping plane\tZ", COMMAND_NEAR_PLANE);
    glutAddMenuEntry("Translate far clipping plane\tX", COMMAND_FAR_PLANE);

    menuDepth=glutCreateMenu(onMenu);
    glutSetMenu(menuDepth);
    glutAddMenuEntry("Enable depth test\tE", COMMAND_ENABLE_DEPTH_TEST);
    glutAddMenuEntry("Disable depth test\tD", COMMAND_DISABLE_DEPTH_TEST);

    menuDFunc=glutCreateMenu(onMenu);
    glutSetMenu(menuDFunc);
    glutAddMenuEntry("Never", COMMAND_DEPTH_FUNC_NEVER);
    glutAddMenuEntry("Less", COMMAND_DEPTH_FUNC_LESS);
    glutAddMenuEntry("Less or Equal", COMMAND_DEPTH_FUNC_LEQUAL);
    glutAddMenuEntry("Equal", COMMAND_DEPTH_FUNC_EQUAL);
    glutAddMenuEntry("Greater or Equal", COMMAND_DEPTH_FUNC_GEQUAL);
    glutAddMenuEntry("Greater", COMMAND_DEPTH_FUNC_GREATER);
    glutAddMenuEntry("Not Equal", COMMAND_DEPTH_FUNC_NOTEQUAL);
    glutAddMenuEntry("Always", COMMAND_DEPTH_FUNC_ALWAYS);

    menuFrontFace=glutCreateMenu(onMenu);
    glutSetMenu(menuFrontFace);
    glutAddMenuEntry("Disable\t1", COMMAND_FRONT_FACE_DISABLE);
    glutAddMenuEntry("Enable\t2", COMMAND_FRONT_FACE_ENABLE);
    glutAddMenuEntry("Points\t3", COMMAND_FRONT_FACE_POINTS);
    glutAddMenuEntry("Lines\t4", COMMAND_FRONT_FACE_LINES);
    glutAddMenuEntry("Polygons\t5", COMMAND_FRONT_FACE_POLYGONS);

    menuBackFace=glutCreateMenu(onMenu);
    glutSetMenu(menuBackFace);
    glutAddMenuEntry("Disable\t6", COMMAND_BACK_FACE_DISABLE);
    glutAddMenuEntry("Enable\t7", COMMAND_BACK_FACE_ENABLE);
    glutAddMenuEntry("Points\t8", COMMAND_BACK_FACE_POINTS);
    glutAddMenuEntry("Lines\t9", COMMAND_BACK_FACE_LINES);
    glutAddMenuEntry("Polygons\t0", COMMAND_BACK_FACE_POLYGONS);

    menuClipNormal=glutCreateMenu(onMenu);
    glutSetMenu(menuClipNormal);
    glutAddMenuEntry("x-axis", COMMAND_CLIP_PLANE_YZ);
    glutAddMenuEntry("y-axis", COMMAND_CLIP_PLANE_XZ);
    glutAddMenuEntry("z-axis", COMMAND_CLIP_PLANE_XY);

    menuClipDirection=glutCreateMenu(onMenu);
    glutSetMenu(menuClipDirection);
    glutAddMenuEntry("Positive", COMMAND_CLIP_PLANE_POSITIVE_DIRECTION);
    glutAddMenuEntry("Negative", COMMAND_CLIP_PLANE_NEGATIVE_DIRECTION);

    menuClipDistance=glutCreateMenu(onMenu);
    glutSetMenu(menuClipDistance);
    glutAddMenuEntry("0", COMMAND_CLIP_PLANE_DIST_0);
    glutAddMenuEntry("1", COMMAND_CLIP_PLANE_DIST_1);
    glutAddMenuEntry("2", COMMAND_CLIP_PLANE_DIST_2);
    glutAddMenuEntry("3", COMMAND_CLIP_PLANE_DIST_3);
    glutAddMenuEntry("4", COMMAND_CLIP_PLANE_DIST_4);

    menuClipping=glutCreateMenu(onMenu);
    glutSetMenu(menuClipping);
    glutAddMenuEntry("Enable clipping", COMMAND_CLIP_PLANE_ENABLE);
    glutAddMenuEntry("Disable clipping", COMMAND_CLIP_PLANE_DISABLE);
    glutAddSubMenu("Normal", menuClipNormal);
    glutAddSubMenu("Normal' direction", menuClipDirection);
    glutAddSubMenu("Distance", menuClipDistance);

    menuQuit=glutCreateMenu(onMenu);
    glutSetMenu(menuQuit);
    glutAddMenuEntry("Yes\tQ", COMMAND_QUIT);
    glutAddMenuEntry("No", COMMAND_NONE);

    menu=glutCreateMenu(onMenu);
    glutAddSubMenu("Mode", menuMode);
    glutAddSubMenu("Front faces", menuFrontFace);
    glutAddSubMenu("Back faces", menuBackFace);
    glutAddSubMenu("Depth test", menuDepth);
    glutAddSubMenu("Depth function", menuDFunc);
    glutAddSubMenu("Clipping", menuClipping);
    glutAddMenuEntry("Full screen\tF", COMMAND_FULL_SCREEN);
    glutAddMenuEntry("Window\tW", COMMAND_WINDOW);
    glutAddSubMenu("Quit", menuQuit);
    glutAttachMenu(GLUT_RIGHT_BUTTON);          // menu je navazano na prave tlacitko mysi
}



//---------------------------------------------------------------------
// Nastaveni souradneho systemu v zavislosti na velikosti okna
//---------------------------------------------------------------------
void onResize(int w, int h)                     // argumenty w a h reprezentuji novou velikost okna
{
    glViewport(0, 0, w, h);                     // viditelna oblast pres cele okno
    windowWidth=w;                              // zapamatovat si velikost okna
    windowHeight=h;
}



//---------------------------------------------------------------------
// Nastaveni perspektivni projekce
//---------------------------------------------------------------------
void setPerspectiveProjection(void)
{
    glMatrixMode(GL_PROJECTION);                // zacatek modifikace projekcni matice
    glLoadIdentity();                           // vymazani projekcni matice (=identita)
    gluPerspective(fov, (double)windowWidth/(double)windowHeight, nearPlane, farPlane);// nastaveni perspektivni kamery
    glMatrixMode(GL_MODELVIEW);                 // bude se menit modelova matice
    glLoadIdentity();                           // nahrat jednotkovou matici
}



//---------------------------------------------------------------------
// Nastaveni ortogonalni projekce
//---------------------------------------------------------------------
void setOrthogonalProjection(void)
{
    glMatrixMode(GL_PROJECTION);                // zacatek modifikace projekcni matice
    glLoadIdentity();                           // vymazani projekcni matice (=identita)
    glOrtho(0, windowWidth, 0, windowHeight, -1, 1);
    glMatrixMode(GL_MODELVIEW);                 // bude se menit modelova matice
    glLoadIdentity();                           // nahrat jednotkovou matici
}



//---------------------------------------------------------------------
// Funkce pro nastaveni orezavaci roviny
//---------------------------------------------------------------------
void setClipPlane(void)
{
    GLdouble dir=1.0;                           // je bud -1 nebo 1 podle orientace normaly
    GLdouble equation[]={0.0f, 0.0f, 0.0f, 0.0f};// parametry A, B, C, D ze vztahu Ax+By+Cz+D=0

    if (clipPlaneDirection==COMMAND_CLIP_PLANE_NEGATIVE_DIRECTION)
        dir=-1.0;                               // podle vyberu z menu se muze zmenit orientace normaly

    switch (clipPlaneNormal) {                  // zmena smeru normaly
        case COMMAND_CLIP_PLANE_XY: equation[2]=dir; break;
        case COMMAND_CLIP_PLANE_XZ: equation[1]=dir; break;
        case COMMAND_CLIP_PLANE_YZ: equation[0]=dir; break;
    }
    equation[3]=clipPlaneDistance-COMMAND_CLIP_PLANE_DIST_0;// vzdalenost orezavaci roviny
    glClipPlane(GL_CLIP_PLANE0, equation);      // nastaveni orezavaci roviny
}



//---------------------------------------------------------------------
// Vypsani retezce do okna na pozici [x,y]
//---------------------------------------------------------------------
void printString(int x, int y, char *text)
{
    glRasterPos2i(x, y);                        // pozice prvniho znaku retezce
    for (; *text; text++)                       // pruchod retezcem
        glutBitmapCharacter(GLUT_BITMAP_9_BY_15, *text);// vykresleni jednoho znaku
}



//--------------------------------------------------------------------
// Vypsani informaci o nastavenych parametrech
//---------------------------------------------------------------------
void drawInfoText(void)
{
    char str[100];
    int  ce=glIsEnabled(GL_CLIP_PLANE0);
    glDisable(GL_CLIP_PLANE0);                  // text by se mel vypsat vzdy, proto vypneme orezavani
    glColor3f(1.0,1.0,1.0);
    sprintf(str, "Rotation x:    %d", xnew);
    printString(10, 100, str);                  // vypsat rotaci ve smeru osy x
    sprintf(str, "Rotation y:    %d", ynew);
    printString(10, 85, str);                   // vypsat rotaci ve smeru osy y
    sprintf(str, "Translation:   %d", znew);
    printString(10, 70, str);                   // vypsat posun objektu od kamery
    sprintf(str, "Near plane:    %5.2f", nearPlane);
    printString(10, 55, str);                   // vzdalenost blizke orezavaci roviny
    sprintf(str, "Far plane:     %5.2f", farPlane);
    printString(10, 40, str);                   // vzdalenost vzdalene orezavaci roviny
    sprintf(str, "Field of view: %5.2f", fov);
    printString(10, 25, str);                   // zorny uhel kamery
    sprintf(str, "Clip plane:    %s", ce ? "enabled":"disabled");
    printString(10, 10, str);                   // povoleni ci zakazani orezavaci roviny
    if (ce) glEnable(GL_CLIP_PLANE0);           // opetovne zapnuti orezavani
}



//--------------------------------------------------------------------
// Vykresleni objektu
//---------------------------------------------------------------------
void drawObject(void)
{
    glBegin(GL_QUADS);                          // vykresleni otevrene krychle - sten domecku
        glColor3f(0.0f, 0.0f, 1.0f); glVertex3f(-5.0f, -5.0f, -5.0f);
        glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(-5.0f, -5.0f,  5.0f);
        glColor3f(0.0f, 1.0f, 1.0f); glVertex3f( 5.0f, -5.0f,  5.0f);
        glColor3f(1.0f, 0.0f, 0.0f); glVertex3f( 5.0f, -5.0f, -5.0f);

        glColor3f(1.0f, 0.0f, 1.0f); glVertex3f(-5.0f,  5.0f, -5.0f);
        glColor3f(1.0f, 1.0f, 0.0f); glVertex3f(-5.0f,  5.0f,  5.0f);
        glColor3f(1.0f, 1.0f, 1.0f); glVertex3f( 5.0f,  5.0f,  5.0f);
        glColor3f(0.0f, 0.0f, 1.0f); glVertex3f( 5.0f,  5.0f, -5.0f);

        glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(-5.0f, -5.0f, -5.0f);
        glColor3f(0.0f, 1.0f, 1.0f); glVertex3f(-5.0f, -5.0f,  5.0f);
        glColor3f(1.0f, 0.0f, 0.0f); glVertex3f(-5.0f,  5.0f,  5.0f);
        glColor3f(1.0f, 0.0f, 1.0f); glVertex3f(-5.0f,  5.0f, -5.0f);

        glColor3f(0.0f, 1.0f, 0.0f); glVertex3f( 5.0f, -5.0f, -5.0f);
        glColor3f(0.0f, 1.0f, 1.0f); glVertex3f( 5.0f, -5.0f,  5.0f);
        glColor3f(1.0f, 0.0f, 0.0f); glVertex3f( 5.0f,  5.0f,  5.0f);
        glColor3f(1.0f, 0.0f, 1.0f); glVertex3f( 5.0f,  5.0f, -5.0f);
    glEnd();

    glBegin(GL_TRIANGLES);                      // vykresleni strechy domecku z trojuhelniku
        glColor3f(0.0f, 0.0f, 1.0f); glVertex3f(-5.0f,  5.0f, -5.0f);
        glColor3f(0.0f, 1.0f, 1.0f); glVertex3f( 5.0f,  5.0f, -5.0f);
        glColor3f(1.0f, 1.0f, 1.0f); glVertex3f( 0.0f, 11.0f,  0.0f);

        glColor3f(1.0f, 0.0f, 0.0f); glVertex3f( 5.0f,  5.0f, -5.0f);
        glColor3f(1.0f, 1.0f, 0.0f); glVertex3f( 5.0f,  5.0f,  5.0f);
        glColor3f(1.0f, 1.0f, 1.0f); glVertex3f( 0.0f, 11.0f,  0.0f);

        glColor3f(0.0f, 1.0f, 0.0f); glVertex3f( 5.0f,  5.0f,  5.0f);
        glColor3f(0.0f, 1.0f, 1.0f); glVertex3f(-5.0f,  5.0f,  5.0f);
        glColor3f(1.0f, 1.0f, 1.0f); glVertex3f( 0.0f, 11.0f,  0.0f);

        glColor3f(0.0f, 1.0f, 0.0f); glVertex3f(-5.0f,  5.0f,  5.0f);
        glColor3f(1.0f, 1.0f, 0.0f); glVertex3f(-5.0f,  5.0f, -5.0f);
        glColor3f(1.0f, 1.0f, 1.0f); glVertex3f( 0.0f, 11.0f,  0.0f);
    glEnd();
}



//--------------------------------------------------------------------
// Tato funkce je volana pri kazdem prekresleni okna
//---------------------------------------------------------------------
void onDisplay(void)
{
    if (depthBufferEnabled)                     // podle povoleni pameti hloubky
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// vymazani barvoveho bufferu i pameti hloubky
    else
        glClear(GL_COLOR_BUFFER_BIT);           // vymazani vsech bitovych rovin barvoveho bufferu

    setOrthogonalProjection();                  // ortogonalni rezim pro kresleni 2D obrazku
    drawInfoText();                             // vypsat informace o nastaveni

    setPerspectiveProjection();                 // nastaveni perspektivni kamery
    glTranslatef(0.0f, 0.0f, -50.0f);           // posun objektu dale od kamery
    glTranslatef(0.0f, 0.0f, znew);             // priblizeni ci vzdaleni objektu podle pohybu kurzoru mysi
    glRotatef(ynew, 1.0f, 0.0f, 0.0f);          // rotace objektu podle pohybu kurzoru mysi
    glRotatef(xnew, 0.0f, 1.0f, 0.0f);
    setClipPlane();                             // nastaveni orezavaci roviny
    drawObject();                               // vykresleni objektu

    glFlush();                                  // provedeni a vykresleni vsech zmen
    glutSwapBuffers();                          // a prohozeni predniho a zadniho bufferu
}



//---------------------------------------------------------------------
// Tato funkce je volana pri stlaceni ASCII klavesy
//---------------------------------------------------------------------
void onKeyboard(unsigned char key, int x, int y)
{
    if (key>='A' && key<='Z')                   // uprava velkych pismen na mala
        key+='a'-'A';                           // pro zjednoduseni prikazu switch

    switch (key) {
        case 27:    exit(0);                            break;  // ukonceni aplikace
        case 'q':   exit(0);                            break;  // ukonceni aplikace
        case 'f':   onMenu(COMMAND_FULL_SCREEN);        break;  // prepnuti do full-screen rezimu
        case 'w':   onMenu(COMMAND_WINDOW);             break;  // prepnuti zpet do okna
        case 'e':   onMenu(COMMAND_ENABLE_DEPTH_TEST);  break;  // povoleni funkce pameti hloubky
        case 'd':   onMenu(COMMAND_DISABLE_DEPTH_TEST); break;  // zakazani funkce pameti hloubky
        case 'r':   onMenu(COMMAND_ROTATE);             break;  // rezim rotace objektu
        case 't':   onMenu(COMMAND_TRANSLATE);          break;  // rezim posunu objektu
        case 'z':   onMenu(COMMAND_NEAR_PLANE);         break;  // rezim posunu blizke orezavaci roviny
        case 'x':   onMenu(COMMAND_FAR_PLANE);          break;  // rezim posunu vzdalene orezavaci roviny
        case '[':   onMenu(COMMAND_CLIP_PLANE_ENABLE);  break;  // povoleni orezavani
        case ']':   onMenu(COMMAND_CLIP_PLANE_DISABLE); break;  // zakaz orezavani
        case '.':   fov--;  glutPostRedisplay();        break;  // zmenseni zorneho uhlu
        case ',':   fov++;  glutPostRedisplay();        break;  // zvetseni zorneho uhlu
        case '>':   fov-=5; glutPostRedisplay();        break;  // rychlejsi zmenseni zorneho uhlu
        case '<':   fov+=5; glutPostRedisplay();        break;  // rychlejsi zvetseni zorneho uhlu
        case '1':   onMenu(COMMAND_FRONT_FACE_DISABLE); break;  // zakaz vykresleni prednich sten
        case '2':   onMenu(COMMAND_FRONT_FACE_ENABLE);  break;  // povoleni vykresleni prednich sten
        case '3':   onMenu(COMMAND_FRONT_FACE_POINTS);  break;  // predni steny se vykresli jako body
        case '4':   onMenu(COMMAND_FRONT_FACE_LINES);   break;  // predni steny se vykresli jako usecky
        case '5':   onMenu(COMMAND_FRONT_FACE_POLYGONS);break;  // predni steny se vykresli jako polygony
        case '6':   onMenu(COMMAND_BACK_FACE_DISABLE);  break;  // zakaz vykresleni zadnich  sten
        case '7':   onMenu(COMMAND_BACK_FACE_ENABLE);   break;  // povoleni vykresleni zadnich sten
        case '8':   onMenu(COMMAND_BACK_FACE_POINTS);   break;  // zadni steny se vykresli jako body
        case '9':   onMenu(COMMAND_BACK_FACE_LINES);    break;  // zadni steny se vykresli jako usecky
        case '0':   onMenu(COMMAND_BACK_FACE_POLYGONS); break;  // zadni steny se vykresli jako polygony
        default:                                        break;
    }
}



//---------------------------------------------------------------------
// Tato funkce je volana pri stisku ci pusteni tlacitka mysi
//---------------------------------------------------------------------
void onMouseButton(int button, int state, int x, int y)
{
    if (button==GLUT_LEFT_BUTTON) {             // pri zmene stavu leveho tlacitka
        switch (operation) {
            case ROTATE:                        // rotace objektu
                if (state==GLUT_DOWN) {         // pri stlaceni tlacitka
                    xx=x;                       // zapamatovat pozici kurzoru mysi
                    yy=y;
                }
                else {                          // pri pusteni tlacitka
                    xold=xnew;                  // zapamatovat novy pocatek
                    yold=ynew;
                }
                glutPostRedisplay();            // prekresleni sceny
                break;
            case TRANSLATE:                     // posun objektu
                if (state==GLUT_DOWN) zz=y;     // pri stlaceni tlacitka zapamatovat polohu kurzoru mysi
                else zold=znew;                 // pri pusteni tlacitka zapamatovat novy pocatek
                glutPostRedisplay();            // prekresleni sceny
                break;
            case NEAR_PLANE:                    // zmena polohy blizke orezavaci roviny
                if (state==GLUT_DOWN) npp=y;    // pri stlaceni tlacitka zapamatovat polohu kurzoru mysi
                else np_old=np_new;
                break;
            case FAR_PLANE:                     // zmena polohy vzdalene orezavaci roviny
                if (state==GLUT_DOWN) fpp=y;    // pri stlaceni tlacitka zapamatovat polohu kurzoru mysi
                else fp_old=fp_new;
                break;
            default:
                break;
        }
    }
}



//---------------------------------------------------------------------
// Tato funkce je volana pri pohybu mysi se stlacenym tlacitkem.
// To, ktere tlacitko je stlaceno si musime predem zaznamenat do
// globalni promenne stav ve funkci onMouseButton()
//---------------------------------------------------------------------
void onMouseMotion(int x, int y)
{
    switch (operation) {
        case ROTATE:                            // stav rotace objektu
            xnew=xold+x-xx;                     // vypocitat novou pozici
            ynew=yold+y-yy;
            glutPostRedisplay();                // a prekreslit scenu
            break;
        case TRANSLATE:                         // stav priblizeni/oddaleni objektu
            znew=zold+y-zz;                     // vypocitat novou pozici
            glutPostRedisplay();                // a prekreslit scenu
            break;
        case NEAR_PLANE:                        // priblizeni/vzdaleni blizke orezavaci roviny
            np_new=np_old+y-npp;
            nearPlane=np_new/100.0;
            onResize(windowWidth, windowHeight);// zmena projekcni matice
            glutPostRedisplay();                // a prekreslit scenu
            break;
        case FAR_PLANE:                         // priblizeni/vzdaleni vzdalene orezavaci roviny
            fp_new=fp_old+y-fpp;
            farPlane=fp_new/10.0;
            onResize(windowWidth, windowHeight);// zmena projekcni matice
            glutPostRedisplay();                // a prekreslit scenu
            break;
    }
}



//---------------------------------------------------------------------
// Hlavni funkce konzolove aplikace
//---------------------------------------------------------------------
int main(int argc, char **argv)
{
    glutInit(&argc, argv);                      // inicializace knihovny GLUT
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);// nastaveni dvou barvovych bufferu a pameti hloubky
    glutInitWindowPosition(30, 30);             // pocatecni pozice leveho horniho rohu okna
    glutInitWindowSize(500, 500);               // pocatecni velikost okna
    glutCreateWindow("Priklad na OpenGL cislo 31");// vytvoreni okna pro kresleni
    glutDisplayFunc(onDisplay);                 // registrace funkce volane pri prekreslovani okna
    glutReshapeFunc(onResize);                  // registrace funkce volane pri zmene velikosti okna
    glutKeyboardFunc(onKeyboard);               // registrace funkce volane pri stlaceni klavesy
    glutMouseFunc(onMouseButton);               // registrace funkce volane pri stlaceni ci pusteni tlacitka
    glutMotionFunc(onMouseMotion);              // registrace funkce volane pri pohybu mysi se stlacenym tlacitkem
    onInit();                                   // inicializace vykreslovani
    glutMainLoop();                             // nekonecna smycka, kde se volaji zaregistrovane funkce
    return 0;                                   // navratova hodnota vracena operacnimu systemu
}



//---------------------------------------------------------------------
// Konec zdrojoveho souboru
//---------------------------------------------------------------------