#include "pch.h"
#include "app.h"

void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat4& pose)
{
    //glm::mat4 ortho_proj = glm::ortho(0.f, box.z, 0.f, box.w, -1000.f, 1000.f);
    //glm::mat4 proj = glm::perspective(glm::radians(m_canvas->m_cam_fov), box.z / box.w, 0.01f, 1000.f);
    //glm::mat4 camera = glm::eulerAngleXY(m_canvas->m_cam_rot.y, m_canvas->m_cam_rot.x) *
    //    glm::translate(m_canvas->m_cam_pos);

    //         auto plane_mvp = proj * camera * transform *
    //             glm::scale(glm::vec3(sz, 1));

    //glm::extractEulerAngleXYZ(camera, vr_rot.y, vr_rot.x, vr_rot.z);
    vr_rot = pose;

    sampler.bind(0);
    sampler.bind(1);
    sampler.bind(2);
    sampler_stencil.bind(3);
    auto blend = glIsEnabled(GL_BLEND);
    auto depth = glIsEnabled(GL_DEPTH_TEST);

    glDisable(GL_BLEND);
    glDisable(GL_DEPTH_TEST);
    glClear(GL_DEPTH_BUFFER_BIT);

    for (int plane_index = 0; plane_index < 6; plane_index++)
    {
        auto plane_mvp = proj * camera * 
            glm::scale(glm::vec3(canvas->m_canvas->m_order.size() + 500)) * 
            canvas->m_canvas->m_plane_transform[plane_index] *
            glm::translate(glm::vec3(0, 0, -1));

        ShaderManager::use(kShader::Checkerboard);
        ShaderManager::u_int(kShaderUniform::Colorize, false);
        ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp);
        m_face_plane.draw_fill();
    }

    glEnable(GL_BLEND);
    glEnable(GL_DEPTH_TEST);
    glClear(GL_DEPTH_BUFFER_BIT);

    for (size_t i = 0; i < canvas->m_canvas->m_order.size(); i++)
    {
        auto layer_index = canvas->m_canvas->m_order[i];
        for (int plane_index = 0; plane_index < 6; plane_index++)
        {
            if (!canvas->m_canvas->m_layers[layer_index]->m_visible || 
                canvas->m_canvas->m_layers[layer_index]->m_opacity == .0f ||
                !canvas->m_canvas->m_layers[layer_index]->m_dirty_face[plane_index])
                continue;

            int z = (int)(canvas->m_canvas->m_order.size() - i);
            auto plane_mvp_z = proj * camera * 
                glm::scale(glm::vec3(z + 1) * 100.f) * 
                //glm::eulerAngleYXZ(yaw, pitch, roll) *
                canvas->m_canvas->m_plane_transform[plane_index] *
                glm::translate(glm::vec3(0, 0, -1));
            
            if (canvas->m_canvas->m_current_mode == kCanvasMode::Erase && canvas->m_canvas->m_show_tmp && canvas->m_canvas->m_current_layer_idx == layer_index)
            {
                sampler.bind(0);
                ShaderManager::use(kShader::CompErase);
                ShaderManager::u_int(kShaderUniform::Tex, 0);
                ShaderManager::u_int(kShaderUniform::TexStroke, 1);
                ShaderManager::u_int(kShaderUniform::TexMask, 2);
                ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_layers[layer_index]->m_opacity);
                //ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[layer_index]->m_alpha_locked);
                ShaderManager::u_int(kShaderUniform::Mask, canvas->m_canvas->m_smask_active);
                ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
                glActiveTexture(GL_TEXTURE0);
                canvas->m_canvas->m_layers[layer_index]->m_rtt[plane_index].bindTexture();
                glActiveTexture(GL_TEXTURE1);
                canvas->m_canvas->m_tmp[plane_index].bindTexture();
                glActiveTexture(GL_TEXTURE2);
                canvas->m_canvas->m_smask.m_rtt[plane_index].bindTexture();
                m_face_plane.draw_fill();
                canvas->m_canvas->m_smask.m_rtt[plane_index].unbindTexture();
                glActiveTexture(GL_TEXTURE1);
                canvas->m_canvas->m_tmp[plane_index].unbindTexture();
                glActiveTexture(GL_TEXTURE0);
                canvas->m_canvas->m_layers[layer_index]->m_rtt[plane_index].unbindTexture();
            }
            else if (canvas->m_canvas->m_show_tmp && canvas->m_canvas->m_current_layer_idx == layer_index)
            {
                const auto& b = canvas->m_canvas->m_current_stroke->m_brush;
                sampler.bind(0);
                
                glm::vec2 patt_scale = glm::vec2(b->m_pattern_scale);
                if (b->m_pattern_flipx) patt_scale.x *= -1.f;
                if (b->m_pattern_flipy) patt_scale.y *= -1.f;

                ShaderManager::use(kShader::CompDraw);
                ShaderManager::u_int(kShaderUniform::Tex, 0);
                ShaderManager::u_int(kShaderUniform::TexStroke, 1);
                ShaderManager::u_int(kShaderUniform::TexMask, 2);
                ShaderManager::u_vec2(kShaderUniform::Resolution, canvas->m_canvas->m_size);
                ShaderManager::u_int(kShaderUniform::TexPattern, 3);
                ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_layers[layer_index]->m_opacity);
                ShaderManager::u_int(kShaderUniform::Lock, canvas->m_canvas->m_layers[layer_index]->m_alpha_locked);
                ShaderManager::u_int(kShaderUniform::Mask, canvas->m_canvas->m_smask_active);
                ShaderManager::u_int(kShaderUniform::UseFragcoord, false);
                ShaderManager::u_int(kShaderUniform::BlendMode, b->m_blend_mode);
                ShaderManager::u_int(kShaderUniform::UseDual, false);
                ShaderManager::u_int(kShaderUniform::UsePattern, b->m_pattern_enabled && !b->m_pattern_eachsample);
                ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
                ShaderManager::u_vec2(kShaderUniform::PatternScale, patt_scale);
                ShaderManager::u_float(kShaderUniform::PatternInvert, b->m_pattern_invert);
                ShaderManager::u_float(kShaderUniform::PatternBright, b->m_pattern_brightness);
                ShaderManager::u_float(kShaderUniform::PatternContrast, b->m_pattern_contrast);
                ShaderManager::u_float(kShaderUniform::PatternDepth, b->m_pattern_depth);
                ShaderManager::u_int(kShaderUniform::PatternBlendMode, b->m_pattern_blend_mode);
                ShaderManager::u_vec2(kShaderUniform::PatternOffset, Canvas::I->m_pattern_offset);

                glActiveTexture(GL_TEXTURE0);
                canvas->m_canvas->m_layers[layer_index]->m_rtt[plane_index].bindTexture();
                glActiveTexture(GL_TEXTURE1);
                canvas->m_canvas->m_tmp[plane_index].bindTexture();
                glActiveTexture(GL_TEXTURE2);
                canvas->m_canvas->m_smask.m_rtt[plane_index].bindTexture();
                glActiveTexture(GL_TEXTURE3);
                b->m_pattern_texture ?
                    b->m_pattern_texture->bind() :
                    glBindTexture(GL_TEXTURE_2D, 0);
                m_face_plane.draw_fill();
                glActiveTexture(GL_TEXTURE2);
                canvas->m_canvas->m_smask.m_rtt[plane_index].unbindTexture();
                glActiveTexture(GL_TEXTURE1);
                canvas->m_canvas->m_tmp[plane_index].unbindTexture();
                glActiveTexture(GL_TEXTURE0);
                canvas->m_canvas->m_layers[layer_index]->m_rtt[plane_index].unbindTexture();
            }
            else
            {
                sampler.bind(0);
                sampler_linear.bind(1);
                ShaderManager::use(kShader::TextureAlphaSep);
                ShaderManager::u_int(kShaderUniform::Tex, 0);
                ShaderManager::u_int(kShaderUniform::TexA, 1);
                ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_layers[layer_index]->m_opacity);
                ShaderManager::u_int(kShaderUniform::Highlight, canvas->m_canvas->m_layers[layer_index]->m_hightlight);
                ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
                
                glActiveTexture(GL_TEXTURE0);
                canvas->m_canvas->m_layers[layer_index]->m_rtt[plane_index].bindTexture();
                glActiveTexture(GL_TEXTURE1);
                canvas->m_canvas->m_layers[layer_index]->m_rtt[plane_index].bindTexture();
                
                m_face_plane.draw_fill();
                
                glActiveTexture(GL_TEXTURE1);
                canvas->m_canvas->m_layers[layer_index]->m_rtt[plane_index].unbindTexture();
                glActiveTexture(GL_TEXTURE0);
                canvas->m_canvas->m_layers[layer_index]->m_rtt[plane_index].unbindTexture();
            }
        }
    }

    float tan_fov = glm::tan(glm::radians(canvas->m_canvas->m_cam_fov / 2.f));
    glm::vec3 aspect = { (float)uirtt.getWidth() / (float)uirtt.getHeight(), 1.f, 1.f };

    // draw the frame
    {
        auto mvp = proj * camera *
            glm::scale(glm::vec3(100)) *
            glm::transpose(canvas->m_canvas->m_cam_rot) *
            glm::translate(glm::vec3(0, 0, -1)) *
            glm::scale(aspect * tan_fov);
        ShaderManager::use(kShader::Color);
        ShaderManager::u_vec4(kShaderUniform::Col, { 0, 0, 0, 1 });
        ShaderManager::u_mat4(kShaderUniform::MVP, mvp);
        m_face_plane.draw_stroke();
    }

    // draw the brush
    if (auto mode = dynamic_cast<CanvasModePen*>(canvas->m_canvas->modes[(int)canvas->m_canvas->m_current_mode][0]))
    {
        auto pos = mode->m_resizing ? mode->m_size_pos_start : mode->m_cur_pos;
        if (App::I.keys[(int)kKey::KeyAlt] && !mode->m_resizing)
            pos.x = pos.x - canvas->m_canvas->m_current_brush->m_tip_size * 500;
        auto cur = (glm::vec2(pos.x / width, 1.f - pos.y / height) - 0.5f) * 2.f;

        ShaderManager::use(kShader::StrokePreview);
        ShaderManager::u_int(kShaderUniform::Tex, 0);
        ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_current_brush->m_tip_flow);
        auto tip_color = glm::vec4(glm::vec3(canvas->m_canvas->m_current_brush->m_tip_color), 1);
        ShaderManager::u_vec4(kShaderUniform::Col, tip_color);
        ShaderManager::u_mat4(kShaderUniform::MVP,
            proj * camera *
            glm::scale(glm::vec3(100)) *
            glm::transpose(canvas->m_canvas->m_cam_rot) *
            glm::translate(glm::vec3(cur * glm::vec2(aspect * tan_fov), -1)) *
            glm::scale(glm::vec3(canvas->m_canvas->m_current_brush->m_tip_size / App::I.height)) *
            glm::eulerAngleZ(canvas->m_canvas->m_current_brush->m_tip_angle  * (float)(M_PI * 2.0))
        );
        glEnable(GL_BLEND);
        glActiveTexture(GL_TEXTURE0);
        auto& tex = *canvas->m_canvas->m_current_brush->m_tip_texture;
        tex.bind();
        sampler_linear.bind(0);
        m_face_plane.draw_fill();
        tex.unbind();
    }
    
    // draw the 2D UI
    if (ui_visible)
    {
        auto mvp = proj * camera *
            glm::scale(glm::vec3(100)) *
            glm::transpose(canvas->m_canvas->m_cam_rot) *
            glm::translate(glm::vec3(0, 0, -1)) *
            glm::scale(aspect * tan_fov);
        sampler_linear.bind(0);
        ShaderManager::use(kShader::Texture);
        ShaderManager::u_int(kShaderUniform::Tex, 0);
        ShaderManager::u_mat4(kShaderUniform::MVP, mvp);
        glActiveTexture(GL_TEXTURE0);
        uirtt.bindTexture();
        m_face_plane.draw_fill();
        uirtt.unbindTexture();
    }

    // draw the cursor
    {
        auto cur = (glm::vec2(cursor.x / width, 1.f - cursor.y / height) - 0.5f) * 2.f;
        auto mvp = proj * camera *
            glm::scale(glm::vec3(100)) *
            glm::transpose(canvas->m_canvas->m_cam_rot) *
            glm::translate(glm::vec3(cur * glm::vec2(aspect * tan_fov), -1));
        ShaderManager::use(kShader::Color);
        ShaderManager::u_vec4(kShaderUniform::Col, { 0, 0, 0, 1 });
        ShaderManager::u_mat4(kShaderUniform::MVP, mvp * glm::scale(glm::vec3(.01)));
        m_face_plane.draw_fill();
        ShaderManager::u_vec4(kShaderUniform::Col, { 1, 1, 1, 1 });
        ShaderManager::u_mat4(kShaderUniform::MVP, mvp * glm::scale(glm::vec3(.005)));
        m_face_plane.draw_fill();
    }

    // draw the motion controller sphere
