//---------------------------------------------------------------------
// Priklad cislo 9
// Autor: Pavel Tisnovsky
//
// Zpracovani udalosti od mysi - zachyceni pohybu mysi
//---------------------------------------------------------------------

#include <GL/glut.h>                    // hlavickovy soubor funkci GLUTu
#include <math.h>

enum {
    None,
    LeftButton,
    RightButton
} status=None;                          // stav tlacitek mysi

int   oldX=200, oldY=200;               // stara pozice stredu trojuhelnika
int   newX=200, newY=200;               // nova pozice stredu trojuhelnika
int   mouseX=0, mouseY=0;               // body, ve kterych se nachazi kurzor mysi
float newAngle, oldAngle, rotAngle=0.0; // uhel rotace sipky okolo sveho stredu



//---------------------------------------------------------------------
// 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
    glScalef(1, -1, 1);                 // inverze y-ove osy, aby se y zvetsovalo smerem dolu
    glTranslatef(0, -h, 0);             // posun pocatku do leveho horniho rohu
}



//---------------------------------------------------------------------
// Tato funkce je volana pri kazdem prekresleni okna
//---------------------------------------------------------------------
void onDisplay(void)
{
    glClear(GL_COLOR_BUFFER_BIT);       // vymazani bitovych rovin barvoveho bufferu
    glMatrixMode(GL_MODELVIEW);         // bude se menit matice modelview
    glLoadIdentity();                   // vynulovani predchozi transformace
    glTranslatef(newX, newY, 0);        // posun sipky
    glRotatef(rotAngle*180.0/3.14, 0, 0, 1.0);// rotace sipky

    glBegin(GL_TRIANGLES);              // zacatek vykreslovani trojuhelniku
        glColor3f(0.0, 0.0, 1.0);       // barva prvniho vertexu
        glVertex2i(0, -70);             // poloha prvniho vertexu
        glColor3f(0.0, 1.0, 0.0);       // barva druheho vertexu
        glVertex2i(-50, 100);           // poloha druheho vertexu
        glColor3f(1.0, 0.0, 0.0);       // barva tretiho vertexu
        glVertex2i(50, 100);            // poloha tretiho vertexu
    glEnd();
    glFlush();                          // provedeni a vykresleni zmen
}



//---------------------------------------------------------------------
// Tato funkce je volana pri stlaceni ASCII klavesy
//---------------------------------------------------------------------
void onKeyboard(unsigned char key, int x, int y)
{
    key=(key>'A' && key<='Z') ? key+'a'-'A':key; // prevod na mala pismena
    switch (key) {
        case 27:                        //  Escape
            exit(0);
            break;
        case 'f':
            glutFullScreen();           // prepnuti na celou obrazovku
            break;
        case 'w':
            glutReshapeWindow(400, 400);// prepnuti zpet do okna
            glutPositionWindow(50, 50);
            break;
        default:
            break;
    }
}



//---------------------------------------------------------------------
// Tato funkce je volana pri stlaceni nebo pusteni tlacitka mysi
//---------------------------------------------------------------------
void onMouse(int button, int state, int x, int y)
{
    switch(button) {                    // ktere tlacitko je stlaceno?
        case GLUT_LEFT_BUTTON:          // leve tlacitko
            if (state==GLUT_DOWN) {     // pri stlaceni
                status=LeftButton;      // nastaveni pro funkci motion
                mouseX=x; mouseY=y;     // zapamatovat pozici kurzoru mysi
            }
            else {                      // GLUT_UP
                status=None;            // normalni stav
                oldX=newX; oldY=newY;   // zapamatovat novy stred trojuhelnika
            }
            break;

        case GLUT_RIGHT_BUTTON:         // prave tlacitko
            if (state==GLUT_DOWN) {     // pri stlaceni
                status=RightButton;     // nastaveni pro funkci motion
                newAngle=atan2(y-newY,x-newX);// vypocitat uhel vektoru od pozice kurzoru mysi
            }
            else {                      // GLUT_UP
                status=None;            // normalni stav
                oldAngle=rotAngle;      // zapamatovat novy uhel natoceni trojuhelnika
            }
            break;

    }
    glutPostRedisplay();                // prekresleni sceny
}



//---------------------------------------------------------------------
// Tato funkce je volana pri pohybu mysi se soucasne stlacenym tlacitkem
//---------------------------------------------------------------------
void onMouseMotion(int x, int y)
{
    if (status==LeftButton) {           // stav presunu trojuhelnika
        newX=oldX+x-mouseX;             // vypocitat novou pozici stredu
        newY=oldY+y-mouseY;
        glutPostRedisplay();            // a prekreslit scenu
    }

    if (status==RightButton) {          // stav otoceni trojuhelnika
        rotAngle=oldAngle+atan2(y-newY, x-newX)-newAngle;// vypocitat novy uhel natoceni
        glutPostRedisplay();            // a prekreslit scenu
    }

}



//---------------------------------------------------------------------
// Hlavni funkce konzolove aplikace
//---------------------------------------------------------------------
int main (int argc, char **argv)
{
    glutInit(&argc, argv);              // inicializace knihovny GLUT
    glutInitDisplayMode(GLUT_RGBA|GLUT_SINGLE);// graficky mod okna
    glutInitWindowSize(400, 400);       // pocatecni velikost okna
    glutInitWindowPosition(10, 10);     // pocatecni pozice okna
    glutCreateWindow("Priklad cislo 9");// vytvoreni okna pro kresleni
    glutDisplayFunc(onDisplay);         // registrace funkce volane pri prekreslovani
    glutReshapeFunc(onResize);          // registrace funkce volane pri zmene velikosti
    glutKeyboardFunc(onKeyboard);       // registrace funkce volane pri stisku klavesy
    glutMouseFunc(onMouse);             // registrace funkce volane pri stisku tlacitek mysi
    glutMotionFunc(onMouseMotion);      // registrace funkce volane pri pohybu mysi
    glutMainLoop();                     // nekonecna smycka, kde se volaji zaregistrovane fce
    return 0;                           // navratova hodnota vracena operacnimu systemu
}



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