// Listing 9.4. Delikatnie zmodyfikowany kod z dokumentacji OpenCV,
// który w każdej klatce rysuje sześcian. W wersji tej utworzyliśmy
// globalne zmienne rotx i roty i połączyliśmy ich wartości z suwakami widocznymi na rysunku 9.6
// Uwaga: ten program wymaga biblioteki OpenGL. Jeśli jej nie będzie, 
//       nie da się skompilować.
#include <GL/gl.h>
#include <GL/glu.h>

#include <opencv2/opencv.hpp>
#include <opencv2/core/opengl.hpp>
#include <iostream>

using namespace std;

int rotx = 55, roty = 40;

void on_opengl(void* param) {
    cv::ogl::Texture2D* backgroundTex = (cv::ogl::Texture2D*)param;
    glEnable( GL_TEXTURE_2D );
    backgroundTex->bind();
    cv::ogl::render(*backgroundTex);
    glDisable( GL_TEXTURE_2D );

    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
    glTranslatef(0, 0, -0.5);
    glRotatef( rotx, 1, 0, 0 );
    glRotatef( roty, 0, 1, 0 );
    glRotatef( 0, 0, 0, 1 );
    glEnable( GL_DEPTH_TEST );
    glDepthFunc( GL_LESS );
    static const int coords[6][4][3] = {
        { { +1, -1, -1 }, { -1, -1, -1 }, { -1, +1, -1 }, { +1, +1, -1 } },
        { { +1, +1, -1 }, { -1, +1, -1 }, { -1, +1, +1 }, { +1, +1, +1 } },
        { { +1, -1, +1 }, { +1, -1, -1 }, { +1, +1, -1 }, { +1, +1, +1 } },
        { { -1, -1, -1 }, { -1, -1, +1 }, { -1, +1, +1 }, { -1, +1, -1 } },
        { { +1, -1, +1 }, { -1, -1, +1 }, { -1, -1, -1 }, { +1, -1, -1 } },
        { { -1, -1, +1 }, { +1, -1, +1 }, { +1, +1, +1 }, { -1, +1, +1 } }
    };
    for (int i = 0; i < 6; ++i) {
        glColor3ub( i*20, 100+i*10, i*42 );
        glBegin( GL_QUADS );
        for (int j = 0; j < 4; ++j) {
            glVertex3d(
                        0.2 * coords[i][j][0],
                    0.2 * coords[i][j][1],
                    0.2 * coords[i][j][2]
                    );
        }
        glEnd();
    }
}

void on_trackbar( int, void* ) {
    cv::updateWindow( "Listing 9.4" );
}

void help(char ** argv) {
	
	cout << "\n//Listing 9.4. Delikatnie zmodyfikowany kod z dokumentacji OpenCV,"
		<< "\n//który w każdej klatce rysuje sześcian. W wersji tej utworzyliśmy"
		<< "\n//globalne zmienne rotx i roty i połączyliśmy ich wartości z suwakami widocznymi na rysunku 9.6"
		<< "\n// Uwaga: ten program wymaga biblioteki OpenGL. Jeśli jej nie będzie, " 
		<< "\n//       nie da się skompilować.\n\/"
		<< "\nWywołanie: " << argv[0] << " <image>\n\n"
		<< "\nBiblioteka OpenGL jest używana do renderowania sześcianu na obrazie.\n"
        << "\nUżytkownik może obracać sześcian za pomocą suwaków.\n" <<endl;
}

int main(int argc, char* argv[])
{
    if(argc != 2) {
        help (argv);
        return -1;
    }

    cv::Mat img = cv::imread(argv[1]);
    if( img.empty() ) {
        cout << "Nie udało się załadować " << argv[1] << endl;
        return -1;
    }

    cv::namedWindow( "Listing 9.4", CV_WINDOW_OPENGL );
    cv::resizeWindow("Listing 9.4", img.cols, img.rows);
    cv::createTrackbar( "Obrów wg osi X", "Listing 9.4", &rotx, 360, on_trackbar);
    cv::createTrackbar( "Obrót wg osi Y", "Listing 9.4", &roty, 360, on_trackbar);

    cv::ogl::Texture2D backgroundTex(img);
    cv::setOpenGlDrawCallback("Listing 9.4", on_opengl, &backgroundTex);
    cv::updateWindow("Listing 9.4");

    cv::waitKey(0);

    cv::setOpenGlDrawCallback("Listing 9.4", 0, 0);
    cv::destroyAllWindows();

    return 0;
}
