#pragma once #include #include #include #include #include #include #include #include "belge.hpp" #include "isik_durum.hpp" #include "fiko/render/boru_hatti.hpp" #include "fiko/render/golge_harita.hpp" #include "isin_alani.hpp" #include "malzeme_gpu.hpp" #include "fiko/render/kare_ubo.hpp" #include "fiko/girdi/dokunma_jest.hpp" // dokunmaEslemeGlobal / dokunmaAyarGlobal tipleri #include "fiko/render/gpu_tampon.hpp" #include "fiko/render/viewport_hedef.hpp" #include "fiko/render/vertex.hpp" // KenarVertex (kenar mega-parti pişirme scratch'i) namespace fiko { struct Dugum; // saydamScratch (per-frame scratch — pointer yeterli) // ---- Dokunmatik / kalem (bkz. motor/girdi/dokunma_jest.hpp) ---- // Ana anahtar: kapalıyken WM_POINTER olayları TÜKETİLMEZ → Windows dokunuşu fare // mesajına yükseltir = dokunmatik desteği eklenmeden ÖNCEKİ davranış birebir. // AyarSistemi "girdi.dokunmatik_aktif". bool& dokunmatikAktif(); // Jest→eylem eşlemesi (şema önayarları + kullanıcı özel). Pencere-başına jest sistemi // bunu her kare okur → ayar anında geçerli olur. AyarSistemi "girdi.dokunma_*". girdi::DokunmaEsleme& dokunmaEslemeGlobal(); // Eşikler/hassasiyetler (sürükleme eşiği, uzun bas süresi, pinch eşiği, çarpanlar). girdi::DokunmaAyar& dokunmaAyarGlobal(); // Orbit/gezinme LOD debounce: fare durduktan SONRA kaç kare kaba mesh'te kalınıp ince'ye // dönüleceği (~kare/60 = saniye). Büyük = LOD daha uzun kalır (durunca geç netleşir ama daha // akıcı hisseder), küçük = çabuk netleşir. AyarSistemi "gorunum.orbit_lod_gecikme". int& orbitLodGecikmeKare(); // Bireysel çizim yolunda da orbit/hover-gezme LOD (mega-parti eşiği ALTINDAKİ az-gövdeli // sahnede — dev tek-gövde modeller burada yaşar). Etkileşim sürerken kaba mesh çizilir, // fare durunca ince döner. AyarSistemi "gorunum.bireysel_orbit_lod". bool& bireyselOrbitLod(); // Bireysel kaba LOD alt eşiği (gövde indeks sayısı): altındaki gövdede etkileşim LOD'u // atlanır — küçük modelde toggle görsel titreşim yapar, ince mesh zaten ucuz. // AyarSistemi "gorunum.bireysel_lod_min_indeks". int& bireyselLodMinIndeks(); // Etkileşim LOD ana anahtarı: kapalıyken orbit/hover'da HİÇ kaba mesh'e düşülmez — // her zaman tam kalite (mesh titremesi tamamen kalkar; ağır modelde orbit yavaşlar). // AyarSistemi "gorunum.etkilesim_lod_aktif". bool& etkilesimLodAktif(); // LOD'u fare gezerken (yalnız hover, tuş basılmadan) de tetikle. VARSAYILAN KAPALI → // boşta fare gezerken yüzey kalitesi düşmez; kaba mesh yalnız gerçek navigasyonda devreye // girer (aşağıdaki kip anahtarları). AyarSistemi "gorunum.lod_hover_tetik". bool& lodHoverTetik(); // Navigasyon kipi başına etkileşim LOD anahtarları: hangi kipte kaliteyi geçici düşürelim. // AyarSistemi "gorunum.lod_dondur" / "gorunum.lod_pan" / "gorunum.lod_zoom". bool& lodDondurAktif(); // döndürme (orbit) bool& lodPanAktif(); // taşıma (pan) bool& lodZoomAktif(); // zoom (sürükle + tekerlek) // Çok-seçim vurgu eşiği: bundan FAZLA gövde seçiliyse seçili gövdeler mega-partiden çıkarılmaz // (seçim değişiminde cook + binlerce bireysel/overlay draw olmaz) → 3B per-gövde vurgu atlanır // (ürün ağacı seçimi gösterir). 0 = kapalı. AyarSistemi "gorunum.cok_secim_vurgu_esigi". int& cokSecimVurguEsigi(); // Seçim cook'unu atla: seçili gövdeyi mega-partiden çıkarma (hover gibi partide tut) → her // seçim değişiminde mega-parti yeniden pişmez (~18ms hitch gider). Vurgu z-bias'lı overlay ile // basılır. VARSAYILAN KAPALI (RUNTIME TEST: z-fighting/speckle). AyarSistemi "gorunum.secim_cook_atla". bool& secimCookAtla(); // Tek-yüz vurgusunda (seçim/hover overlay) yalnız o yüzün indeks aralığını çiz (vars. AÇIK). bool& yuzAralikCiz(); // Tek-kare takılma (hitch) teşhis eşiği, ms (0 = kapalı). int& kareHitchEsigiMs(); // Kare içi ADIM ölçer: eşiği (kareHitchEsigiMs) aşan her bölüm log'a tek satır yazar → // "hangi karede" değil "karenin NERESİNDE" takıldığını gösterir. Yalnız teşhis; yıkımda // bir karşılaştırma, sıcak yolda ölçülebilir maliyeti yok. struct AdimOlcer { const char* ad; std::chrono::steady_clock::time_point t0; explicit AdimOlcer(const char* a) : ad(a), t0(std::chrono::steady_clock::now()) {} ~AdimOlcer(); }; #define FIKO_ADIM(etiket) ::fiko::AdimOlcer fikoAdimOlcer_{etiket} bool& cpuKenarPick(); // kenar hover CPU ekran-uzayı pick (GPU kenar pass'ı atla) // ============================================================================ // belge_ciz — bir Belge'nin 3D sahnesini bir ViewportHedef'e çizen boru hattı // (MDI Dalga 2, docs/mdi_blueprint.md). main.cpp'deki kare-içi sahne-çizim // bloğu buraya taşındı: hover çözümü + kamera matrisi + GPU pick geçişi + // model/analiz/kenar/nokta/seçim geçişleri. Belge penceresi başına bir // ViewportHedef + CizimOnbellek ile N belge bağımsız çizilir. // ============================================================================ // Viewport render pass'ine bağlı sabit grafik pipeline seti. Uygulama-GLOBAL: // render pass + formatlar tek olduğundan tüm belgeler/hedefler paylaşır. struct BoruHatlari { BoruHatlari(VulkanBaglam& vulkan, const std::string& shaderDizin); // Undercut görünürlük gölge haritası. analizHat'ın descriptor set yerleşimini // sağladığı için hatlardan ÖNCE kurulmalı (üye sırası = inşa sırası). GolgeHarita golge; // Et kalınlığı per-fragment ışın alanı (set=1). analizHat'ın ikinci descriptor // set yerleşimini sağlar → hatlardan ÖNCE kurulmalı (üye sırası = inşa sırası). IsinAlani isinAlani; // Kare-sabit ışık/renk UBO'su — model hatlarının descriptor set yerleşimini // sağlar → golge ile aynı gerekçe: hatlardan ÖNCE kurulmalı (üye sırası). KareUbo kareUbo; // Malzeme/doku sistemi (set=1: malzeme SSBO + yuz→malzeme + doku dizisi). // Model hatlarinin ikinci descriptor set yerlesimini saglar → hatlardan ONCE // kurulmali (uye sirasi = insa sirasi; kareUbo ile ayni gerekce). MalzemeGpuKaynak malzemeGpu; BoruHatti modelHat, modelSeffafHat; BoruHatti modelHatTekYon; // CULL_BACK varyant (çift-taraflı KAPALI — Ayarlar) BoruHatti analizHat, analizSeffafHat, zebraHat, reflectHat; // Undercut EXACT gölge overlay'i: analiz hattının ikizi ama derinlik biası // KAMERAYA doğru (altındaki yüzle z-fight etmesin). BoruHatti golgeOverlayHat; BoruHatti kenarHat, kenarVurguHat, refKenarHat, refKenarVurguHat, noktaHat; // GPU kesit kapağı (stencil capping): sayım (parite) + düzlem quad dolgusu. BoruHatti kesitSayimHat, kesitDolguHat; // Selection Stack "peek" lens: highlight gövde, imleç dairesinde derinlik-testsiz. BoruHatti peekHat; BoruHatti peekKenarHat, peekNoktaHat; // aktif kenar/nokta lens içinde parlak }; // Et kalınlığı per-fragment ışın alanını (set=1 BVH/üçgen SSBO) güncel tutar. // KOMUT TAMPONU DIŞINDA, kare güncelleme fazında çağrılmalı: içeride descriptor // yazımı + gerekirse device-idle var (kayıt ortasında yapılırsa fence zaman aşımı // → aygıt kaybı; golge_harita.cpp'de yaşanmış tuzağın aynısı). // Kalınlık analizi yoksa alanı boşaltır. Aynı anda TEK gövde desteklenir. void kalinlikIsinAlaniGuncelle(Sahne& sahne, analiz::AnalizSistemi& analizSis, BoruHatlari& hatlar); // Son güncellemenin sonucu: "AKTİF" ya da neden devrede olmadığı (panelde canlı // gösterilir — "hâlâ üçgensel" şikâyeti tahminle değil OKUNARAK ayıklansın). const char* kalinlikIsinDurumu(u32* ucgenCikti = nullptr); // Görünüm-başına çizim önbelleği (eski fonksiyon-static'ler): mega-parti // VB/IB imzaları + analiz skaler tamponları. Belge penceresi başına BİR örnek — // static kalsaydı N belge aynı partiyi ezip dururdu (her karede tam pişirme). struct CizimOnbellek { std::unordered_map> skalerOnbellek; // analizKimlik → (versiyon, tampon) // Undercut EXACT gölge overlay'i: analizKimlik → (golgeSurum, vertex, indeks). struct GolgeGpu { u32 surum = 0; GpuTampon vbuf, ibuf; }; std::unordered_map golgeOnbellek; std::unordered_map> bantOnbellek; // Radius bant (mod 7) paketli renk tamponu GpuTampon sifirTampon; // analitik/kesit modları için binding=1 dolgusu u32 sifirBoyut = 0; std::vector mergeImza; // model mega-parti imzası (İNCE seviye) GpuTampon mergeVB, mergeIB; u32 mergeIndeksSayi = 0; // KABA (LOD) seviye AYRI kalıcı buffer: orbit/hover LOD toggle'ı buffer PAYLAŞMAZ → // ince↔kaba geçişi yeniden pişirme TETİKLEMEZ (yalnız hangi buffer çizileceği seçilir). // Her seviye kendi geometri imzası değişince (rebuild/renk) bir kez pişer. std::vector mergeImzaKaba; GpuTampon mergeVBKaba, mergeIBKaba; u32 mergeIndeksSayiKaba = 0; std::vector kenarMergeImza; // kenar mega-parti imzası GpuTampon kenarMergeVB; u32 kenarMergeSayi = 0; // A#2: imza scratch'leri (kare-başı yeniden tahsis yerine reserve'li yeniden kullanım). // clear() kapasiteyi korur → statik sahnede realloc zinciri yok; kopya yalnız pişmede. std::vector imzaScratch; std::vector kenarImzaScratch; // Kenar partisi teşhis/scratch: imzaya paralel düğüm kimliği (hangi düğüm imzayı // bozdu → her-kare pişirme kökü) + pişirme vertex tamponu (kare-başı tahsis yerine). std::vector kenarImzaKimlik, kenarImzaKimlikSon; std::vector kenarPisirScratch; std::unordered_set seciliGovdeScratch; // A#6: seçili gövde kümesi (kare-başı yeniden kullan) u64 seciliGovdeImza = ~0ull; // yukarıdaki kümenin son imzası → seçim değişmedikçe kurma std::vector> saydamScratch; // saydam/per-yüz-alfa gövde sıralaması (kare-başı yeniden kullan) // Depth-hint (adaptif near/far) cache: kamera SABİTken (hover) her-kare O(N) düğüm gezmesini // atla. Kamera hareketinde VEYA periyodik (30 kare, geometri değişimi güvencesi) yeniden hesap. Vec3f depthKamKonum{}; f32 depthEnYakin = -1.0f, depthEnUzak = -1.0f; int depthKare = -1000; // ---- P1: GPU pick gating (fare/kamera/sahne sabitken pick geçişini atla) ---- // Pick geçişi tüm sahnenin İKİNCİ bir raster'ı; imleç altındaki eleman // değişemiyorsa (sabit fare+kamera+sahne) her kare koşmasına gerek yok → // önceki pick sonucu korunur (hover değişmez). Bu üyeler önceki karenin // tetik-durumunu tutar (görünüm-başına; static olsa N belge birbirini ezerdi). bool pickGecerli = false; // en az bir pick kaydedildi mi u32 sonHareketKare = 0; // fare/orbit son hareket karesi (etkileşim LOD debounce) f32 pickSonImlecX = 0, pickSonImlecY = 0; bool pickSonHover = false; u64 pickSonVpImza = 0; // kamera vp matris hash u64 pickSonSahneImza = 0; // pick'e giren düğüm kümesi hash u32 pickSonFiltre = 0; // fYuz/fKenar/fNokta/fGovde bitleri u64 pickCalisan = 0, pickToplam = 0; // perf: kaç karede pick koştu / toplam // CPU yüz hover (isinVur) gating: fare/kamera/düğüm-sayısı sabitse yeniden pick YOK // (sonuç secimSis'te retained). Büyük modelde her-kare BVH, çok-dosyada O(N) atlanır. f32 hoverSonImlecX = -1e30f, hoverSonImlecY = -1e30f; u64 hoverSonVpImza = 0; std::size_t hoverSonDugumSayi = ~std::size_t(0); bool hoverSonBvhEksik = false; // BVH kurulurken skip etme (sonuç kısmi) }; // Kare-başı çizim girdisi (belge penceresinden toplanır). struct BelgeCizimGirdi { f32 zaman = 0; // animasyonlu vurgu fazı int kare = 0; // perf log aralığı f32 imlecX = 0, imlecY = 0; // pick imleci (viewport-yerel piksel) bool vpHover = false; // imleç bu belgenin viewport'u üstünde mi // P1+: kamera navigasyonu (döndür/pan/zoom) sürüyorken GPU pick geçişini duraklat // — imleç zaten model üstünde gezmiyor, hover değişmez. Nav bitince (bir sonraki // sabit karede vp farkı) pick kendiliğinden devam eder → ciddi FPS kazancı. bool navigasyonAktif = false; // Aktif navigasyon kipi (etkileşim LOD kapısı — hangi kip kaliteyi düşürür ayarlanır): // -1 yok, 0 döndür, 1 zoom (sürükle), 2 pan. tekerlekZoom = fare tekerleğiyle zoom. int navKip = -1; bool tekerlekZoom = false; // B#2 (agent): kamera yumuşatma animasyonu (zoom/fit/snap slerp) sürüyor mu. Fare sabit // olsa bile görüntü oturana kadar hareketli → o süre GPU pick boşuna koşar. Oturunca vp // farkı pick'i bir kez yeniden tetikler. Çağrı yeri kamera.hareketliMi() ile besler. bool kameraHareketli = false; // Selection Stack "peek" (CATIA lens): highlight'lı gövdeyi imleç dairesi içinde // derinlik-testsiz (önündeki elemanlar olmadan) göster. peekGovde=0 → kapalı. // merkez/yarıçap framebuffer-piksel (viewport-yerel). u32 peekGovde = 0; u32 peekAlt = 0; // aktif adayın yüz/kenar/nokta ordinali (lens'te parlak) u32 peekTur = 1; // 0 gövde, 1 yüz, 2 kenar, 3 nokta f32 peekMerkezX = 0, peekMerkezY = 0, peekYari = 0; }; // Perf göstergesi (davranış-nötr): VAR OLAN [perf] ölçüm noktalarının son // değerlerini merkezi bir yapıda tutar; ImGui HUD overlay (main.cpp) bunları // okur. YENİ ölçüm EKLEMEZ — belge_ciz zaten hesapladığı sayıları buraya yazar, // HUD gösterir. Render/pipeline'a dokunmaz. Uygulama-GLOBAL tekil. struct PerfGosterge { u32 modelDrawCagri = 0; // son kare: model geçişi draw-call sayısı u32 megaIndeks = 0; // son mega-parti indeks sayısı (>0 → toplu çizim aktif) f64 modelCookMs = 0.0; // son model mega-parti pişirme süresi (ms) f64 kenarCookMs = 0.0; // son kenar mega-parti pişirme süresi (ms) bool hudAcik = false; // HUD overlay görünürlüğü (Görünüm menüsü toggle) // ---- CAM Simülasyon ölçümleri (ÖLÇÜM, tahmin yok; sim açıkken doldurulur) ---- bool simAktif = false; // sim penceresi bu kare açık mı (HUD'da sim satırlarını göster) u32 simNoktaSayi = 0; // aktif program nokta sayısı f64 simKurMs = 0.0; // son programKur+simSahneKur (bir kez; açılışta) f64 simGuncelleMs = 0.0; // son kare sim güncelleme (reveal+takım) f64 simKutukMs = 0.0; // son kare kütük oyma (batch) f64 simKutukMeshMs = 0.0;// son kütük mesh çıkarma // ---- Malzeme sistemi (ÖLÇÜM): tablo yeniden kurulumu SADECE içerik değişince // koşmalı; HUD'da bu sayının kare-başı sıfır kalması "sıcak yol temiz" // demektir (tahmin değil, ölçüm — [[feedback_tahmin_yasak]]). f64 malzemeTazeleMs = 0.0; // son GERÇEK tablo kurulumu (ms) u32 malzemeTazeleSayac = 0; // açılıştan beri kaç kez kuruldu u32 malzemeYuzTablo = 0; // yüz→malzeme tablosu boyutu }; inline PerfGosterge& perfGosterge() { static PerfGosterge g; return g; } // Belgenin sahnesini hedefe çizer (pick geçişi dahil). sonEnBoy/sonG/sonY: // bu karenin viewport oranı/boyutu (çağıran ekran-uzayı projeksiyonlarında // kullanır — pusula/trap/ölçüm overlay'leri). void belgeCiz(Belge& b, ViewportHedef& hedef, VulkanBaglam& vulkan, BoruHatlari& hatlar, CizimOnbellek& onbellek, const IsikDurum& isikDurum, VkCommandBuffer kb, const BelgeCizimGirdi& girdi, f32& sonEnBoy, f32& sonG, f32& sonY); } // namespace fiko