#include "Avm_3DRender.h"
#include "CELLMath.h"
#include "Bowl.h"
#include "Car.h"
#include "Line.h"
#include "PlanView.h"

#define MODULE_NAME "AVM_3DRender"
#define AVM_DEBUG_SWITCH       0
#include "Avm_log.h"


extern GLuint programCar;
extern CObj * pCObj;

static   int  g_From2Dto3D = 0;
static   int  g_3Dstepcount = 0;
static float  g_Fovy[2] = {30.0, 30.0};

static CELL::matrix4     matView;
static CELL::matrix4     Perspect_2D;
static CELL::matrix4     Perspect_3D;
static float            *pPerspect_2D;
static float            *pPerspect_3D;


/*****************functions Lev 3**********************************/
void SetCamMat_TopView()
{
    static CELL::float3    eye_cur  = CELL::float3(0.0, 16.5,  0.0);
    static CELL::float3    look_cur = CELL::float3(0.0,  0.0,  0.0);
    static CELL::float3    up_cur   = CELL::float3(0.0,  0.0,  -1.0);

    matView = CELL::lookAt(eye_cur, look_cur, up_cur);

/*
    glUseProgram(programCar);
    glUniformMatrix4fv(glGetUniformLocation(programCar, "car_matView"), 1, GL_FALSE, matView.data());
    glUniformMatrix4fv(glGetUniformLocation(programCar, "car_projection"),    1, GL_FALSE, pPerspect_2D);
    glUseProgram(0);

    SetMatrix_Bowl(matView.data(), pPerspect_2D);
//    SetMatrix_Tracks(matView.data(), pPerspect_2D);
*/

}


