#pragma once

#include"VulkanAppFramework.h"

using namespace hgl;
using namespace hgl::graph;

class ViewModelFramework:public VulkanApplicationFramework
{
private:

    vulkan::Buffer *            ubo_world_matrix    =nullptr;

protected:

    AABB                        bounding_box;

    Matrix4f                    object_matrix,origin_matrix;

    ControlCamera               camera,origin_camera;
    float                       move_speed=1;

    Vector2f                    mouse_last_pos;

protected:

    SceneNode                   render_root;
    RenderList                  render_list;

public:

    virtual ~ViewModelFramework()=default;

    virtual bool Init(int w,int h,const AABB &aabb)
    {
        if(!VulkanApplicationFramework::Init(w,h))
            return(false);

        bounding_box=aabb;

        InitCamera(w,h);
        return(true);
    }

    virtual void InitCamera(int w,int h)
    {     
        math::vec center_point  =bounding_box.CenterPoint();
        math::vec min_point     =bounding_box.minPoint;
        math::vec size          =bounding_box.Size();

        math::vec eye(  center_point.x,
                        center_point.y-size.y*4,
                        center_point.z,
                        1.0f);
        
        camera.type     =CameraType::Perspective;
        camera.width    =w;
        camera.height   =h;
        camera.center   =center_point;
        camera.eye      =eye;

        camera.Refresh();      //更新矩阵计算

        origin_camera=camera;

        move_speed=length(min_point,center_point)/100.0f;

        object_matrix=Matrix4f::identity;
        origin_matrix=object_matrix;
    }

    bool InitCameraUBO(vulkan::MaterialInstance *mi,const UTF8String &world_matrix_name)
    {
        ubo_world_matrix=db->CreateUBO(sizeof(WorldMatrix),&camera.matrix);

        if(!ubo_world_matrix)
            return(false);

        return mi->BindUBO(world_matrix_name,ubo_world_matrix);
    }

    void Resize(int w,int h)override
    {
        camera.width=w;
        camera.height=h;
    }

    virtual void Draw()override
    {
        const uint32_t index=AcquireNextImage();

        camera.Refresh();                           //更新相机矩阵
        ubo_world_matrix->Write(&camera.matrix);    //写入缓冲区
        
        render_root.RefreshMatrix(&object_matrix);
        render_list.Clear();
        render_root.ExpendToList(&render_list);

        BuildCommandBuffer(index,&render_list);

        SubmitDraw(index);

        if(key_status[kbEnter])
        {
            origin_camera.width=camera.width;
            origin_camera.height=camera.height;
            camera=origin_camera;
            object_matrix=origin_matrix;
        }
        else
        if(key_status[kbW])camera.Forward   (move_speed);else
        if(key_status[kbS])camera.Backward  (move_speed);else
        if(key_status[kbA])camera.Left      (move_speed);else
        if(key_status[kbD])camera.Right     (move_speed);else
        if(key_status[kbR])camera.Up        (move_speed);else
        if(key_status[kbF])camera.Down      (move_speed);else
        {
            auto axis=normalized(camera.center-camera.eye);
            float rotate_rad=hgl_ang2rad(move_speed)*10;

            if(key_status[kbLeft ])
                object_matrix=rotate(-rotate_rad,camera.forward_vector)*object_matrix;else
            if(key_status[kbRight])
                object_matrix=rotate( rotate_rad,camera.forward_vector)*object_matrix;else

            return;
        }
    }

    virtual void KeyPress(KeyboardButton kb)override
    {
        if(kb==kbMinus)move_speed*=0.9f;else
        if(kb==kbEquals)move_speed*=1.1f;else
            return;
    }

    virtual void MouseDown(uint) override
    {
        mouse_last_pos=mouse_pos;
    }

    virtual void MouseMove() override
    {
        if(!mouse_key)return;

        Vector2f gap=mouse_pos-mouse_last_pos;

        if(mouse_key&mbLeft)
        {
            if(gap.x!=0)camera.HorzRotate(-gap.x/10.0f);
            if(gap.y!=0)camera.VertRotate(-gap.y/10.0f);
        }
        else if(mouse_key&mbRight)
        {
            if(gap.x!=0)object_matrix=rotate(hgl_ang2rad(gap.x),camera.up_vector)*object_matrix;
            if(gap.y!=0)object_matrix=rotate(hgl_ang2rad(gap.y),camera.right_vector)*object_matrix;
        }
        else if(mouse_key&mbMid)
        {
            if(gap.x!=0)camera.Left(gap.x*move_speed/5.0f);
            if(gap.y!=0)camera.Up(gap.y*move_speed/5.0f);
        }

        mouse_last_pos=mouse_pos;
    }

    virtual void MouseWheel(int v,int h,uint)
    {
        camera.Distance(1+(v/1000.0f));
    }
};//class CameraAppFramework
