#include "fiko/ui/efekt.hpp" #include #include #include "fiko/render/boru_hatti.hpp" #include "fiko/render/vulkan_baglam.hpp" #include "fiko/ui/tema.hpp" #include "imgui_impl_vulkan.h" namespace fiko::ui { namespace { struct EfektItme { float rect[4]; // min.xy, max.xy (framebuffer px) float hedef[4]; // fb boyut, zaman, yuvarlak float renkA[4]; float renkB[4]; float param[4]; // şiddet, yayılım, mod(nabız/ölçek), serbest }; enum class EfektTip { Glow, Aurora }; struct EfektVeri { EfektTip tip; EfektItme itme; }; BoruHatti* g_glowHat = nullptr; BoruHatti* g_auroraHat = nullptr; // Sabit arena: pointer'lar kare boyunca geçerli kalmalı (realloc yasak). std::array g_arena; int g_arenaSayac = 0; void geriCagri(const ImDrawList*, const ImDrawCmd* cmd) { auto* rs = (ImGui_ImplVulkan_RenderState*)ImGui::GetPlatformIO().Renderer_RenderState; if (!rs || !rs->CommandBuffer) return; const auto* v = (const EfektVeri*)cmd->UserCallbackData; const BoruHatti* hat = v->tip == EfektTip::Glow ? g_glowHat : g_auroraHat; if (!hat) return; VkCommandBuffer kb = rs->CommandBuffer; // Scissor: quad sınırları (yayılım payı dahil), framebuffer'a kıskaçlı. const float pay = v->itme.param[1]; const float fbG = v->itme.hedef[0], fbY = v->itme.hedef[1]; const float x0 = v->itme.rect[0] - pay, y0 = v->itme.rect[1] - pay; const float x1 = v->itme.rect[2] + pay, y1 = v->itme.rect[3] + pay; VkRect2D kirp; kirp.offset.x = (int32_t)(x0 < 0 ? 0 : x0); kirp.offset.y = (int32_t)(y0 < 0 ? 0 : y0); kirp.extent.width = (uint32_t)((x1 > fbG ? fbG : x1) - (float)kirp.offset.x); kirp.extent.height = (uint32_t)((y1 > fbY ? fbY : y1) - (float)kirp.offset.y); if ((int)kirp.extent.width <= 0 || (int)kirp.extent.height <= 0) return; vkCmdSetScissor(kb, 0, 1, &kirp); hat->bagla(kb); hat->itmeSabitYaz(kb, &v->itme, sizeof(EfektItme)); vkCmdDraw(kb, 6, 1, 0, 0); } // GPU yolu yoksa / ikincil viewport'ta: katmanlı DrawList yaklaşımı. void glowFallback(ImDrawList* dl, ImVec2 min, ImVec2 max, const ImVec4& renkA, float yuvarlak, float siddet) { for (int i = 1; i <= 3; ++i) { const float y = (float)i * 2.0f; dl->AddRect({min.x - y, min.y - y}, {max.x + y, max.y + y}, u32(renkA, 0.15f * siddet / (float)i), yuvarlak + y, 0, 2.5f); } } bool gpuYoluVar(ImDrawList* dl) { if (!g_glowHat) return false; if (g_arenaSayac >= (int)g_arena.size()) return false; // Yalnız ana viewport'un pencere listeleri: ikincil OS pencereleri backend'in // kendi render geçişini kullanır (format uyumu garanti değil) → fallback. ImGuiViewport* vp = ImGui::GetWindowViewport(); if (vp != ImGui::GetMainViewport()) return false; (void)dl; return true; } EfektVeri* kayitHazirla(EfektTip tip, ImVec2 min, ImVec2 max, const ImVec4& renkA, const ImVec4& renkB, float yuvarlak, float yayilim, float siddet, float mod) { ImGuiViewport* vp = ImGui::GetMainViewport(); const ImVec2 vpPos = vp->Pos; EfektVeri* v = &g_arena[(size_t)g_arenaSayac++]; v->tip = tip; EfektItme& it = v->itme; it.rect[0] = min.x - vpPos.x; it.rect[1] = min.y - vpPos.y; it.rect[2] = max.x - vpPos.x; it.rect[3] = max.y - vpPos.y; it.hedef[0] = vp->Size.x; it.hedef[1] = vp->Size.y; it.hedef[2] = (float)ImGui::GetTime(); it.hedef[3] = yuvarlak; it.renkA[0] = renkA.x; it.renkA[1] = renkA.y; it.renkA[2] = renkA.z; it.renkA[3] = renkA.w; it.renkB[0] = renkB.x; it.renkB[1] = renkB.y; it.renkB[2] = renkB.z; it.renkB[3] = renkB.w; it.param[0] = siddet; it.param[1] = yayilim; it.param[2] = mod; it.param[3] = 0.0f; return v; } } // namespace void Efektler::kur(VulkanBaglam& vb, const std::string& shaderDizin) { kapat(); BoruHattiAyar ayar; ayar.vertexSpv = shaderDizin + "fikoui.vert.spv"; ayar.itmeSabitBayt = sizeof(EfektItme); ayar.ayiklama = VK_CULL_MODE_NONE; ayar.derinlikTest = false; ayar.derinlikYaz = false; ayar.gecis = vb.renderPass(); ayar.fragmentSpv = shaderDizin + "fikoui_glow.frag.spv"; ayar.harmanEkleyici = true; g_glowHat = new BoruHatti(vb, ayar); ayar.fragmentSpv = shaderDizin + "fikoui_aurora.frag.spv"; ayar.harmanEkleyici = false; ayar.harmanla = true; g_auroraHat = new BoruHatti(vb, ayar); } void Efektler::kapat() { delete g_glowHat; delete g_auroraHat; g_glowHat = nullptr; g_auroraHat = nullptr; } bool Efektler::hazir() { return g_glowHat != nullptr; } void Efektler::kareBasla() { g_arenaSayac = 0; } void Efektler::glow(ImDrawList* dl, ImVec2 min, ImVec2 max, const ImVec4& renkA, const ImVec4& renkB, float yuvarlak, float yayilim, float siddet, float nabizHz) { siddet *= tema().glowSiddet; if (siddet <= 0.01f) return; if (!gpuYoluVar(dl)) { glowFallback(dl, min, max, renkA, yuvarlak, siddet); return; } EfektVeri* v = kayitHazirla(EfektTip::Glow, min, max, renkA, renkB, yuvarlak, yayilim, siddet, nabizHz); dl->AddCallback(geriCagri, v); dl->AddCallback(ImDrawCallback_ResetRenderState, nullptr); } void Efektler::aurora(ImDrawList* dl, ImVec2 min, ImVec2 max, float siddet, float olcek) { if (!gpuYoluVar(dl)) { // fallback: sade dikey gradient const Tema& t = tema(); const ImU32 ust = u32(karisim(t.panel, t.vurgu, 0.10f), siddet); const ImU32 alt = u32(karisim(t.panel, t.vurgu2, 0.08f), siddet); dl->AddRectFilledMultiColor(min, max, ust, ust, alt, alt); return; } const Tema& t = tema(); const ImVec4 a = karisim(t.panel, t.vurgu, 0.45f); const ImVec4 b = karisim(t.panel, t.vurgu2, 0.45f); EfektVeri* v = kayitHazirla(EfektTip::Aurora, min, max, a, b, t.yuvarlak + 2.0f, 0.0f, siddet, olcek); dl->AddCallback(geriCagri, v); dl->AddCallback(ImDrawCallback_ResetRenderState, nullptr); } } // namespace fiko::ui