Исходник C++ Dear ImGui : Animated 3D Cube, loading spinner

get good, get zeus, for ever
Пользователь
Статус
Оффлайн
Регистрация
1 Июн 2018
Сообщения
598
Реакции[?]
115
Поинты[?]
16K
Анимированный 3Д куб, сделан в стилистике загрузочного спинера прогресс бара нету просто кубик крутится + анимация цвета

source code:
#include <array>
#include <cmath>

struct ImVec3 {
    float x, y, z;
    ImVec3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
};

ImVec3 RotateX(const ImVec3& v, float angle) {
    float rad = angle * (3.14159f / 180.0f);
    float cosA = cos(rad);
    float sinA = sin(rad);
    return ImVec3(v.x, v.y * cosA - v.z * sinA, v.y * sinA + v.z * cosA);
}

ImVec3 RotateY(const ImVec3& v, float angle) {
    float rad = angle * (3.14159f / 180.0f);
    float cosA = cos(rad);
    float sinA = sin(rad);
    return ImVec3(v.x * cosA + v.z * sinA, v.y, -v.x * sinA + v.z * cosA);
}

void Add3DCube(ImVec2 center, float size, float perspective, float rotationX, float rotationY, float distance)
{
    std::array<ImVec3, 8> cube_vertices{ {
        ImVec3(-1, -1, -1), ImVec3(1, -1, -1),
        ImVec3(1,  1, -1), ImVec3(-1,  1, -1),
        ImVec3(-1, -1,  1), ImVec3(1, -1,  1),
        ImVec3(1,  1,  1), ImVec3(-1,  1,  1)
    } };

    std::array<ImVec2, 8> projected_vertices;

    for (size_t i = 0; i < cube_vertices.size(); i++)
    {
        ImVec3 rotated = RotateX(cube_vertices[i], rotationX);
        rotated = RotateY(rotated, rotationY);

        rotated.x *= distance;
        rotated.y *= distance;
        rotated.z *= distance;

        float z = rotated.z * perspective + 3.0f;
        projected_vertices[i] = ImVec2(
            center.x + rotated.x * size / z,
            center.y + rotated.y * size / z
        );

        //ImGui::GetWindowDrawList()->AddCircle(
        //    projected_vertices[i], 3.5f, ImColor(255, 255, 0, 255), 24, 2.0f
        //);
    }

    std::array<std::pair<int, int>, 12> edges = { {
        {0, 1}, {1, 2}, {2, 3}, {3, 0},
        {4, 5}, {5, 6}, {6, 7}, {7, 4},
        {0, 4}, {1, 5}, {2, 6}, {3, 7}
    } };

    for (const auto& edge : edges)
    {
        ImGui::GetWindowDrawList()->AddLine(
            projected_vertices[edge.first],
            projected_vertices[edge.second],
            IM_COL32(255, 255, 255, 255), 2.0f
        );
    }
}

struct AnimationState {
    bool state;
    float target_speed;
    float speed_multiplier;
    float rotation_x;
    float rotation_y;
};

void AddLoadingCube(const char* label)
{
    ImGuiWindow* window = ImGui::GetCurrentWindow();
    ImGuiID id = window->GetID(label);
    if (window->SkipItems)
        return;

    ImGui::PushID(id);

    auto& g = *GImGui;
    auto center = ImGui::GetWindowPos() + ImVec2(ImGui::GetWindowWidth(), ImGui::GetWindowHeight()) / 2;
    auto delta_time = ImGui::GetIO().DeltaTime;

    ImVec2 text_size = ImGui::CalcTextSize(label);

    static float spacing = 25.f;
    static float cube_size = 50.f;

    const ImVec2 extra_bb = ImVec2(cube_size + spacing, cube_size + spacing);
    const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + extra_bb);
    ImGui::ItemSize(extra_bb);
    ImGui::ItemAdd(bb, 0);

    /[I]ImGui::GetWindowDrawList()->AddRect(bb.Min, bb.Max, ImColor(255, 255, 0, 255), 0.0f, ImDrawFlags_None, 2.0f);[/I]/

    static std::map<ImGuiID, AnimationState> animations;

    if (animations.find(id) == animations.end()) {
        animations[id] = AnimationState{ true, 68.0f, 0.0f, 0.0f, 0.0f };
    }

    AnimationState& anim_state = animations[id];

    float lerp_factor = delta_time * 3.0f;

    if (anim_state.state) {
        anim_state.speed_multiplier = ImLerp(anim_state.speed_multiplier, anim_state.target_speed, lerp_factor);
        if (anim_state.speed_multiplier >= anim_state.target_speed * 0.95f)
            anim_state.state = false;
    }
    else {
        anim_state.speed_multiplier = ImLerp(anim_state.speed_multiplier, 2.0f, lerp_factor);
        if (anim_state.speed_multiplier <= 2.4f)
            anim_state.state = true;
    }

    anim_state.rotation_x += delta_time * (8.5f * anim_state.speed_multiplier);
    anim_state.rotation_y -= delta_time * (8.0f * anim_state.speed_multiplier);

    float scale_factor = 1.0f + (anim_state.speed_multiplier * 0.0012f);

    Add3DCube(bb.Min + ImVec2(cube_size / 2.f + spacing / 2, cube_size / 2.f + spacing / 4.f), cube_size, 0.f, anim_state.rotation_x, anim_state.rotation_y, scale_factor);

    ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[8]);

    static std::map<ImGuiID, float> values;
    auto value = values.find(id);
    if (value == values.end()) {
        values.insert({ id, 0.f });
        value = values.find(id);
    }
    value->second = ImLerp(value->second, 200.f, g.IO.DeltaTime * 10.f);

    ImVec2 text_pos = ImVec2(bb.Min.x + (bb.GetWidth() - text_size.x) / 2.0f, bb.Min.y + (bb.GetHeight() - text_size.y) / 1.0f);

    ImGui::GetWindowDrawList()->AddText(text_pos, ImColor(255, 255, 255, int((anim_state.speed_multiplier * 2) + 135)), label);
    ImGui::PopFont();

    ImGui::PopID();
}
 
Последнее редактирование:
Сверху Снизу