void SetCamMat_FixedPos(int whichPos)
{
    static UChar typenum = 1;
    static UChar pre_typenum = 1;
    static int MoveSpeed = 20;

    static CELL::float3    _eye;
    static CELL::float3    _look;
    static CELL::float3    _up;

    static CELL::float3    eye_sub;
    static CELL::float3    look_sub;
    static CELL::float3    up_sub;

    //default position: front
    static CELL::float3    eye_cur  = CELL::float3(0.0, 2.0, -10.0);
    static CELL::float3    look_cur = CELL::float3(0.0, 0.0,  1.5);
    static CELL::float3    up_cur   = CELL::float3(0.0, 1.0, 0.0);

    if (0 == g_3Dstepcount)
    {
        typenum = whichPos;
    }

    if ((typenum != pre_typenum) && (typenum <= 8) && (typenum >= 1)
        && (pre_typenum <= 8) && (pre_typenum >= 1) && (0 == g_3Dstepcount) && (1 == g_From2Dto3D))
    {
        int typesub = typenum - pre_typenum;
        int abstypesub = typesub > 0? typesub : (0 - typesub);
        switch (abstypesub)
        {
            case 1:
                MoveSpeed = 10;
                break;
            case 2:
                MoveSpeed = 15;
                break;
            case 3:
                MoveSpeed = 25;
                break;
            case 4:
                typenum = 100;
                MoveSpeed = 10;
                break;
            default:
                MoveSpeed = 10;
        }
    }
    AVM_DEBUG("typenum=%d, pre_typenum=%d, MoveSpeed=%d, g_3Dstepcount=%d, g_From2Dto3D=%d\n",
                typenum, pre_typenum, MoveSpeed, g_3Dstepcount, g_From2Dto3D);
    if (1 == typenum)
    {
        //front
        _eye = CELL::float3(0.0, 3.2, -10.0);
        _look = CELL::float3(0.0, 0.0, 0.3);
        _up   =   CELL::float3(0.0, 1.0, 0.0);
        if (0 == g_From2Dto3D)
        {
            eye_cur  = CELL::float3(0.0, 3.2, -10.0);
            look_cur = CELL::float3(0.0, 0.0, 0.3);
            up_cur   = CELL::float3(0.0, 1.0,  0.0);
        }
    }
    else if (2 == typenum)
    {
        //left front
        _eye = CELL::float3(-5.5, 4.7, -9.1);
        _look = CELL::float3(2.4, -1.6, 4.0);
        _up   =   CELL::float3(0.0, 1.0, 0.0);
        if (0 == g_From2Dto3D)
        {
            eye_cur  = CELL::float3(-5.5, 4.7, -9.1);
            look_cur = CELL::float3(2.4, -1.6, 4.0);
            up_cur   = CELL::float3(0.0, 1.0,  0.0);
        }
    }
    else if (3 == typenum)
    {
        /* left */
        _eye = CELL::float3(-9.7, 6.5, 0.0);
        _look = CELL::float3(0.0, 0.5, 0.0);
        _up   =   CELL::float3(0.0, 1.0, 0.0);
        if (0 == g_From2Dto3D)
        {
            eye_cur  = CELL::float3(-9.7, 6.5, 0.0);
            look_cur = CELL::float3(0.0, 0.5, 0.0);
            up_cur   = CELL::float3(0.0, 1.0, 0.0);
        }
    }
    else if (4 == typenum)
    {
        //left back
        _eye = CELL::float3(-4.1, 3.2, 9.1);
        _look = CELL::float3(4.7, -3.4, -10.9);
        _up   =   CELL::float3(0.0, 1.0, 0.0);

        if (0 == g_From2Dto3D)
        {
            eye_cur  = CELL::float3(-4.1, 3.2, 9.1);
            look_cur = CELL::float3(4.7, -3.4, -10.9);
            up_cur   = CELL::float3(0.0, 1.0,  0.0);
        }
    }
    else if (5 == typenum)
    {
        //back
        _eye = CELL::float3(0.0, 3.2, 10.0);
        _look = CELL::float3(0.0, 0.0, -0.3);
        _up   =   CELL::float3(0.0, 1.0, 0.0);
        if (0 == g_From2Dto3D)
        {
            eye_cur  = CELL::float3(0.0, 3.2, 10.0);
            look_cur = CELL::float3(0.0, 0.0, -0.3);
            up_cur   = CELL::float3(0.0, 1.0, 0.0);
        }
    }
    else if (6 == typenum)
    {
        //right back
        _eye = CELL::float3(4.1, 3.2, 9.1);
        _look = CELL::float3(-4.7, -3.4, -10.9);
        _up   =   CELL::float3(0.0, 1.0, 0.0);
        if (0 == g_From2Dto3D)
        {
            eye_cur  = CELL::float3(4.1, 3.2, 9.1);
            look_cur = CELL::float3(-4.7, -3.4, -10.9);
            up_cur   = CELL::float3(0.0, 1.0,  0.0);
        }
    }
    else if (7 == typenum)
    {
        /* right */
        _eye = CELL::float3(9.7, 6.5, 0.0);
        _look = CELL::float3(0.0, 0.5, 0.0);
        _up   =   CELL::float3(0.0, 1.0, 0.0);
        if (0 == g_From2Dto3D)
        {
            eye_cur  = CELL::float3(9.7, 6.5, 0.0);
            look_cur = CELL::float3(0.0, 0.5, 0.0);
            up_cur   = CELL::float3(0.0, 1.0, 0.0);
        }
    }
    else if (8 == typenum)
    {
        //right front
        _eye = CELL::float3(5.5, 4.7, -9.1);
        _look = CELL::float3(-2.4, -1.6, 4.0);
        _up   =   CELL::float3(0.0, 1.0, 0.0);
        if (0 == g_From2Dto3D)
        {
            eye_cur  = CELL::float3(5.5, 4.7, -9.1);
            look_cur = CELL::float3(-2.4, -1.6, 4.0);
            up_cur   = CELL::float3(0.0, 1.0,  0.0);
        }
    }
    else if (9 == typenum)
    {
        /* lookdown front*/
        _eye = CELL::float3(0.0, 7.6, -1.7);
        _look = CELL::float3(0.0, 0.0, -3.2);
        _up   =   CELL::float3(0.0, 0.0, -1.0);

        eye_cur  = CELL::float3(0.0, 7.6, -1.7);
        look_cur = CELL::float3(0.0, 0.0, -3.2);
        up_cur   = CELL::float3(0.0, 0.0, -1.0);

    }
    else if (10 == typenum)
    {
        /* lookdown back*/
        _eye = CELL::float3(0.0, 7.6, 1.7);
        _look = CELL::float3(0.0, 0.0, 3.2);
        _up   =   CELL::float3(0.0, 0.0, -1.0);

        eye_cur  = CELL::float3(0.0, 7.6, 1.7);
        look_cur = CELL::float3(0.0, 0.0, 3.2);
        up_cur   = CELL::float3(0.0, 0.0, -1.0);
    }
    else if (11 == typenum)        //front top view
    {
        _eye = CELL::float3(0.0, 5.0, 1.0);
        _look = CELL::float3(0.0, 0.0, -6.0);
        _up   =   CELL::float3(0.0, 1.0, 0.0);

        eye_cur  = CELL::float3(0.0, 5.0, 1.0);
        look_cur = CELL::float3(0.0, 0.0, -6.0);
        up_cur   = CELL::float3(0.0, 1.0,  0.0);
    }
    else if (12 == typenum)        //rear top view
    {
        _eye = CELL::float3(0.0, 5.0, -1.0);
        _look = CELL::float3(0.0, 0.0, 6.0);
        _up   =   CELL::float3(0.0, 1.0, 0.0);

        eye_cur  = CELL::float3(0.0, 5.0, 1.0);
        look_cur = CELL::float3(0.0, 0.0, 6.0);
        up_cur   = CELL::float3(0.0, 1.0,  0.0);
    }
    else    // typenum = 100
    {
        _eye = CELL::float3(0.0, 3.2, -10.0);
        _look = CELL::float3(0.0, 0.0, 0.3);
        _up   =   CELL::float3(0.0, 1.0, 0.0);
    }
    matView = CELL::lookAt(eye_cur, look_cur, up_cur);
/*
    glUseProgram(programCar);
    glUniformMatrix4fv(glGetUniformLocation(programCar, "car_matView"), 1, GL_FALSE, matView.data());
    glUniformMatrix4fv(glGetUniformLocation(programCar, "car_projection"),    1, GL_FALSE, pPerspect_3D);
    glUseProgram(0);

    SetMatrix_Bowl(matView.data(), pPerspect_2D);
//    SetMatrix_Tracks(matView.data(), pPerspect_2D);
*/
    if (typenum != pre_typenum)
    {
        g_3Dstepcount = MoveSpeed;
        eye_sub  = (_eye  - eye_cur)  / (float)g_3Dstepcount;
        look_sub = (_look - look_cur) / (float)g_3Dstepcount;
        up_sub   = (_up   - up_cur)   / (float)g_3Dstepcount;
    }
    AVM_DEBUG("g_3Dstepcount = %d\n", g_3Dstepcount);

    if (g_3Dstepcount > 0)
    {
        g_3Dstepcount--;
        eye_cur += eye_sub;
        look_cur += look_sub;
        up_cur += up_sub;
    }
    else
    {
        eye_cur = _eye;
        look_cur = _look;
        up_cur = _up;
    }
    AVM_DEBUG("g_3Dstepcount = %d\n", g_3Dstepcount);
    pre_typenum = typenum;
}

