//---------------------------------------------------------------------
// Ukazkovy priklad k serii clanku o graficke knihovne OpenGL a GLU
//
// Autor:          Pavel Tisnovsky
// Cislo clanku:   20
// Cislo prikladu: 1
//
// Program otevre jedno hlavni okno a vykresli do nej slozitejsi
// polygon vytvoreny pomoci teselatoru. Okno (a tim i celou aplikaci)
// lze ukoncit stiskem klavesy ESC.
//---------------------------------------------------------------------

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>                                // hlavickovy soubor funkci GLUTu
#include <stdlib.h>
#include <stdio.h>

#define WINDOW_WIDTH    450                         // velikost okna
#define WINDOW_HEIGHT   250
#define WINDOW_TITLE    "OpenGL a GLU, priklad 20.1"// titulek okna

#ifndef CALLBACK
#define CALLBACK
#endif

GLdouble currentWinding = GLU_TESS_WINDING_ODD;
GLUtesselator *gluTessObject;



//---------------------------------------------------------------------
// Nastaveni souradneho systemu v zavislosti na velikosti okna
//---------------------------------------------------------------------
void onResize(int w, int h)                         // w a h reprezentuje novou velikost okna
{
    glViewport(0, 0, w, h);                         // viditelna oblast pres cele okno
    glMatrixMode(GL_PROJECTION);                    // zacatek modifikace projekcni matice
    glLoadIdentity();                               // vymazani projekcni matice (=identita)
    glOrtho(0, w, 0, h, -1, 1);                     // mapovani abstraktnich souradnic do souradnic okna
    glTranslatef(0.0, h, 0.0);
    glScalef(1.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}



//---------------------------------------------------------------------
// Callback funkce volana pri zahajeni vykreslovani graficke primitivy
//---------------------------------------------------------------------
void CALLBACK callbackBegin(GLenum which)
{
    glBegin(which);
}



//---------------------------------------------------------------------
// Callback funkce volana pri ukonceni vykreslovani graficke primitivy
//---------------------------------------------------------------------
void CALLBACK callbackEnd(void)
{
   glEnd();
}



//---------------------------------------------------------------------
// Callback funkce volana pri vyskytu chyby
//---------------------------------------------------------------------
void CALLBACK callbackError(GLenum errorCode)
{
   const GLubyte *s=gluErrorString(errorCode);
   fprintf(stderr, "chyba pri teselaci: %s\n", s);
   exit(0);
}



//---------------------------------------------------------------------
// Tato funkce je volana pri kazdem prekresleni okna
//---------------------------------------------------------------------
void onDisplay(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);               // nastaveni mazaci barvy na cernou
    glClear(GL_COLOR_BUFFER_BIT);                   // vymazani bitovych rovin barvoveho bufferu
    glShadeModel(GL_FLAT);
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);      // rezim vykreslovani polygonu

    glColor3f(1.0f, 1.0f, 1.0f);                    // nastaveni barvy pro kresleni
    glBegin(GL_POLYGON);                            // vykresleni konvexniho polygonu
        glVertex2i( 50, 100);
        glVertex2i(100,  50);
        glVertex2i(150,  50);
        glVertex2i(200, 100);
        glVertex2i(200, 150);
        glVertex2i(150, 200);
        glVertex2i(100, 200);
        glVertex2i( 50, 150);
    glEnd();

    gluTessObject=gluNewTess();                      // vytvoreni objektu pro teselaci
    gluTessCallback(gluTessObject, GLU_TESS_VERTEX, glVertex3dv);
    gluTessCallback(gluTessObject, GLU_TESS_BEGIN, callbackBegin);
    gluTessCallback(gluTessObject, GLU_TESS_END, callbackEnd);
    gluTessCallback(gluTessObject, GLU_TESS_ERROR, callbackError);
    gluTessProperty(gluTessObject, GLU_TESS_WINDING_RULE, currentWinding);
    gluTessBeginPolygon(gluTessObject, NULL);        // zahajeni noveho polygonu
        gluTessBeginContour(gluTessObject);          // zahajeni nove kontury
            GLdouble vertex[][3]={
                {250, 100},
                {300,  50},
                {350,  50},
                {400, 100},
                {400, 150},
                {350, 200},
                {300, 200},
                {250, 150}
            };

            // specifikace jednotlivych vrcholu kontury
            gluTessVertex(gluTessObject, vertex[0], vertex[0]);
            gluTessVertex(gluTessObject, vertex[1], vertex[1]);
            gluTessVertex(gluTessObject, vertex[2], vertex[2]);
            gluTessVertex(gluTessObject, vertex[3], vertex[3]);
            gluTessVertex(gluTessObject, vertex[4], vertex[4]);
            gluTessVertex(gluTessObject, vertex[5], vertex[5]);
            gluTessVertex(gluTessObject, vertex[6], vertex[6]);
            gluTessVertex(gluTessObject, vertex[7], vertex[7]);
        gluTessEndContour(gluTessObject);           // konec specifikace kontury
    gluTessEndPolygon(gluTessObject);               // konec specifikace polygonu
    gluDeleteTess(gluTessObject);                   // zruseni objektu teselatoru

    glFlush();                                      // provedeni a vykresleni zmen
}



//---------------------------------------------------------------------
// Tato funkce je volana pri stlaceni ASCII klavesy
//---------------------------------------------------------------------
void onKeyboard(unsigned char key, int x, int y)
{
    if (key==27) exit(0);                           // pokud byla stlacena klavesa ESC, konec programu
}



//---------------------------------------------------------------------
// Hlavni funkce konzolove aplikace
//---------------------------------------------------------------------
int main(int argc, char **argv)
{
    glutInit(&argc, argv);                          // inicializace knihovny GLUT
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);    // nastaveni jednoho barvoveho bufferu
    glutInitWindowPosition(30, 30);                 // pocatecni pozice leveho horniho rohu okna
    glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);// pocatecni velikost okna
    glutCreateWindow(WINDOW_TITLE);                 // 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
    glutMainLoop();                                 // nekonecna smycka, kde se volaji zaregistrovane funkce
    return 0;                                       // navratova hodnota vracena operacnimu systemu
}



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