Skip to content

File Viewport.cpp

File List > layer > Viewport.cpp

Go to the documentation of this file

#include "Viewport.h"
#include "Input.h"

#include "ITEM/TextureViewer.h"

#include "Camera.h"
#include "Transform.h"
#include "SceneManager.h"
#include "buffers/FrameBuffer.h"

#include "events/CameraEvents.h"
#include "events/KeyMouseEvents.h"
#include "events/ViewportEvents.h"

#include "xdz_matrix.h"

ImGuizmo::MODE Viewport::trans_mod = ImGuizmo::WORLD;
ImGuizmo::OPERATION Viewport::handle_mod = ImGuizmo::TRANSLATE;

Viewport::Viewport()
{
    uly_name = "";
}

Viewport::Viewport(const std::string& name)
    :Viewport(name, 0)
{}

Viewport::Viewport(const std::string& name, GLuint texID)
    : Viewport(name, 0, ImVec2(SCREEN_W, SCREEN_H))
{}

Viewport::Viewport(const std::string& name, GLuint texID, const ImVec2& vp_size)
{
    uly_name = name;
    PushItem<UI::TextureViewer>("Viewport", texID, vp_size);
}

Viewport::~Viewport()
{

}


void MTranslate()
{
    Viewport::handle_mod = ImGuizmo::TRANSLATE;
}

void MRotate()
{
    Viewport::handle_mod = ImGuizmo::ROTATE;
}

void MScale()
{
    Viewport::handle_mod = ImGuizmo::SCALE;
}

void _SpecifyAxis(GLuint offset) {
    // offset: 0, 1, 2, 3 -> X, Y, Z, W

    if (Viewport::handle_mod & ImGuizmo::TRANSLATE) {
        const ImGuizmo::OPERATION trans = ImGuizmo::OPERATION(ImGuizmo::TRANSLATE_X << offset);
        if (Viewport::handle_mod == trans)
            ::MTranslate();         // Reset to full translate
        else
            Viewport::handle_mod = trans;   // Or specify axis
    }
    else if (Viewport::handle_mod & ImGuizmo::ROTATE) {
        const ImGuizmo::OPERATION rotate = ImGuizmo::OPERATION(ImGuizmo::ROTATE_X << offset);
        if (Viewport::handle_mod == rotate)
            ::MRotate();
        else
            Viewport::handle_mod = rotate;
    }
    else if (Viewport::handle_mod & ImGuizmo::SCALE) {
        const ImGuizmo::OPERATION scale = ImGuizmo::OPERATION(ImGuizmo::SCALE_X << offset);
        if (Viewport::handle_mod == scale)
            ::MScale();
        else
            Viewport::handle_mod = scale;
    }
}

void XAxis()
{
    ::_SpecifyAxis(0);
}

void YAxis()
{
    ::_SpecifyAxis(1);
}

void ZAxis()
{
    ::_SpecifyAxis(2);
}

void WAxis()
{
    if (Viewport::handle_mod & (ImGuizmo::OPERATION::TRANSLATE | ImGuizmo::OPERATION::SCALE))
        return; // W axis is only for rotation

    ::_SpecifyAxis(3);
}

void Viewport::RegisterEvents(EventPool& evt)
{
    evt.subscribe<KeyClickEvent>([this](KeyClickEvent e) {
        if (!is_mouse_hovered) return;

        switch (e.key.normal) {
        case Input::NormalKeyFromChar('G'): // G
            ::MTranslate(); break;
        case Input::NormalKeyFromChar('R'): // R
            ::MRotate(); break;
        case Input::NormalKeyFromChar('S'): // S
            ::MScale(); break;
        case Input::NormalKeyFromChar('X'): // X
            ::XAxis(); break;
        case Input::NormalKeyFromChar('Y'): // Y
            ::YAxis(); break;
        case Input::NormalKeyFromChar('Z'): // Z
            ::ZAxis(); break;
        case Input::NormalKeyFromChar('W'): // W
            ::WAxis(); break;
        }
        });

    evt.subscribe<MouseClickEvent>([this, &evt](MouseClickEvent e) {
        if (!is_mouse_hovered) return;
        if (viewport_status != HoverStatus::OnViewport) return;

        if (e.mouse == Input::MouseButtons::LMB) {
            int mouse_x = int(Input::GetMousePosX() - uly_pos.x);
            int mouse_y = int(Input::GetMousePosY() - uly_pos.y);
            evt.emit(ViewportSelectedEvent{ mouse_x, mouse_y, e.key == Input::SHIFT });
        }
        });

    evt.subscribe<ViewportImageResetEvent>([this](ViewportImageResetEvent e) {
        ImguiItem* item = FindImguiItem(0);
        if (item != nullptr) {
            item->ResetBufferID(e.tex_id);
        }
        });
}