void SetCamMat_AnyView ()
{

}


int ConvertView(avmViewState View3D)
{
    int cam3D = 1;
    switch (View3D)
    {
        case AVM_DISPLAY_STATE_3D_FRONT:
            cam3D = 1;
            break;
        case AVM_DISPLAY_STATE_3D_LEFT_FRONT:
            cam3D = 2;
            break;
        case AVM_DISPLAY_STATE_3D_LEFT:
            cam3D = 3;
            break;
        case AVM_DISPLAY_STATE_3D_LEFT_REAR:
            cam3D = 4;
            break;
        case AVM_DISPLAY_STATE_3D_REAR:
            cam3D = 5;
            break;
        case AVM_DISPLAY_STATE_3D_RIGHT_REAR:
            cam3D = 6;
            break;
        case AVM_DISPLAY_STATE_3D_RIGHT:
            cam3D = 7;
            break;
        case AVM_DISPLAY_STATE_3D_RIGHT_FRONT:
            cam3D = 8;
            break;
        case AVM_DISPLAY_STATE_3D_LOOKDOWN_FRONT:
            cam3D = 9;
            break;
        case AVM_DISPLAY_STATE_3D_LOOKDOWN_REAR:
            cam3D = 10;
            break;
        case AVM_DISPLAY_STATE_3D_TOP_FRONT:
            cam3D = 11;
            break;
        case AVM_DISPLAY_STATE_3D_TOP_REAR:
            cam3D = 12;
            break;
        default:
            cam3D = 1;
            break;
    }

    return cam3D;
}

