#include "malzeme_nesnesi.hpp" #include #include #include #include "fiko/cekirdek/cekirdek.hpp" #include "fiko/sahne/sahne.hpp" namespace fiko { namespace { // Malzeme düğümünü gövdesine bağlayan bileşen. Ayrı bileşen olmasının nedeni: // senkron fonksiyonu "hangi gövdenin düğümü var" sorusunu tek geçişte O(N) // yanıtlayabilsin (nesne deposunu dynamic_cast'le taramak yerine). struct MalzemeBagBilesen { Varlik govde = VARLIK_YOK; }; } // namespace std::string MalzemeNesnesi::ad() const { if (!adOzel_.empty()) return adOzel_; if (const malzeme::MalzemeTanim* m = tanim()) return m->ad; return "Malzeme"; } OzellikSeti MalzemeNesnesi::ozellikler(Dunya&) { OzellikSeti s; const malzeme::MalzemeTanim* m = tanim(); if (!m) return s; // Salt-okunur özet: gerçek düzenleme Malzeme penceresinde (tek kaynak). // Buradan yazmak kütüphaneyi değiştirir → aynı malzemeyi kullanan TÜM gövdeleri // etkilerdi; kullanıcı bunu beklemeyeceği için bilerek okunur bırakıldı. s.push_back(Ozellik::metin("Malzeme", [m] { return m->ad; }, nullptr)); s.back().saltOkunur = true; s.push_back(Ozellik::metin("Sınıf", [m] { return std::string(malzeme::sinifAdi(m->sinif)); }, nullptr)); s.back().saltOkunur = true; s.push_back(Ozellik::renk("Taban Renk", [m] { return m->tabanRenk; }, nullptr)); s.back().saltOkunur = true; s.push_back(Ozellik::sayi("Yoğunluk (kg/m³)", [m] { return m->yogunluk; }, nullptr)); s.back().saltOkunur = true; s.push_back(Ozellik::sayi("Metaliklik", [m] { return (f64)m->metaliklik; }, nullptr)); s.back().saltOkunur = true; s.push_back(Ozellik::sayi("Pürüzlülük", [m] { return (f64)m->puruzluluk; }, nullptr)); s.back().saltOkunur = true; return s; } const MalzemeNesnesi* MalzemeGorunum::nesne() const { if (!dunya_) return nullptr; const NesneKok* k = dunya_->bul(kimlik()); return k ? dynamic_cast(k->get()) : nullptr; } Vec3f MalzemeGorunum::agacRengi() const { const MalzemeNesnesi* n = nesne(); const malzeme::MalzemeTanim* m = n ? n->tanim() : nullptr; return m ? m->tabanRenk : Vec3f{0.6f, 0.6f, 0.6f}; } std::string MalzemeGorunum::agacMiniBilgi(Dunya&) const { const MalzemeNesnesi* n = nesne(); const malzeme::MalzemeTanim* m = n ? n->tanim() : nullptr; if (!m) return {}; char b[96]; std::snprintf(b, sizeof(b), "%s · %.0f kg/m³", malzeme::sinifAdi(m->sinif), m->yogunluk); return b; } bool malzemeDugumuMu(Cekirdek& cekirdek, Varlik v) { return dynamic_cast(cekirdek.nesne(v)) != nullptr; } void malzemeDugumleriSenkron(Cekirdek& cekirdek, Sahne& sahne, const malzeme::MalzemeKutuphanesi& kut, const malzeme::MalzemeAtama& atama) { Dunya& d = cekirdek.dunya(); // 1) Mevcut malzeme düğümlerini gövdeye göre indeksle (tek geçiş). std::unordered_map govdeDugum; // gövde → malzeme düğümü std::vector fazla; // atama kalmamış / gövdesi ölmüş { Depo& depo = d.depo(); for (std::size_t i = 0; i < depo.boyut(); ++i) { const Varlik dugum = depo.varlikAt(i); const Varlik govde = depo.bilesenAt(i).govde; const u32 atanan = atama.govdeninMalzemesi(govde); if (!atanan || !sahne.bul(govde)) { fazla.push_back(dugum); continue; } // Aynı gövde için ikinci düğüm oluşmuşsa (olmamalı) fazlasını at. if (!govdeDugum.emplace(govde, dugum).second) fazla.push_back(dugum); } } // 2) Fazlaları sil (atama kaldırıldı ya da gövde silindi). // yokEt TÜM depolardan siler (tür-silinmiş geri çağrımlar) → düğüm izsiz gider. for (Varlik v : fazla) d.yokEt(v); // 3) Eksikleri kur, malzemesi değişeni güncelle. for (const auto& [govde, malzemeKimlik] : atama.govdeler()) { if (!malzemeKimlik || !sahne.bul(govde)) continue; auto it = govdeDugum.find(govde); if (it != govdeDugum.end()) { if (auto* mn = dynamic_cast(cekirdek.nesne(it->second))) mn->malzemeAyarla(malzemeKimlik); continue; } const Varlik v = d.olustur(); d.ekle(v, MalzemeBagBilesen{govde}); // Gövdenin ALTINDA yaşar → ağaçta PartBody/gövde satırının çocuğu olarak, // Pad/Pocket ile aynı seviyede görünür. sira=-1: feature'lardan ÖNCE (CATIA). d.ekle(v, HiyerarsiBilesen{govde, -1}); d.ekle(v, std::make_unique(v, govde, malzemeKimlik, &kut)); d.ekle(v, std::make_unique(v, &d)); } } } // namespace fiko