/*
    {
        auto mvp = proj * camera * glm::translate(glm::normalize(vr_controller_pos));
        ShaderManager::use(kShader::Color);
        ShaderManager::u_vec4(kShaderUniform::Col, { 0, 0, 0, 1 });
        ShaderManager::u_mat4(kShaderUniform::MVP, mvp * glm::scale(glm::vec3(.025)));
        sphere.draw_fill();
    }
*/

    // draw the motion controller brush
    {
        auto pos = glm::translate(glm::normalize(vr_controller_pos));
        ShaderManager::use(kShader::StrokePreview);
        ShaderManager::u_int(kShaderUniform::Tex, 0);
        ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_current_brush->m_tip_flow);
        auto tip_color = glm::vec4(glm::vec3(canvas->m_canvas->m_current_brush->m_tip_color), 1);
        ShaderManager::u_vec4(kShaderUniform::Col, tip_color);
        ShaderManager::u_mat4(kShaderUniform::MVP,
            proj * camera * pos * 
            glm::inverse(glm::lookAt({ 0, 0, 0 }, vr_controller_pos, { 0, 1, 0 })) *
            //glm::scale(glm::vec3(0.1)) *
            glm::scale(glm::vec3(canvas->m_canvas->m_current_brush->m_tip_size / App::I.height)) *
            glm::eulerAngleZ(canvas->m_canvas->m_current_brush->m_tip_angle  * (float)(M_PI * 2.0))
        );
        glEnable(GL_BLEND);
        glActiveTexture(GL_TEXTURE0);
        auto& tex = *canvas->m_canvas->m_current_brush->m_tip_texture;
        tex.bind();
        sampler_linear.bind(0);
        m_face_plane.draw_fill();
        tex.unbind();
    }

/*
    for (auto& mode : *m_canvas->m_mode)
        mode->on_Draw(ortho_proj, proj, camera);
    
    glDisable(GL_DEPTH_TEST);
    if (m_canvas->m_smask_active)
    {
        m_canvas->modes[(int)kCanvasMode::MaskFree][0]->on_Draw(ortho_proj, proj, camera);
        m_canvas->modes[(int)kCanvasMode::MaskLine][0]->on_Draw(ortho_proj, proj, camera);
    }
    
    // keep drawing the grids
    if (m_canvas->m_state != kCanvasMode::Grid)
        for (auto& mode : Canvas::modes[(int)kCanvasMode::Grid])
            mode->on_Draw(ortho_proj, proj, camera);
*/

    blend ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
    depth ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST);
    sampler.unbind();
}