void PerspectMatInit(WindowPos *stWindowPos[])
{
    static float  aspect[2] = {0.0, 0.0};
    static float    Fovy[2] = {0.0, 0.0};
    int i = 0;

    for(i=0; i<2; i++)
    {
          aspect[i] = (float)stWindowPos[i]->width / (float)stWindowPos[i]->height;
    }

    Perspect_2D     = CELL::perspective(g_Fovy[0], aspect[0], 0.1f, 100.0f);
    pPerspect_2D    = const_cast<float *>(Perspect_2D.data());

    Perspect_3D     = CELL::perspective(g_Fovy[1], aspect[1], 0.1f, 100.0f);
    pPerspect_3D    = const_cast<float *>(Perspect_3D.data());
}

void TransMatrixtoProgram()
{
    glUseProgram(programCar);
    glUniformMatrix4fv(glGetUniformLocation(programCar, "car_matView"), 1, GL_FALSE, matView.data());
    glUniformMatrix4fv(glGetUniformLocation(programCar, "car_projection"),    1, GL_FALSE, pPerspect_2D);
    glUseProgram(0);

    SetMatrix_Bowl(matView.data(), pPerspect_2D);
//    SetMatrix_Tracks(matView.data(), pPerspect_2D);

}

/*****************functions Lev 2**********************************/
void Set3DMatrix(WindowPos *stWindowPos[], avmViewState View3D)
{
/*
    static CELL::matrix4     matView;
    static CELL::matrix4     Perspect_2D;
    static CELL::matrix4     Perspect_3D;
    static float            *pPerspect_2D;
    static float            *pPerspect_3D;
*/

    /*1: 设置透视矩阵参数*/
    PerspectMatInit(stWindowPos);

    /*2: 设置相机矩阵参数*/
    int camPos = 1;
    if (AVM_DISPLAY_STATE_3D_TOP == View3D)
    {
        SetCamMat_TopView();
    }
    else
    {
        camPos = ConvertView(View3D);
        SetCamMat_FixedPos(camPos);   //需要更新调整代码

        SetCamMat_AnyView();
    }


    /*3: 向3D渲染程序输入 相机/透视 矩阵*/
    TransMatrixtoProgram();

}

void View3DPicRender()
{
    /*1: 逻辑处理*/

    /*2: 调用3D图标的绘制函数*/

}

/*****************functions Lev 1**********************************/

/* 控制视图切换方式: 渐进式/闪切式 */
void Set3DMove ( int flag3D )
{
    g_From2Dto3D = flag3D;
#if 0
    if (0 == g_From2Dto3D)
    {
        g_3Dstepcount = 0;
    }
#endif
}


/*
*idTexture:左-右-前-后
*wbFactor:左-右-前-后*/
void fun3DRender(GLuint *idTexture, WindowPos *stWindowPos[], OVSBasicInfo *pOVSBasicInfo_3D, avmViewState avmWhitchView, VehicleSignal* stVehicleSignal, CtrlSignal *stCtrlSignal, double *wbFactor)
{
    enumTracks Track3D = TRACKS_NONE;

    /*设置3D视角下的相机矩阵和透视矩阵*/
    Set3DMatrix(stWindowPos, avmWhitchView);

    /*绘制车模型*/
    pCObj->RenderCar(stVehicleSignal);
    /*绘制碗模型*/
    Bowlrender(idTexture, wbFactor);

    /*绘制车底盲区*/
    DeadZoneRender();

    /*逻辑处理，确定轨迹线类型*/
    Track3D = SetPlaneTracksType(avmWhitchView);

    /*绘制轨迹线*/
    LineTracksRender(pOVSBasicInfo_3D, Track3D, stVehicleSignal);

    /*绘制3D视图中需要的提示图标*/
    View3DPicRender();


    /*绘制全景俯视图中的MOD框*/
    LineTopViewModRender();

    /*在3D视图中叠加2D平面空间的图标*/
    PlanePicRender();

}

