#include "crDevGizmos.h"

#include <imgui.h>

#include "crApp.h"
#include "crBatchedLines3D.h"
#include "crCamera.h"
#include "crDevPhysics.h"
#include "crDevText.h"
#include "crGraphics.h"
#include "crGraphicsUniforms.h"
#include "crMath.h"

static constexpr float GIZMO_AXIS_LENGTH  = 1.0f;
static constexpr float GIZMO_LIGHT_LENGTH = 2.0f;
static constexpr float GIZMO_LIGHT_HEAD   = 0.25f;

void crDevGizmos::Init( crApp* app )
{
    _lineBatch = new crBatchedLines3D;
    _lineBatch->Init();

    _app = app;
}
void crDevGizmos::Cleanup()
{
    if( _lineBatch != nullptr )
    {
        _lineBatch->Cleanup();
        delete _lineBatch;
        _lineBatch = nullptr;
    }

    _app = nullptr;
}

void crDevGizmos::TryRenderGizmos()
{
    if( ( enabled == false ) ||
        ( ( _worldAxisEnabled == false ) && ( _lightDirEnabled == false ) ) )
        return;

    const float3 t = _app->camera->Target();

    _lineBatch->Begin();

    if( _worldAxisEnabled )
    {
        _lineBatch->Line( t, float3( t.x + GIZMO_AXIS_LENGTH, t.y, t.z ), color4( 1.0f, 0.2f, 0.2f, 1.0f ) );
        _lineBatch->Line( t, float3( t.x, t.y + GIZMO_AXIS_LENGTH, t.z ), color4( 0.2f, 1.0f, 0.2f, 1.0f ) );
        _lineBatch->Line( t, float3( t.x, t.y, t.z + GIZMO_AXIS_LENGTH ), color4( 0.3f, 0.5f, 1.0f, 1.0f ) );
    }

    if( _lightDirEnabled )
    {
        // arrow arriving at the target from the light: tail sits toward the light, tip at the target
        const float3 d      = crMath::Normalize3( _app->graphics->Uniforms()->lightDir );
        const float3 tail   = float3( t.x + ( d.x * GIZMO_LIGHT_LENGTH ),
                                      t.y + ( d.y * GIZMO_LIGHT_LENGTH ),
                                      t.z + ( d.z * GIZMO_LIGHT_LENGTH ) );
        const color4 yellow = color4( 1.0f, 0.9f, 0.2f, 1.0f );

        _lineBatch->Line( tail, t, yellow );

        const float3 perp = crMath::Normalize3( crMath::Cross3( d, float3( 0.0f, 1.0f, 0.0f ) ) );
        _lineBatch->Line( t, float3( t.x + ( ( d.x + perp.x ) * GIZMO_LIGHT_HEAD ),
                                     t.y + ( ( d.y + perp.y ) * GIZMO_LIGHT_HEAD ),
                                     t.z + ( ( d.z + perp.z ) * GIZMO_LIGHT_HEAD ) ), yellow );
        _lineBatch->Line( t, float3( t.x + ( ( d.x - perp.x ) * GIZMO_LIGHT_HEAD ),
                                     t.y + ( ( d.y - perp.y ) * GIZMO_LIGHT_HEAD ),
                                     t.z + ( ( d.z - perp.z ) * GIZMO_LIGHT_HEAD ) ), yellow );
    }

    _lineBatch->Flush( _app->graphics->Program( EShader::LINE_3D ), false );
}
void crDevGizmos::TryRenderPanel()
{
    if( enabled == false )
        return;

    ImGui::PushStyleVar( ImGuiStyleVar_FramePadding, ImVec2( 4.0f, 0.0f ) );
    ImGui::PushStyleVar( ImGuiStyleVar_ItemSpacing, ImVec2( 8.0f, 2.0f ) );

    ImGui::SetNextWindowPos( ImVec2( 10.0f + 240.0f, 10.0f + 20.0f ), ImGuiCond_FirstUseEver );
    ImGui::SetNextWindowSize( ImVec2( 240.0f, 0.0f ), ImGuiCond_FirstUseEver );
    ImGui::SetNextWindowCollapsed( true, ImGuiCond_FirstUseEver );

    if( ImGui::Begin( "Gizmos", nullptr, ImGuiWindowFlags_NoSavedSettings ) )
    {
        ImGui::Checkbox( "World Axis", &_worldAxisEnabled );
        ImGui::Checkbox( "Light Direction", &_lightDirEnabled );

        ImGui::SeparatorText( "Wireframe" );

        bool physicsWire = _app->devPhysics->GetDebugDraw();
        if( ImGui::Checkbox( "Physics", &physicsWire ) )
            _app->devPhysics->SetDebugDraw( physicsWire );

        bool textWire = _app->devText->GetDebugDraw();
        if( ImGui::Checkbox( "Text", &textWire ) )
            _app->devText->SetDebugDraw( textWire );
    }
    ImGui::End();

    ImGui::PopStyleVar( 2 );
}
