#include "fiko/ui/imgui_katman.hpp" #include #include #include // [GEÇİCİ combo-teşhis] — combo bug'ı çözülünce kaldır #include "fiko/core/gunluk.hpp" #include "fiko/core/kare_istek.hpp" #include "fiko/platform/pencere.hpp" #include "fiko/platform/sistem.hpp" #include "fiko/render/vk_kontrol.hpp" #include "fiko/render/vulkan_baglam.hpp" #include "fiko/ui/animasyon.hpp" #include "fiko/ui/efekt.hpp" #include "fiko/ui/seffaf_pencere.hpp" #include "fiko/ui/simge.hpp" #include "fiko/ui/tema.hpp" #include "imgui.h" #include "imgui_impl_vulkan.h" #include "imgui_impl_win32.h" #include "misc/freetype/imgui_freetype.h" extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); namespace fiko { namespace { // UYGULAMA-GLOBAL altyapı (efekt/simge/şeffaf) ref-count: ilk katman kurar, son // katman yıkar. NOT: font atlas context-BAŞINA (paylaşılmaz) — ImGui 1.92 dinamik // doku sisteminde ImTextureData atlas'a ait + BackendUserData onun içinde; iki // Vulkan backend aynı atlası paylaşırsa descriptor/doku ömrü çakışır. Her context // kendi atlasını yükler (pencere başına bir font dokusu; doğruluk > bellek). int g_katmanSayisi = 0; // Tema artık merkezi token sisteminden (fiko/ui/tema.hpp) uygulanır. // Metin (Segoe UI) + tek-renkli sembol (Segoe UI Symbol) + RENKLİ emoji // (Segoe UI Emoji) birleşik font. ImGui 1.92 dinamik atlas: glif aralığı // vermeye gerek yok, glifler talep üzerine yüklenir. Renkli emoji için FreeType // yükleyici + LoadColor bayrağı şarttır (stb_truetype COLR/CPAL glif yüklemez). void fontYukle() { ImGuiIO& io = ImGui::GetIO(); ImFontConfig metinAyar; metinAyar.OversampleH = 2; if (!io.Fonts->AddFontFromFileTTF("C:/Windows/Fonts/segoeui.ttf", 16.0f, &metinAyar)) { io.Fonts->AddFontDefault(); return; } // SIRALAMA KRİTİK: renkli emoji (seguiemj) sembol fontundan (seguisym) ÖNCE // merge edilir. Segoe UI Symbol birçok emoji kod noktasını (🎯 📏 ...) TEK-RENKLİ // outline glif olarak içerir; symbol önce gelirse ImGui o tek-renk sürümü bulur ve // renkli emoji fontuna HİÇ bakmaz → emoji tek renk çıkar. Emoji önce → renkli kazanır. ImFontConfig emojiAyar; emojiAyar.MergeMode = true; emojiAyar.FontLoaderFlags |= ImGuiFreeTypeLoaderFlags_LoadColor; // COLR/CPAL katmanları emojiAyar.GlyphOffset = ImVec2(0, 3); io.Fonts->AddFontFromFileTTF("C:/Windows/Fonts/seguiemj.ttf", 15.0f, &emojiAyar); // Emoji'de OLMAYAN tek-renkli teknik/geometrik semboller (◆ ⚙ ✕ ↔ ⊟ ...). ImFontConfig simgeAyar; simgeAyar.MergeMode = true; simgeAyar.GlyphOffset = ImVec2(0, 1); io.Fonts->AddFontFromFileTTF("C:/Windows/Fonts/seguisym.ttf", 15.0f, &simgeAyar); } } ImGuiKatman::ImGuiKatman(Pencere& pencere, VulkanBaglam& vb) : vb_(vb) { // 256: simge kitaplığı (PNG/SVG dokuları) + viewport dokuları buradan pay alır. const VkDescriptorPoolSize boyutlar[] = { {VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 256}}; VkDescriptorPoolCreateInfo havuzBilgi{VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO}; havuzBilgi.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; havuzBilgi.maxSets = 256; havuzBilgi.poolSizeCount = 1; havuzBilgi.pPoolSizes = boyutlar; VK_KONTROL(vkCreateDescriptorPool(vb.aygit(), &havuzBilgi, nullptr, &havuz_)); IMGUI_CHECKVERSION(); const bool ilkKatman = (g_katmanSayisi == 0); ctx_ = ImGui::CreateContext(); // kendi font atlası (context'e ait) ImGui::SetCurrentContext(ctx_); ImGuiIO& io = ImGui::GetIO(); // NavEnableKeyboard AÇMIYORUZ: aksi halde 3D pencere odaktayken ImGui klavyeyi // yakalar (WantCaptureKeyboard) ve uygulama kısayolları (1-4, F, G, Del...) çalışmaz. io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Multi-viewport (panellerin ana pencere DIŞINA sürüklenebilmesi): if (multiViewportAcik()) io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Pencereler YALNIZ başlık çubuğundan taşınır: 3B görünüm içeriği (ImGui::Image // etkileşimsiz) sol-sürüklemede pencereyi kaydırmasın — sürükleme kamera/seçim jesti. io.ConfigWindowsMoveFromTitleBarOnly = true; io.IniFilename = nullptr; fontYukle(); // bu context'in kendi atlasına fontları yükle ui::temaUygula(ui::tema()); // stil her context'e uygulanır ImGui_ImplWin32_Init(pencere.dogalTutamac()); ImGui_ImplVulkan_InitInfo bilgi{}; bilgi.ApiVersion = VK_API_VERSION_1_3; bilgi.Instance = vb.instance(); bilgi.PhysicalDevice = vb.fizikselAygit(); bilgi.Device = vb.aygit(); bilgi.QueueFamily = vb.grafikAile(); bilgi.Queue = vb.grafikKuyruk(); bilgi.DescriptorPool = havuz_; bilgi.MinImageCount = 2; // 2×: SeffafPencere overlay'i ana viewport'la aynı vertex tampon halkasını // paylaşır (kare başına 2 RenderDrawData) → halka derinliği ikiye katlanır ki // GPU'da uçuştaki kare tamponun üstüne yazılmasın. bilgi.ImageCount = vb.gorselSayisi() * 2; bilgi.PipelineInfoMain.RenderPass = vb.renderPass(); bilgi.PipelineInfoMain.MSAASamples = VK_SAMPLE_COUNT_1_BIT; ImGui_ImplVulkan_Init(&bilgi); // Multi-viewport için Vulkan yüzey yaratıcı: Win32 backend Platform_CreateVkSurface // SAĞLAMAZ (GLFW/SDL sağlar) → handler'sız ikincil pencere yaratımı NULL-CALL çökmesi // (imgui_impl_vulkan.cpp:2075). Kendi Win32 yüzeyimizi kurarız. ImGui::GetPlatformIO().Platform_CreateVkSurface = [](ImGuiViewport* vp, ImU64 vkInstance, const void* vkAllocator, ImU64* ciktiYuzey) -> int { VkWin32SurfaceCreateInfoKHR sci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR}; sci.hinstance = ::GetModuleHandleW(nullptr); sci.hwnd = (HWND)(vp->PlatformHandleRaw ? vp->PlatformHandleRaw : vp->PlatformHandle); return (int)vkCreateWin32SurfaceKHR((VkInstance)vkInstance, &sci, (const VkAllocationCallbacks*)vkAllocator, (VkSurfaceKHR*)ciktiYuzey); }; // Girdi WndProc → BU katmanın context'ine yönlenir (çoklu pencerede her pencere // kendi context'ini aktif yapar, sonra ImGui handler'a devreder). ImGuiContext* buCtx = ctx_; pencere.hamMesaj = [buCtx](void* hwnd, u32 mesaj, u64 w, i64 l) -> bool { ImGui::SetCurrentContext(buCtx); if (ImGui_ImplWin32_WndProcHandler((HWND)hwnd, mesaj, w, l)) return true; const ImGuiIO& io = ImGui::GetIO(); // [GEÇİCİ combo-teşhis] Her ana-pencere sol-tıkta girdi-kapı kararını + viewport // sayısını dosyaya yaz. Combo "bazen açılmıyor" tanısı: kapanmayan tıklarda // WantCaptureMouse=0 ise yarış (hipotez A); viewportSayi>1 ise popup-viewport (B). if (mesaj == WM_LBUTTONDOWN) { static std::FILE* tf = std::fopen( (sistem::calistirilabilirDizin() + "combo_teshis.log").c_str(), "w"); if (tf) { std::fprintf(tf, "sol-tik: WantCaptureMouse=%d viewportSayi=%d\n", (int)io.WantCaptureMouse, ImGui::GetPlatformIO().Viewports.Size); std::fflush(tf); } } if (mesaj >= WM_MOUSEFIRST && mesaj <= WM_MOUSELAST) return io.WantCaptureMouse; if (mesaj >= WM_KEYFIRST && mesaj <= WM_KEYLAST) return io.WantCaptureKeyboard; return false; }; // FikoUi shader efekt + simge kitaplığı + şeffaf overlay UYGULAMA-GLOBAL: ilk // katman kurar, tüm pencereler paylaşır (Vulkan aygıtı zaten paylaşımlı). if (ilkKatman) { ui::Efektler::kur(vb, sistem::calistirilabilirDizin() + "shader\\"); ui::kitaplik::kur(vb); ui::SeffafPencere::altyapiKur(vb); } ++g_katmanSayisi; } ImGuiKatman::~ImGuiKatman() { gunluk::g_teshisAdim = "imgui-yikim: 1 SetCurrentContext/bekle"; ImGui::SetCurrentContext(ctx_); vb_.bekle(); gunluk::g_teshisAdim = "imgui-yikim: 2 DestroyPlatformWindows"; if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ImGui::DestroyPlatformWindows(); const bool sonKatman = (g_katmanSayisi == 1); if (sonKatman) { gunluk::g_teshisAdim = "imgui-yikim: 3 altyapiKapat"; ui::SeffafPencere::altyapiKapat(); ui::kitaplik::kapat(); ui::Efektler::kapat(); } gunluk::g_teshisAdim = "imgui-yikim: 4 ImGui_ImplVulkan_Shutdown"; ImGui_ImplVulkan_Shutdown(); gunluk::g_teshisAdim = "imgui-yikim: 5 ImGui_ImplWin32_Shutdown"; ImGui_ImplWin32_Shutdown(); gunluk::g_teshisAdim = "imgui-yikim: 6 DestroyContext"; ImGui::DestroyContext(ctx_); // kendi atlasını da siler (context'e ait) --g_katmanSayisi; gunluk::g_teshisAdim = "imgui-yikim: 7 vkDestroyDescriptorPool"; vkDestroyDescriptorPool(vb_.aygit(), havuz_, nullptr); gunluk::g_teshisAdim = "imgui-yikim: 8 bitti"; } void ImGuiKatman::ctxAktif() { ImGui::SetCurrentContext(ctx_); } void ImGuiKatman::iniDosyasiAyarla(std::string yol) { ImGuiContext* eski = ImGui::GetCurrentContext(); ImGui::SetCurrentContext(ctx_); iniYol_ = std::move(yol); ImGui::GetIO().IniFilename = iniYol_.empty() ? nullptr : iniYol_.c_str(); ImGui::SetCurrentContext(eski); } void ImGuiKatman::kareBasla() { ImGui::SetCurrentContext(ctx_); ImGuiIO& io = ImGui::GetIO(); if (multiViewportAcik()) io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; else io.ConfigFlags &= ~ImGuiConfigFlags_ViewportsEnable; ImGui_ImplVulkan_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); ui::Efektler::kareBasla(); ui::animKare(); // On-demand: fare UI üzerindeyken (hover) VEYA metin girişi aktifken sürekli kare // iste → hover vurgusu/tooltip pürüzsüz (seyrek karede flicker olmaz). Fare 3B // sahnedeyken WantCaptureMouse=false → yine idle'a düşer (tasarruf korunur). if (io.WantCaptureMouse || io.WantTextInput) kareIste(3); } void ImGuiKatman::ciz(VkCommandBuffer kb) { ImGui::SetCurrentContext(ctx_); ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), kb); } void ImGuiKatman::viewportPencereleriCiz() { // Multi-viewport: dışarı taşınan panellerin OS pencerelerini güncelle + çiz. // ANA render pass + submit SONRASI çağrılmalı (kareBitir'den sonra) — backend her // ikincil pencere için kendi swapchain acquire/submit/present'ini yapar. ImGui::SetCurrentContext(ctx_); if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); } } void ImGuiKatman::kareIptal() { ImGui::SetCurrentContext(ctx_); ImGui::EndFrame(); } uint64_t ImGuiKatman::dokuEkle(VkSampler ornekleyici, VkImageView gorunum) { ImGui::SetCurrentContext(ctx_); return (uint64_t)ImGui_ImplVulkan_AddTexture(ornekleyici, gorunum, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); } void ImGuiKatman::dokuKaldir(uint64_t doku) { if (doku) { ImGui::SetCurrentContext(ctx_); ImGui_ImplVulkan_RemoveTexture((VkDescriptorSet)doku); } } }