void Viewport::RenderLayer(const Context& ctx, EventPool& evt)
{
    item_list[0]->RenderItem();

#if _DEBUG
    ImGui::Text("[ %d ]", is_mouse_hovered);
    ImGui::Text("[ %.0f , %.0f ]", ImGui::GetWindowPos().x, ImGui::GetWindowPos().y);
    ImGui::Text("[ %.0f , %.0f ]", ImGui::GetWindowContentRegionMin().x, ImGui::GetWindowContentRegionMin().y);
    ImGui::Text("[ %.0f , %.0f ]", ImGui::GetMainViewport()->Pos.x, ImGui::GetMainViewport()->Pos.y);
    ImGui::Text("[ %.0f , %.0f ]", ImGui::GetCursorScreenPos().x, ImGui::GetCursorScreenPos().y);
    ImGui::Text("[ %.0f , %.0f ]", Input::GetMousePosX(), Input::GetMousePosY());
    ImVec2 window_pos = (ImGui::GetWindowPos() - ImGui::GetMainViewport()->Pos);
    ImGui::Text("[ %.0f , %.0f ]", Input::GetMousePosX() - window_pos.x, Input::GetMousePosY() - window_pos.y);
#endif // _DEBUG

    if (display_grid)
        RenderGrids(ctx);
    if (display_axis)
        RenderAxis(ctx);
    if (display_trans_handle)
        RenderHandle(ctx);

    if (IsResized()) {
        item_list[0]->ResetSize(uly_size + ImVec2(10, 10));
        evt.emit(ViewportResizeEvent{ int(uly_size.x), int(uly_size.y) });
    }

    if (is_mouse_hovered) {
        if (Input::IsMousePressed(Input::MouseButtons::MMB)) {
            const Camera* active_cam = dynamic_cast<const Camera*>(ctx.scene.GetActiveCamera());
            if (Input::IsKeyPressed(Input::CTRL)) {
                evt.emit(CameraPushEvent{ (Camera*)active_cam, Input::GetDeltaMouseX(), Input::GetDeltaMouseY()});
            }
            else if (Input::IsKeyPressed(Input::SHIFT)) {
                evt.emit(CameraSlideEvent{ (Camera*)active_cam, Input::GetDeltaMouseX(), Input::GetDeltaMouseY() });
            }
            else if (Input::IsKeyPressed(Input::ALT)) {
                evt.emit(CameraSpinEvent{ (Camera*)active_cam, Input::GetDeltaMouseX(), Input::GetDeltaMouseY() });
            }
            else if (Input::IsKeyPressed(Input::NONE)) {
                evt.emit(CameraRotateEvent{ (Camera*)active_cam, Input::GetDeltaMouseX(), Input::GetDeltaMouseY() });
            }
        }

        if (Input::IsMouseScrolled()) {
            const Camera* active_cam = dynamic_cast<const Camera*>(ctx.scene.GetActiveCamera());
            evt.emit(CameraZoomEvent{ (Camera*)active_cam, Input::GetScrollY() });
        }
    }
}

void Viewport::RenderGrids(const Context& ctx)
{
    const Camera* active_cam = dynamic_cast<const Camera*>(ctx.scene.GetActiveCamera());

    if (active_cam == nullptr)
        return;

    ImGuizmo::DrawGrid(&active_cam->o_InvTransform[0][0], &active_cam->cam_frustum[0][0], &xdzm::identityMatrix[0][0], 30.f, 0.5f);
}

void Viewport::RenderAxis(const Context& ctx)
{
    Camera* active_cam = (Camera*)dynamic_cast<const Camera*>(ctx.scene.GetActiveCamera());

    ImGuiIO& io = ImGui::GetIO();
    float viewManipulateRight = io.DisplaySize.x;
    float viewManipulateTop = 0;

    ImGuizmo::SetDrawlist();
    float windowWidth = (float)ImGui::GetWindowWidth();
    float windowHeight = (float)ImGui::GetWindowHeight();
    ImGuizmo::SetRect(ImGui::GetWindowPos().x, ImGui::GetWindowPos().y, windowWidth, windowHeight);
    viewManipulateRight = ImGui::GetWindowPos().x + windowWidth;
    viewManipulateTop = ImGui::GetWindowPos().y;

    if (active_cam == nullptr)
        return;

    glm::mat4 cam_trans = active_cam->o_InvTransform;
    static glm::mat4 test_trans{1};
    ImGuizmo::ViewManipulate(&cam_trans[0][0], 5, ImVec2(viewManipulateRight - 128, viewManipulateTop), ImVec2(128, 128), 0x10101010);

    // TODO: event system
    active_cam->SetCamTrans(glm::transpose(cam_trans), false, true);
}

void Viewport::RenderHandle(const Context& ctx)
{
    Scene* scene = dynamic_cast<Scene*>(ctx.scene.active_scene);
    Camera* active_cam = dynamic_cast<Camera*>(scene->GetActiveCamera());

    const SelectionManager<ObjectID>& sel = ctx.editor.selections;
    Transform3D* active_trans = dynamic_cast<Transform3D*>(sel.GetActiveObject());

    if (active_trans == nullptr || active_cam == nullptr)
        return;

    static bool useSnap = false;
    static float snap[3] = { 1.f, 1.f, 1.f };
    static float bounds[] = { -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f };
    static float boundsSnap[] = { 0.1f, 0.1f, 0.1f };
    static bool boundSizing = false;
    static bool boundSizingSnap = false;

    //ImGuizmo::DrawCubes(&active_cam->o_InvTransform[0][0], &active_cam->cam_frustum[0][0], &active_trans->o_Transform[0][0], 1);
    glm::mat4 obj_trans = active_trans->o_Transform;

    bool hover, click;
    ImGuizmo::Manipulate(&active_cam->o_InvTransform[0][0], &active_cam->cam_frustum[0][0], Viewport::handle_mod, Viewport::trans_mod, &obj_trans[0][0], &hover, &click, NULL, useSnap ? &snap[0] : NULL, boundSizing ? bounds : NULL, boundSizingSnap ? boundsSnap : NULL);

    if (hover) {
        viewport_status = HoverStatus(viewport_status | HoverStatus::OnHandle);
    }
    else {
        viewport_status = HoverStatus(viewport_status & ~HoverStatus::OnHandle);
    }

    if(click) // TODO: event system
        active_trans->SetTrans(obj_trans);
}