#pragma once // Gizmosuz async feature op'ları (Yüz Kaldır / Defeaturing) için viewport "işleniyor" ghost'u // + ✕ iptal. Kenar fillet ghost'unun gizmosuz ikizi: async BAŞLARKEN ekle(), bitti // callback'inde sil(), her kare ciz(). ✕ → partD.featureIptal(fk): async pump'ta bul(fk)==null // olunca sonuç GÜVENLE atılır (part_design async pump'ı bunu tasarımca ele alır). #include #include #include #include "gizmo_gorsel.hpp" // gizmo::degerEtiketi #include "imgui.h" #include "fiko/parca/part_design_sistemi.hpp" #include "fiko/render/orbit_kamera.hpp" #include "fiko/ui/bilesen_ek.hpp" // ui::toastGoster namespace fiko { struct YuzGhostDurum { struct Bek { u32 id = 0; u32 fk = 0; // ✕ iptal → featureIptal(fk) Vec3f orta{}; // etiket dünya konumu (kaldırılan yüzlerin ortası) char etiket[40] = ""; }; std::vector bekleyenler; u32 sayac = 0; // Async başlarken kayıt aç → id döner (bitti callback bununla siler). etiket kısa tutulur. u32 ekle(u32 fk, Vec3f orta, const char* etiket) { Bek b; b.id = ++sayac; b.fk = fk; b.orta = orta; std::snprintf(b.etiket, sizeof(b.etiket), "%s", etiket ? etiket : "İşleniyor…"); bekleyenler.push_back(b); return b.id; } void sil(u32 id) { bekleyenler.erase(std::remove_if(bekleyenler.begin(), bekleyenler.end(), [id](const Bek& b) { return b.id == id; }), bekleyenler.end()); } }; // Her kare çağrılır (viewport draw). Ghost etiketi + büyüyüp sönen halka + ✕ iptal butonu çizer. inline void yuzGhostCiz(YuzGhostDurum& gd, parca::PartDesignSistemi& partD, OrbitKamera& kamera, ImDrawList* dl, f32 mx, f32 my, f32 vw, f32 vh, f32 enBoy) { if (gd.bekleyenler.empty()) return; const Mat4f vp = kamera.izdusum(enBoy) * kamera.gorunum(); const f32 t = (f32)ImGui::GetTime(); const f32 f01 = std::fmod(t, 1.2f) / 1.2f; const f32 nabiz = 0.55f + 0.35f * std::sin(t * 4.0f); u32 iptalId = 0, iptalFk = 0; for (const auto& bek : gd.bekleyenler) { const Vec4f h = vp * Vec4f{bek.orta, 1.0f}; if (h.w <= 1e-4f) continue; const ImVec2 om{mx + (h.x / h.w * 0.5f + 0.5f) * vw, my + (h.y / h.w * 0.5f + 0.5f) * vh}; const int halkaAlfa = (int)(180.0f * (1.0f - f01)); dl->AddCircle(om, 8.0f + 26.0f * f01, IM_COL32(255, 150, 90, halkaAlfa), 0, 2.0f); gizmo::degerEtiketi(dl, om, bek.etiket, IM_COL32(200, 215, 235, (int)(140 + 90 * nabiz))); // ✕ iptal (etiketin sağında) — kenar_fillet ghost'uyla birebir görsel. const ImVec2 ts = ImGui::CalcTextSize(bek.etiket); const ImVec2 xm{om.x + 20.0f + ts.x + 13.0f, om.y - ts.y * 0.5f}; ImGui::SetCursorScreenPos({xm.x - 9.0f, xm.y - 9.0f}); ImGui::PushID((int)(3300u + bek.id)); const bool tik = ImGui::InvisibleButton("##yuzGhostIptal", {18, 18}); const bool hov = ImGui::IsItemHovered(); ImGui::PopID(); const ImU32 xr = hov ? IM_COL32(255, 95, 82, 255) : IM_COL32(232, 120, 108, 225); dl->AddCircleFilled(xm, 9.0f, IM_COL32(30, 20, 22, 235)); dl->AddCircle(xm, 9.0f, xr, 0, 1.6f); dl->AddLine({xm.x - 3.4f, xm.y - 3.4f}, {xm.x + 3.4f, xm.y + 3.4f}, xr, 1.8f); dl->AddLine({xm.x - 3.4f, xm.y + 3.4f}, {xm.x + 3.4f, xm.y - 3.4f}, xr, 1.8f); if (hov) ImGui::SetTooltip("İşlemi iptal et"); if (tik) { iptalId = bek.id; iptalFk = bek.fk; } } if (iptalId) { // ✕ → feature draft'ı sil (async sonuç güvenle atılır) + ghost'u kaldır if (iptalFk) partD.featureIptal(iptalFk); gd.sil(iptalId); ui::toastGoster("İşlem iptal edildi", ui::ToastTip::Bilgi); } } } // namespace fiko