#ifndef CAMERA_MESH_H
#define CAMERA_MESH_H

#include "define.h"

struct TextureInfo
{
    GLuint texture[3];  //textures
    int iWidth;
    int iHeight;
    uchar* buf;
    bool m_bTextureArrived;
    bool bDirty;        // a dirty flag for check whether texture image is updated or not.
    GLenum fmt;
};

class CCameraViewMesh
{
public:
    CCameraViewMesh() : m_bRatioAdjusted(false)
    {
        UpdateGeometry(1.0f);
        ResetMatrix();
        memset(&m_textureInfo, 0, sizeof(m_textureInfo));
        m_textureInfo.buf = NULL;
    }
    ~CCameraViewMesh(){}

    void ResetMatrix()
    {
        m_TransMatrix.identity();
        m_HomoMatrix.identity();
    }

    void UpdateGeometry(double ratioH2W)
    {
        double PlaneHalfW = gPlaneHalfW;
        double PlaneHalfH = gPlaneHalfW * ratioH2W;

        memset(m_VertexArr, 0, sizeof(m_VertexArr));
        memset(m_TextureArr, 0, sizeof(m_TextureArr));

        double dHeight = PlaneHalfH*2;
        for(int f=0; f<NumOfFace; f++)
        {
            int a = f%NumOfFace_sqrt;
            int b = f/NumOfFace_sqrt;

            // Vertex
            m_VertexArr[f][0] = -PlaneHalfW+(double)a/NumOfFace_sqrt;
            m_VertexArr[f][1] = -PlaneHalfH+(double)b*dHeight/NumOfFace_sqrt;
            m_VertexArr[f][2] = 0.5;

            m_VertexArr[f][3] = -PlaneHalfW+(double)(a+1)/NumOfFace_sqrt;
            m_VertexArr[f][4] = -PlaneHalfH+(double)b*dHeight/NumOfFace_sqrt;
            m_VertexArr[f][5] = 0.5;

            m_VertexArr[f][6] = -PlaneHalfW+(double)(a+1)/NumOfFace_sqrt;
            m_VertexArr[f][7] = -PlaneHalfH+(double)(b+1)*dHeight/NumOfFace_sqrt;
            m_VertexArr[f][8] = 0.5;

            m_VertexArr[f][9] = -PlaneHalfW+(double)a/NumOfFace_sqrt;
            m_VertexArr[f][10]= -PlaneHalfH+(double)(b+1)*dHeight/NumOfFace_sqrt;
            m_VertexArr[f][11]= 0.5;

            // Texture
            m_TextureArr[f][0] = (double)a/NumOfFace_sqrt;
            m_TextureArr[f][1] = 1.0 - (double)(b)/NumOfFace_sqrt;

            m_TextureArr[f][2] = (double)(a+1)/NumOfFace_sqrt;
            m_TextureArr[f][3] = 1.0 - (double)(b)/NumOfFace_sqrt;

            m_TextureArr[f][4] = (double)(a+1)/NumOfFace_sqrt;
            m_TextureArr[f][5] = 1.0 - (double)(b+1)/NumOfFace_sqrt;

            m_TextureArr[f][6] = (double)a/NumOfFace_sqrt;
            m_TextureArr[f][7] = 1.0 - (double)(b+1)/NumOfFace_sqrt;
        }
    }

    void AdjustAspectRatio(double winRatio, double imgRatio)
    {
        // Keep video aspect ratio without modifying polygon geometry.
        float x = 0.0;
        float y = 1.0;
        double diff;
        double range_x = 1.0, range_y = 1.0;
        if(winRatio > imgRatio)
        {
            // put margin on left and right hand sides
            diff = (winRatio/imgRatio-1.0);
            range_x = winRatio/imgRatio;
            x -= diff/2;
        }
        else
        {
            // put margin on top and bottom sides
            diff = (imgRatio/winRatio-1.0);
            range_y = imgRatio/winRatio;
            y += diff/2;
        }

        for(int f=0; f<NumOfFace; f++)
        {
            int a = f%NumOfFace_sqrt;
            int b = f/NumOfFace_sqrt;

            // Texture
            m_TextureArr[f][0] = x + (double)a*range_x/NumOfFace_sqrt;
            m_TextureArr[f][1] = y - (double)(b)*range_y/NumOfFace_sqrt;

            m_TextureArr[f][2] = x + (double)(a+1)*range_x/NumOfFace_sqrt;
            m_TextureArr[f][3] = y - (double)(b)*range_y/NumOfFace_sqrt;

            m_TextureArr[f][4] = x + (double)(a+1)*range_x/NumOfFace_sqrt;
            m_TextureArr[f][5] = y - (double)(b+1)*range_y/NumOfFace_sqrt;

            m_TextureArr[f][6] = x + (double)a*range_x/NumOfFace_sqrt;
            m_TextureArr[f][7] = y - (double)(b+1)*range_y/NumOfFace_sqrt;
        }

        m_bRatioAdjusted = true;
    }

    void ApplyHomography()
    {
//         CvMat *Homography = cvCreateMat(3,3,CV_64FC1);
//         for(int j=0; j<9; j++)
//             cvmSet(Homography, j%3, j/3, m_HomoMatrix.values[j]);
// 
//         double inputVertex[3];
//         double resultVertex[3];
//         double LeftBottom[2] = {m_VertexArr[0][0], m_VertexArr[0][1]};
//         for(int f=0; f<NumOfFace; f++ )
//         {
//             for(int j=0; j<4; j++)
//             {
//                 CvMat vector = cvMat(3,1,CV_64FC1, inputVertex);
//                 CvMat vector2 = cvMat(3,1,CV_64FC1, resultVertex);
// 
//                 inputVertex[0] = m_VertexArr[f][j*3] - LeftBottom[0];
//                 inputVertex[1] = m_VertexArr[f][j*3+1] - LeftBottom[1];
//                 inputVertex[2] = 1.0;
// 
//                 cvMatMul(Homography, &vector, &vector2);
// 
//                 resultVertex[0] /= resultVertex[2];
//                 resultVertex[1] /= resultVertex[2];
// 
//                 m_VertexArr[f][j*3]   = resultVertex[0] + LeftBottom[0];
//                 m_VertexArr[f][j*3+1] = resultVertex[1] + LeftBottom[1];
//             }
//         }// end of for(f)
// 
//         cvReleaseMat(&Homography);
    }

    bool IsRatioAdjusted(){ return m_bRatioAdjusted; }
    void AdjustGeometry(double ratioH2W)
    {
        // Update the correct aspect ratio and apply homograph matrix to estimate the warped mesh.
        UpdateGeometry(ratioH2W);
        ApplyHomography();

        m_bRatioAdjusted = true;
    }

public:
    float m_VertexArr[NumOfFace][12];
    float m_TextureArr[NumOfFace][8];

    Matrix4X4 m_TransMatrix;
    Matrix3X3 m_HomoMatrix;
    TextureInfo m_textureInfo;

private:
    bool m_bRatioAdjusted;
};
#endif