#include "fiko/malzeme/malzeme.hpp" #include #include #include #include "fiko/core/metin.hpp" namespace fiko::malzeme { namespace { constexpr f32 kPi = 3.14159265358979f; f32 kelepce(f32 v, f32 a, f32 b) { return v < a ? a : (v > b ? b : v); } void kelepceRenk(Vec3f& r) { r.x = kelepce(r.x, 0.0f, 1.0f); r.y = kelepce(r.y, 0.0f, 1.0f); r.z = kelepce(r.z, 0.0f, 1.0f); } // Hazır malzeme kısa kurucusu — tablo okunur kalsın diye. MalzemeTanim haz(const char* ad, MalzemeSinif sinif, Vec3f renk, f32 metal, f32 puruz, f64 yogunluk) { MalzemeTanim m; m.ad = ad; m.sinif = sinif; m.hazir = true; m.tabanRenk = renk; m.metaliklik = metal; m.puruzluluk = puruz; m.yogunluk = yogunluk; return m; } } // namespace const char* sinifAdi(MalzemeSinif s) { switch (s) { case MalzemeSinif::Metal: return "Metal"; case MalzemeSinif::Plastik: return "Plastik"; case MalzemeSinif::Ahsap: return "Ahşap"; case MalzemeSinif::Cam: return "Cam"; case MalzemeSinif::Kaucuk: return "Kauçuk"; case MalzemeSinif::Seramik: return "Seramik"; case MalzemeSinif::Boya: return "Boya"; case MalzemeSinif::Kumas: return "Kumaş"; case MalzemeSinif::Sivi: return "Sıvı"; default: return "Diğer"; } } const char* kaplamaAdi(KaplamaTip k) { switch (k) { case KaplamaTip::Triplanar: return "Triplanar"; case KaplamaTip::Duzlemsel: return "Düzlemsel"; case KaplamaTip::Silindirik: return "Silindirik"; default: return "Küresel"; } } const char* sarmaAdi(SarmaTip s) { switch (s) { case SarmaTip::Tekrar: return "Tekrar"; case SarmaTip::Ayna: return "Ayna"; default: return "Kenar"; } } const char* kanalAdi(DokuKanal k) { switch (k) { case DokuKanal::Taban: return "Taban Renk"; case DokuKanal::Puruzluluk: return "Pürüzlülük"; case DokuKanal::Metaliklik: return "Metaliklik"; case DokuKanal::Normal: return "Normal"; case DokuKanal::Ortme: return "Örtme (AO)"; case DokuKanal::Emisyon: return "Emisyon"; case DokuKanal::Opaklik: return "Opaklık"; default: return "Kabartma"; } } bool kanalLineerMi(DokuKanal k) { return k != DokuKanal::Taban && k != DokuKanal::Emisyon; } bool MalzemeTanim::dokuluMu() const { for (const DokuKatman& d : dokular) if (d.acik()) return true; return false; } void MalzemeTanim::gecerliKil() { kelepceRenk(tabanRenk); kelepceRenk(kaplamaRenk); kelepceRenk(emilimRenk); kelepceRenk(parlakTuyRenk); kelepceRenk(sacilmaRenk); emisyonRenk.x = std::max(0.0f, emisyonRenk.x); emisyonRenk.y = std::max(0.0f, emisyonRenk.y); emisyonRenk.z = std::max(0.0f, emisyonRenk.z); opaklik = kelepce(opaklik, 0.0f, 1.0f); metaliklik = kelepce(metaliklik, 0.0f, 1.0f); // Pürüzlülük tabanı 0 DEĞİL: GGX 0'da tekilleşir (sonsuz parlak nokta, NaN riski). puruzluluk = kelepce(puruzluluk, 0.015f, 1.0f); yansima = kelepce(yansima, 0.0f, 1.0f); ortmeSiddet = kelepce(ortmeSiddet, 0.0f, 1.0f); anizotropi = kelepce(anizotropi, -1.0f, 1.0f); kaplamaBerrak = kelepce(kaplamaBerrak, 0.0f, 1.0f); kaplamaPuruz = kelepce(kaplamaPuruz, 0.015f, 1.0f); gecirgenlik = kelepce(gecirgenlik, 0.0f, 1.0f); kalinlik = std::max(0.0f, kalinlik); kirilmaIndisi = kelepce(kirilmaIndisi, 1.0f, 3.0f); parlakTuyPuruz = kelepce(parlakTuyPuruz, 0.015f, 1.0f); sacilmaSiddet = kelepce(sacilmaSiddet, 0.0f, 1.0f); emisyonSiddet = std::max(0.0f, emisyonSiddet); triplanarKeskinlik = kelepce(triplanarKeskinlik, 1.0f, 32.0f); kabartmaDerinlik = kelepce(kabartmaDerinlik, 0.0f, 10.0f); yogunluk = std::max(0.0, yogunluk); for (DokuKatman& d : dokular) d.siddet = kelepce(d.siddet, 0.0f, 1.0f); } MalzemeGpu gpuKaydiYap(const MalzemeTanim& m) { MalzemeGpu g{}; g.tabanRenk[0] = m.tabanRenk.x; g.tabanRenk[1] = m.tabanRenk.y; g.tabanRenk[2] = m.tabanRenk.z; g.tabanRenk[3] = m.opaklik; g.emisyon[0] = m.emisyonRenk.x; g.emisyon[1] = m.emisyonRenk.y; g.emisyon[2] = m.emisyonRenk.z; g.emisyon[3] = m.emisyonSiddet; g.pbr[0] = m.metaliklik; g.pbr[1] = m.puruzluluk; g.pbr[2] = m.yansima; g.pbr[3] = m.ortmeSiddet; g.kaplamaKat[0] = m.kaplamaBerrak; g.kaplamaKat[1] = m.kaplamaPuruz; g.kaplamaKat[2] = m.anizotropi; g.kaplamaKat[3] = m.anizotropiAci * kPi / 180.0f; g.gecirgen[0] = m.gecirgenlik; g.gecirgen[1] = m.kalinlik; g.gecirgen[2] = m.kirilmaIndisi; g.gecirgen[3] = m.kabartmaDerinlik; g.emilim[0] = m.emilimRenk.x; g.emilim[1] = m.emilimRenk.y; g.emilim[2] = m.emilimRenk.z; g.tuy[0] = m.parlakTuyRenk.x; g.tuy[1] = m.parlakTuyRenk.y; g.tuy[2] = m.parlakTuyRenk.z; g.tuy[3] = m.parlakTuyPuruz; g.sacilma[0] = m.sacilmaRenk.x; g.sacilma[1] = m.sacilmaRenk.y; g.sacilma[2] = m.sacilmaRenk.z; g.sacilma[3] = m.sacilmaSiddet; g.kaplamaRenk[0] = m.kaplamaRenk.x; g.kaplamaRenk[1] = m.kaplamaRenk.y; g.kaplamaRenk[2] = m.kaplamaRenk.z; g.izdusum[0] = static_cast(m.kaplama); g.izdusum[1] = m.dokuDonus * kPi / 180.0f; g.izdusum[2] = m.triplanarKeskinlik; g.izdusum[3] = m.dunyaUzayinda ? 1.0f : 0.0f; // Ölçek = "kaç mm'de bir tekrar" → shader çarpan olarak 1/ölçek ister; sıfıra // bölmeyi burada ele (sıcak yolda shader'da dallanma olmasın). const f32 s[3] = {m.dokuOlcek.x, m.dokuOlcek.y, m.dokuOlcek.z}; for (u32 i = 0; i < 3; ++i) g.dokuOlcek[i] = std::abs(s[i]) > 1e-6f ? 1.0f / s[i] : 0.0f; g.dokuOfset[0] = m.dokuOfset.x; g.dokuOfset[1] = m.dokuOfset.y; g.dokuOfset[2] = m.dokuOfset.z; for (u32 i = 0; i < DOKU_KANAL_SAYI; ++i) { // İşaret ters-çevirme bayrağını taşır → shader'da ek alan/dallanma yok. g.kanalSiddet[i] = m.dokular[i].ters ? -m.dokular[i].siddet : m.dokular[i].siddet; g.dokuSlot[i] = m.dokular[i].gpuSlot; } return g; } // ── Kütüphane ─────────────────────────────────────────────────────────────── void MalzemeKutuphanesi::hazirlariYukle() { MalzemeTanim h[] = { haz("Çelik", MalzemeSinif::Metal, {0.56f, 0.57f, 0.58f}, 1.0f, 0.35f, 7850), haz("Paslanmaz Çelik", MalzemeSinif::Metal, {0.66f, 0.67f, 0.69f}, 1.0f, 0.18f, 7900), haz("Alüminyum", MalzemeSinif::Metal, {0.83f, 0.84f, 0.86f}, 1.0f, 0.28f, 2700), haz("Fırçalı Alüminyum",MalzemeSinif::Metal, {0.81f, 0.82f, 0.84f}, 1.0f, 0.34f, 2700), haz("Pirinç", MalzemeSinif::Metal, {0.78f, 0.62f, 0.26f}, 1.0f, 0.25f, 8500), haz("Bakır", MalzemeSinif::Metal, {0.83f, 0.47f, 0.29f}, 1.0f, 0.22f, 8960), haz("Döküm Demir", MalzemeSinif::Metal, {0.36f, 0.36f, 0.37f}, 1.0f, 0.62f, 7200), haz("Krom", MalzemeSinif::Metal, {0.78f, 0.79f, 0.80f}, 1.0f, 0.05f, 7190), haz("Titanyum", MalzemeSinif::Metal, {0.62f, 0.60f, 0.58f}, 1.0f, 0.32f, 4500), haz("Altın", MalzemeSinif::Metal, {1.00f, 0.77f, 0.34f}, 1.0f, 0.12f, 19300), haz("ABS Plastik", MalzemeSinif::Plastik, {0.85f, 0.85f, 0.87f}, 0.0f, 0.45f, 1040), haz("Naylon (PA6)", MalzemeSinif::Plastik, {0.92f, 0.90f, 0.84f}, 0.0f, 0.55f, 1140), haz("POM (Delrin)", MalzemeSinif::Plastik, {0.90f, 0.90f, 0.90f}, 0.0f, 0.35f, 1410), haz("Meşe", MalzemeSinif::Ahsap, {0.62f, 0.44f, 0.26f}, 0.0f, 0.65f, 750), haz("Kontrplak", MalzemeSinif::Ahsap, {0.76f, 0.62f, 0.42f}, 0.0f, 0.72f, 600), haz("Cam", MalzemeSinif::Cam, {0.92f, 0.96f, 0.97f}, 0.0f, 0.03f, 2500), haz("Kauçuk (NBR)", MalzemeSinif::Kaucuk, {0.10f, 0.10f, 0.11f}, 0.0f, 0.88f, 1200), haz("Seramik", MalzemeSinif::Seramik, {0.94f, 0.93f, 0.90f}, 0.0f, 0.20f, 2400), haz("Boya (Kırmızı)", MalzemeSinif::Boya, {0.72f, 0.08f, 0.08f}, 0.0f, 0.30f, 1300), haz("Boya (Mavi)", MalzemeSinif::Boya, {0.09f, 0.24f, 0.65f}, 0.0f, 0.30f, 1300), haz("Kadife", MalzemeSinif::Kumas, {0.25f, 0.05f, 0.10f}, 0.0f, 0.85f, 400), haz("Su", MalzemeSinif::Sivi, {0.80f, 0.92f, 0.95f}, 0.0f, 0.05f, 1000), }; // Sınıfa özgü ince ayarlar — hazır malzemeler "ilk bakışta doğru" görünsün. auto ayarla = [](MalzemeTanim& m) { switch (m.sinif) { case MalzemeSinif::Metal: m.yansima = 1.0f; break; case MalzemeSinif::Boya: m.kaplamaBerrak = 0.7f; m.kaplamaPuruz = 0.05f; break; case MalzemeSinif::Cam: m.gecirgenlik = 0.92f; m.opaklik = 0.25f; m.kirilmaIndisi = 1.52f; m.emilimRenk = {0.86f, 0.94f, 0.90f}; m.kalinlik = 4.0f; break; case MalzemeSinif::Sivi: m.gecirgenlik = 0.95f; m.opaklik = 0.28f; m.kirilmaIndisi = 1.33f; m.emilimRenk = {0.75f, 0.90f, 0.95f}; m.kalinlik = 20.0f; break; case MalzemeSinif::Kumas: m.parlakTuyRenk = {0.45f, 0.20f, 0.25f}; m.parlakTuyPuruz = 0.35f; break; case MalzemeSinif::Ahsap: m.yansima = 0.35f; break; case MalzemeSinif::Kaucuk: m.yansima = 0.25f; break; default: break; } }; for (MalzemeTanim& m : h) { if (m.ad == "Fırçalı Alüminyum") { m.anizotropi = 0.8f; m.anizotropiAci = 0.0f; } if (m.ad == "Altın") m.yansima = 1.0f; ayarla(m); m.gecerliKil(); ekle(m); } } u32 MalzemeKutuphanesi::ekle(MalzemeTanim m) { m.kimlik = m.kimlik ? m.kimlik : siradaki_; siradaki_ = std::max(siradaki_, m.kimlik + 1); ++surum_; if (MalzemeTanim* v = bul(m.kimlik)) { *v = std::move(m); return v->kimlik; } liste_.push_back(std::move(m)); return liste_.back().kimlik; } bool MalzemeKutuphanesi::sil(u32 kimlik) { auto it = std::find_if(liste_.begin(), liste_.end(), [kimlik](const MalzemeTanim& m) { return m.kimlik == kimlik; }); if (it == liste_.end() || it->hazir) return false; liste_.erase(it); ++surum_; return true; } MalzemeTanim* MalzemeKutuphanesi::bul(u32 kimlik) { for (MalzemeTanim& m : liste_) if (m.kimlik == kimlik) return &m; return nullptr; } const MalzemeTanim* MalzemeKutuphanesi::bul(u32 kimlik) const { return const_cast(this)->bul(kimlik); } u32 MalzemeKutuphanesi::kopyala(u32 kimlik) { const MalzemeTanim* k = bul(kimlik); if (!k) return 0; MalzemeTanim y = *k; y.kimlik = 0; y.hazir = false; y.ad += " (kopya)"; return ekle(std::move(y)); } std::vector MalzemeKutuphanesi::ara(const std::string& parca, bool sinifFiltre, MalzemeSinif sinif) const { const std::string p = sadeTr(parca); std::vector sonuc; for (const MalzemeTanim& m : liste_) { if (sinifFiltre && m.sinif != sinif) continue; if (!p.empty() && sadeTr(m.ad).find(p) == std::string::npos && sadeTr(m.aciklama).find(p) == std::string::npos) continue; sonuc.push_back(m.kimlik); } return sonuc; } std::vector MalzemeKutuphanesi::gpuTablo() const { std::vector t; t.reserve(liste_.size() + 1); t.push_back(MalzemeGpu{}); // 0 = malzeme yok (nötr; shader indeks 0'ı eler) for (const MalzemeTanim& m : liste_) t.push_back(gpuKaydiYap(m)); return t; } u32 MalzemeKutuphanesi::gpuIndeks(u32 kimlik) const { for (std::size_t i = 0; i < liste_.size(); ++i) if (liste_[i].kimlik == kimlik) return static_cast(i + 1); return 0; } // ── Atama ─────────────────────────────────────────────────────────────────── void MalzemeAtama::govdeyeAta(u32 govde, u32 malzeme) { if (!govde) return; if (malzeme) govdeler_[govde] = malzeme; else govdeler_.erase(govde); ++surum_; } void MalzemeAtama::yuzeAta(u32 govde, u32 yuzOrdinal, u32 malzeme) { if (!govde || !yuzOrdinal) return; const u64 a = yuzAnahtar(govde, yuzOrdinal); if (malzeme) yuzler_[a] = malzeme; else yuzler_.erase(a); ++surum_; } u32 MalzemeAtama::govdeninMalzemesi(u32 govde) const { auto it = govdeler_.find(govde); return it == govdeler_.end() ? 0u : it->second; } u32 MalzemeAtama::coz(u32 govde, u32 yuzOrdinal) const { if (yuzOrdinal) { auto it = yuzler_.find(yuzAnahtar(govde, yuzOrdinal)); if (it != yuzler_.end()) return it->second; } return govdeninMalzemesi(govde); } void MalzemeAtama::govdeyiTemizle(u32 govde) { govdeler_.erase(govde); yuzleriTemizle(govde); ++surum_; } void MalzemeAtama::yuzleriTemizle(u32 govde) { for (auto it = yuzler_.begin(); it != yuzler_.end();) it = (it->first >> 32) == govde ? yuzler_.erase(it) : std::next(it); ++surum_; } void MalzemeAtama::malzemeyiKaldir(u32 malzeme) { if (!malzeme) return; for (auto it = govdeler_.begin(); it != govdeler_.end();) it = it->second == malzeme ? govdeler_.erase(it) : std::next(it); for (auto it = yuzler_.begin(); it != yuzler_.end();) it = it->second == malzeme ? yuzler_.erase(it) : std::next(it); ++surum_; } void MalzemeAtama::temizle() { govdeler_.clear(); yuzler_.clear(); ++surum_; } std::vector> MalzemeAtama::govdeninYuzleri(u32 govde) const { std::vector> sonuc; for (const auto& [anahtar, malzeme] : yuzler_) if ((anahtar >> 32) == govde) sonuc.emplace_back(static_cast(anahtar & 0xFFFFFFFFu), malzeme); std::sort(sonuc.begin(), sonuc.end()); return sonuc; } } // namespace fiko::malzeme