#include "fiko/kutuk/dexel3_motor.hpp" #include #include #include namespace fiko::kutuk { namespace { inline bool sonluMu(f64 v) { return std::isfinite(v); } inline bool sonluMu(const Vec3d& v) { return sonluMu(v.x) && sonluMu(v.y) && sonluMu(v.z); } // Eksen bileseni erisimi (0=x,1=y,2=z). inline f64 bilesen(const Vec3d& v, int e) { return e == 0 ? v.x : (e == 1 ? v.y : v.z); } // Gecerli (birim) eksen; NaN/sifir -> (0,0,1) (spec §1 guard). Vec3d gecerliEksen(Vec3d e) { if (!sonluMu(e)) return {0, 0, 1}; const f64 u2 = e.uzunlukKare(); if (u2 < 1e-12) return {0, 0, 1}; return e / std::sqrt(u2); } } // namespace // --------------------------------------------------------------------------- // cam::Takim -> TakimGeo // --------------------------------------------------------------------------- TakimGeo takimGeoYap(const cam::Takim& t) { TakimGeo g; g.cap = t.cap > 0 ? t.cap : 0.1; g.boy = t.boy > 0 ? t.boy : g.cap; const f64 r = g.cap * 0.5; switch (t.tip) { case cam::TakimTip::KureselFreze: g.tip = TakimGeo::Tip::Kuresel; g.koseR = r; // uc = tam kure (koseR = takim yaricapi) break; case cam::TakimTip::TorusFreze: g.tip = TakimGeo::Tip::Torus; g.koseR = std::clamp(t.koseYaricap, 0.0, r); break; default: g.tip = TakimGeo::Tip::Duz; g.koseR = std::clamp(t.koseYaricap, 0.0, r); break; } return g; } // --------------------------------------------------------------------------- // Grid kurulumu // --------------------------------------------------------------------------- void Dexel3Motoru::Grid::kur(int isinE, u32 nuS, u32 nvS) { isinEksen = isinE; // u,v = isin ekseni disindaki iki eksen (sirali). int a = 0, b = 1; if (isinE == 0) { a = 1; b = 2; } // isin X -> u=Y,v=Z else if (isinE == 1) { a = 0; b = 2; } // isin Y -> u=X,v=Z else { a = 0; b = 1; } // isin Z -> u=X,v=Y uEksen = a; vEksen = b; nu = nuS; nv = nvS; data.assign(static_cast(nu) * nv * MAKS_SPAN * 2, 0.0f); spanSayi.assign(static_cast(nu) * nv, 0); } // --------------------------------------------------------------------------- // kutukKur // --------------------------------------------------------------------------- bool Dexel3Motoru::kutukKur(const cam::Stok& stok, Aabbf sinir, f64 cozunurluk) { sonHata_.clear(); kuruldu_ = false; supurmeCapUyarisi_ = false; kaldirilanHacim_ = 0.0; birlestirmeSayisi_ = 0; // Gecersiz bbox (min>max) reddi (MEMORY gotcha: NaN kamera fit korunur). if (!sinir.gecerliMi() || !sonluMu(Vec3d{sinir.asgari.x, sinir.asgari.y, sinir.asgari.z}) || !sonluMu(Vec3d{sinir.azami.x, sinir.azami.y, sinir.azami.z})) { sonHata_ = "Gecersiz kutuk siniri (min>max veya NaN)."; return false; } const Vec3f boyutF = sinir.boyut(); const f64 bx = boyutF.x, by = boyutF.y, bz = boyutF.z; if (!(cozunurluk > 1e-9) || !sonluMu(cozunurluk)) { sonHata_ = "Gecersiz cozunurluk."; return false; } // Bos/dejenerre kutuk -> bos grid (NaN uretme). Basari ama malzeme yok. if (bx <= 1e-9 || by <= 1e-9 || bz <= 1e-9) { sinir_ = sinir; cozunurluk_ = cozunurluk; for (auto& g : gridler_) g.kur(g.isinEksen, 0, 0); kuruldu_ = true; return true; } sinir_ = sinir; cozunurluk_ = cozunurluk; const Vec3d mn{sinir.asgari.x, sinir.asgari.y, sinir.asgari.z}; const Vec3d mx{sinir.azami.x, sinir.azami.y, sinir.azami.z}; const f64 ext[3] = {bx, by, bz}; auto hucreSayi = [&](f64 uzunluk) -> u32 { return std::max(1, static_cast(std::ceil(uzunluk / cozunurluk))); }; // Uc grid: isinEksen 0/1/2. u/v = diger iki eksen. for (int e = 0; e < 3; ++e) { int a, b; if (e == 0) { a = 1; b = 2; } else if (e == 1) { a = 0; b = 2; } else { a = 0; b = 1; } Grid& g = gridler_[e]; g.kur(e, hucreSayi(ext[a]), hucreSayi(ext[b])); g.u0 = bilesen(mn, a); g.v0 = bilesen(mn, b); g.w0 = bilesen(mn, e); g.w1 = bilesen(mx, e); g.hucreU = ext[a] / g.nu; g.hucreV = ext[b] / g.nv; // Silindir stok: XY duzleminde radyal maske. Diger tipler: tam kutu (bbox). const bool silindir = (stok.tip == cam::StokTip::Silindir); const f64 rad = silindir ? stok.boyut.x * 0.5 : 0.0; const Vec3f merkF = sinir.merkez(); const Vec3d merk{merkF.x, merkF.y, merkF.z}; for (u32 iv = 0; iv < g.nv; ++iv) { for (u32 iu = 0; iu < g.nu; ++iu) { // Silindir: hucre merkezi XY yaricap disindaysa bos sutun. if (silindir) { const f64 uc = g.u0 + (iu + 0.5) * g.hucreU; const f64 vc = g.v0 + (iv + 0.5) * g.hucreV; // u,v eksenlerinden dunya X/Y bilesenlerini turet (isin eksenine gore). f64 wx = merk.x, wy = merk.y; if (a == 0) wx = uc; else if (a == 1) wy = uc; if (b == 0) wx = vc; else if (b == 1) wy = vc; const f64 dx = wx - merk.x, dy = wy - merk.y; if (dx * dx + dy * dy > rad * rad) continue; // bos sutun } const u32 ofs = g.hucreOfset(iu, iv); g.data[ofs + 0] = static_cast(g.w0); g.data[ofs + 1] = static_cast(g.w1); g.spanSayi[iv * g.nu + iu] = 1; // kutuk basi: tek span (tam bbox) } } } kuruldu_ = true; return true; } // --------------------------------------------------------------------------- // sifirla — dolu kutuk haline geri don // --------------------------------------------------------------------------- void Dexel3Motoru::sifirla() { if (!kuruldu_) return; // kutukKur mantigini stok=Kutu ile tekrar cagirmak yerine mevcut grid'i // yeniden doldur (silindir maskesini korumak icin span=1 olanlar zaten dolu // degildi; en basit ve dogru yol: bos sutunu koru, dolu sutunu tam span yap). kaldirilanHacim_ = 0.0; for (auto& g : gridler_) { for (u32 iv = 0; iv < g.nv; ++iv) { for (u32 iu = 0; iu < g.nu; ++iu) { u8& sc = g.spanSayi[iv * g.nu + iu]; if (sc == 0) continue; // orijinal bos sutun (silindir disi) — koru const u32 ofs = g.hucreOfset(iu, iv); g.data[ofs + 0] = static_cast(g.w0); g.data[ofs + 1] = static_cast(g.w1); sc = 1; } } } } // --------------------------------------------------------------------------- // sutunKes — 5 durum span cikarma (split TAM) + tasma birlestir // --------------------------------------------------------------------------- f64 Dexel3Motoru::sutunKes(Grid& g, u32 iu, u32 iv, f64 cutMin, f64 cutMax) { if (cutMin >= cutMax) return 0.0; // sifir/ters kesim — atla (guard) const u32 idx = iv * g.nu + iu; u8& sc = g.spanSayi[idx]; if (sc == 0) return 0.0; // bos sutun — atla (guard) f32* d = &g.data[g.hucreOfset(iu, iv)]; const f32 cLo = static_cast(cutMin); const f32 cHi = static_cast(cutMax); f64 kaldirilan = 0.0; // Span listesi sirali degil olabilir; yerinde tara. En fazla 1 span artisi // (split) olabilecegi icin gecici tasma guard'i ile calis. u8 i = 0; while (i < sc) { f32& lo = d[i * 2 + 0]; f32& hi = d[i * 2 + 1]; if (cHi <= lo || cLo >= hi) { ++i; continue; } // 1) disinda -> degismez if (cLo <= lo && cHi >= hi) { // 2) kapsar -> sil (span'i son span ile takas) kaldirilan += static_cast(hi - lo); --sc; if (i != sc) { d[i * 2 + 0] = d[sc * 2 + 0]; d[i * 2 + 1] = d[sc * 2 + 1]; } continue; // ayni i'yi tekrar isle (takas edilen span) } if (cLo > lo && cHi < hi) { // 3) ortada -> IKIYE BOL (split-case TAM). [lo,cLo] + [cHi,hi] kaldirilan += static_cast(cHi - cLo); if (sc < MAKS_SPAN) { // yeni span'i sona ekle d[sc * 2 + 0] = cHi; d[sc * 2 + 1] = hi; hi = cLo; // mevcut span alt parca ++sc; } else { // MAKS_SPAN tasti -> en kucuk span'i birlestir (sessiz kirpma YOK). // Once mevcut span'i alt parcaya kirp, ust parcayi en kucuk span ile birlestir. // En kucuk span'i bul. u8 kMin = 0; f32 minUz = d[1] - d[0]; for (u8 k = 1; k < sc; ++k) { const f32 uz = d[k * 2 + 1] - d[k * 2 + 0]; if (uz < minUz) { minUz = uz; kMin = k; } } // en kucuk span'i ust parca [cHi,hi] ile birlestirilmis araliga cevir const f32 ustHi = hi; hi = cLo; // mevcut alt parca sabit d[kMin * 2 + 0] = std::min(d[kMin * 2 + 0], cHi); d[kMin * 2 + 1] = std::max(d[kMin * 2 + 1], ustHi); ++birlestirmeSayisi_; // sessiz kayip yok — istatistik say } ++i; continue; } if (cLo <= lo && cHi < hi) { // 4) soldan -> alt sinir yukari kaldirilan += static_cast(cHi - lo); lo = cHi; ++i; continue; } // 5) sagdan -> ust sinir asagi (cLo>lo && cHi>=hi) kaldirilan += static_cast(hi - cLo); hi = cLo; ++i; } return kaldirilan; } // --------------------------------------------------------------------------- // gridKes — takim etki-kutusu tarama (tum grid DEGIL) + profil // ---------------------------------------------------------------------------- // Takim solid: eksen T (birim), uc konumu poz, yaricap R, boy. Govde silindiri // [0,boy] + uc profili (Duz duzlem / Kuresel yarimkure / Torus kose). Her grid // isini icin isin ekseni w boyunca solid'e giren [w0,w1] araligi analitik cozulur // (u,v sabit). isPointInMaterial 3-grid AND dogru calisir. Hacim: yalniz takim // eksenine PARALEL grid'den say (cift sayim yok — o grid solid'in tam yuksekligini // gorur; lateral gridler ayni hacmi kismi olcer). 3-eksende T=Z -> Z grid sayar. // --------------------------------------------------------------------------- void Dexel3Motoru::gridKes(Grid& g, Vec3d poz, const TakimGeo& takim) { if (g.nu == 0 || g.nv == 0) return; const f64 R = takim.cap * 0.5; if (R <= 0) return; const f64 R2 = R * R; const f64 boy = takim.boy; const Vec3d T = takim.eksen; // birim (cagiranda garanti) const int a = g.uEksen, b = g.vEksen, w = g.isinEksen; // Takim ekseni bu grid'in isin eksenine ne kadar paralel (hacim sayaci icin). const f64 wEkseniIleParalel = std::fabs(bilesen(T, w)); const bool hacimGridi = wEkseniIleParalel > 0.5; // en paralel grid sayar const bool torus = takim.tip == TakimGeo::Tip::Torus; const bool kuresel = takim.tip == TakimGeo::Tip::Kuresel; const f64 rc = std::clamp(takim.koseR, 0.0, R); // torus kose radyusu const f64 flatR = torus ? std::max(0.0, R - rc) : 0.0; // duz bolge yaricapi // Uc alti profil derinligi (uc, eksen boyunca en fazla asagi ne kadar iner). const f64 ucDerinlik = kuresel ? R : (torus ? rc : 0.0); // Etki-kutusu yaricapi (uv duzleminde) — konservatif R + boy izdusumu. const f64 kutuR = R + boy * std::sqrt(std::max(0.0, 1.0 - wEkseniIleParalel * wEkseniIleParalel)); const f64 pu = bilesen(poz, a); const f64 pv = bilesen(poz, b); auto aralik = [&](f64 merkez, f64 o0, f64 hucre, u32 n, u32& i0, u32& i1) { const f64 lo = (merkez - kutuR - o0) / hucre; const f64 hi = (merkez + kutuR - o0) / hucre; if (hi < 0 || lo > n) { i0 = 1; i1 = 0; return; } i0 = static_cast(std::max(0.0, std::floor(lo))); i1 = static_cast(std::min(n - 1, std::ceil(hi))); }; u32 iu0, iu1, iv0, iv1; aralik(pu, g.u0, g.hucreU, g.nu, iu0, iu1); aralik(pv, g.v0, g.hucreV, g.nv, iv0, iv1); if (iu0 > iu1 || iv0 > iv1) return; // Bir dunya noktasinin takim solid icinde olup olmadigi (axial+radial profil). auto solidIci = [&](const Vec3d& p) -> bool { const Vec3d rp = p - poz; const f64 ax = rp.nokta(T); // eksen boyunca (uc=0) const f64 rad2 = std::max(0.0, rp.uzunlukKare() - ax * ax); if (ax >= 0.0 && ax <= boy) return rad2 <= R2; // govde silindiri if (ax > boy) return false; // uc ustu // ax<0: uc profili if (kuresel) return rp.uzunlukKare() <= R2; // yarimkure if (torus) { if (-ax > rc) return false; const f64 rad = std::sqrt(rad2); if (rad <= flatR) return true; // duz merkez alti degil const f64 dd = rad - flatR; return dd * dd + ax * ax <= rc * rc; // kose torus kesiti } return false; // duz uc: ax<0 dis }; const f64 hucreAlan = g.hucreU * g.hucreV; // Isin taramasini takim ekseninin w-izdusum footprint'ine daralt (hot path). const f64 pw = bilesen(poz, w); const f64 wYar = R + boy; // konservatif w-yariciap (govde+uc+egik eksen) const f64 wLo = std::max(g.w0, pw - wYar - ucDerinlik); const f64 wHi = std::min(g.w1, pw + wYar); const f64 dw = (wHi - wLo); if (dw <= 0) return; // Isin boyunca ince adimlarla giris/cikis bul (cozunurlugun yarisi). const f64 orn = std::max(cozunurluk_ * 0.5, (g.w1 - g.w0) / 4096.0); for (u32 iv = iv0; iv <= iv1; ++iv) { const f64 vc = g.v0 + (iv + 0.5) * g.hucreV; for (u32 iu = iu0; iu <= iu1; ++iu) { const f64 uc = g.u0 + (iu + 0.5) * g.hucreU; // Isin boyunca solid araligini bul. Genelde tek surekli aralik (konveks // govde+uc) — ilk giris / son cikis yeterli. Vec3d p; auto ekleBilesen = [&](f64 wv) { f64 xyz[3]; xyz[a] = uc; xyz[b] = vc; xyz[w] = wv; p = {xyz[0], xyz[1], xyz[2]}; }; f64 girW = 1e300, cikW = -1e300; for (f64 wv = wLo; wv <= wHi + 1e-9; wv += orn) { ekleBilesen(wv); if (solidIci(p)) { girW = std::min(girW, wv); cikW = std::max(cikW, wv); } } if (girW > cikW) continue; // bu sutun takim disi const f64 cutMin = girW - orn * 0.5; const f64 cutMax = cikW + orn * 0.5; const f64 kald = sutunKes(g, iu, iv, cutMin, cutMax); if (hacimGridi) kaldirilanHacim_ += kald * hucreAlan; // cift sayim yok if (kald > 0) idxDirty(g, iu, iv); } } } // --------------------------------------------------------------------------- // takimUygula // --------------------------------------------------------------------------- void Dexel3Motoru::takimUygula(Vec3d poz, const TakimGeo& takim) { if (!kuruldu_) return; if (!sonluMu(poz)) return; // NaN poz — atla TakimGeo t = takim; t.eksen = gecerliEksen(takim.eksen); // NaN/sifir eksen -> (0,0,1) if (!(t.cap > 0)) return; for (auto& g : gridler_) gridKes(g, poz, t); } // --------------------------------------------------------------------------- // sweptUygula — adaptif adim (uzunluk/cozunurluk oranli cap + uyari) // --------------------------------------------------------------------------- void Dexel3Motoru::sweptUygula(Vec3d a, Vec3d b, const TakimGeo& takim) { if (!kuruldu_) return; if (!sonluMu(a) || !sonluMu(b)) return; const Vec3d d = b - a; const f64 uz = d.uzunluk(); if (uz < 0.01) { // sifir hareket -> tek ornek (guard) takimUygula(a, takim); return; } // Adim: cozunurlugun yarisi (surekli oluk icin stepSize(std::min(oranliCap, 100000.0)); u32 n = static_cast(std::ceil(uz / adim)); if (n > ustSinir) { n = ustSinir; supurmeCapUyarisi_ = true; } if (n < 1) n = 1; for (u32 i = 0; i <= n; ++i) { const f64 t = static_cast(i) / n; takimUygula(a + d * t, takim); } } // --------------------------------------------------------------------------- // noktaIcerideMi — 3 grid AND (undercut-farkinda) // --------------------------------------------------------------------------- bool Dexel3Motoru::noktaIcerideMi(Vec3d p) const { if (!kuruldu_ || !sonluMu(p)) return false; for (const auto& g : gridler_) { if (g.nu == 0 || g.nv == 0) return false; // bos kutuk const f64 pu = bilesen(p, g.uEksen); const f64 pv = bilesen(p, g.vEksen); const f64 pw = bilesen(p, g.isinEksen); const f64 fu = (pu - g.u0) / g.hucreU; const f64 fv = (pv - g.v0) / g.hucreV; if (fu < 0 || fv < 0 || fu >= g.nu || fv >= g.nv) return false; const u32 iu = static_cast(fu); const u32 iv = static_cast(fv); const u32 idx = iv * g.nu + iu; const u8 sc = g.spanSayi[idx]; if (sc == 0) return false; const f32* dd = &g.data[g.hucreOfset(iu, iv)]; bool ic = false; for (u8 s = 0; s < sc; ++s) { if (pw >= dd[s * 2 + 0] && pw <= dd[s * 2 + 1]) { ic = true; break; } } if (!ic) return false; // bir grid disi -> nokta dis (AND) } return true; } // dirtyMask yardimci (incremental mesh altyapisi — tam kullanim sonraki dalga). bool Dexel3Motoru::idxDirty(Grid& g, u32 iu, u32 iv) { if (g.isinEksen != 2) return false; // yalniz ust grid izlenir (mesh kaynagi) const size_t need = static_cast(g.nu) * g.nv; if (dirtyMask_.size() < need) dirtyMask_.assign(need, 0); dirtyMask_[iv * g.nu + iu] = 1; return true; } // --------------------------------------------------------------------------- // meshCikar — heightmap (ust+alt) + normal (central diff) + yan/ic duvar // --------------------------------------------------------------------------- void Dexel3Motoru::meshCikar(MeshVeri& cikti) { cikti.temizle(); const Grid& g = gridler_[2]; // Z grid (isin Z) = ust/alt heightmap kaynagi if (g.nu == 0 || g.nv == 0) return; // bos kutuk -> bos mesh (NaN uretme) const u32 nu = g.nu, nv = g.nv; heightUst_.assign(static_cast(nu) * nv, std::numeric_limits::quiet_NaN()); heightAlt_.assign(static_cast(nu) * nv, std::numeric_limits::quiet_NaN()); // Her sutun icin ust = en yuksek span.hi, alt = en dusuk span.lo. for (u32 iv = 0; iv < nv; ++iv) { for (u32 iu = 0; iu < nu; ++iu) { const u32 idx = iv * nu + iu; const u8 sc = g.spanSayi[idx]; if (sc == 0) continue; // bos sutun -> NaN (delik) const f32* d = &g.data[g.hucreOfset(iu, iv)]; f32 hi = d[1], lo = d[0]; for (u8 s = 1; s < sc; ++s) { hi = std::max(hi, d[s * 2 + 1]); lo = std::min(lo, d[s * 2 + 0]); } heightUst_[idx] = hi; heightAlt_[idx] = lo; } } const f64 x0 = g.u0, y0 = g.v0; const f64 cu = g.hucreU, cv = g.hucreV; auto dolu = [&](u32 iu, u32 iv) { return g.spanSayi[iv * nu + iu] != 0; }; auto ekleVertex = [&](f32 x, f32 y, f32 z, f32 nx, f32 ny, f32 nz) -> u32 { const u32 vi = cikti.vertexSayi(); cikti.pozisyon.push_back(x); cikti.pozisyon.push_back(y); cikti.pozisyon.push_back(z); cikti.normal.push_back(nx); cikti.normal.push_back(ny); cikti.normal.push_back(nz); cikti.sinir.genislet({x, y, z}); return vi; }; // Ust yuzey: her dolu hucre -> quad (central-diff normal). auto ustNormal = [&](u32 iu, u32 iv) -> Vec3d { const u32 idx = iv * nu + iu; const f32 h = heightUst_[idx]; if (!std::isfinite(h)) return {0, 0, 1}; const u32 il = iu > 0 ? iu - 1 : iu; const u32 ir = iu + 1 < nu ? iu + 1 : iu; const u32 ib = iv > 0 ? iv - 1 : iv; const u32 it = iv + 1 < nv ? iv + 1 : iv; const f32 hl = heightUst_[iv * nu + il], hr = heightUst_[iv * nu + ir]; const f32 hb = heightUst_[ib * nu + iu], ht = heightUst_[it * nu + iu]; const f64 dzx = (std::isfinite(hr) && std::isfinite(hl)) ? (hr - hl) : 0.0; const f64 dzy = (std::isfinite(ht) && std::isfinite(hb)) ? (ht - hb) : 0.0; Vec3d nrm{-dzx / (2 * cu), -dzy / (2 * cv), 1.0}; return nrm.birim(); }; // Ust + Alt yuzey quad'lari. for (u32 iv = 0; iv < nv; ++iv) { for (u32 iu = 0; iu < nu; ++iu) { if (!dolu(iu, iv)) continue; const u32 idx = iv * nu + iu; const f32 hu = heightUst_[idx], ha = heightAlt_[idx]; const f32 xa = static_cast(x0 + iu * cu), xb = static_cast(x0 + (iu + 1) * cu); const f32 ya = static_cast(y0 + iv * cv), yb = static_cast(y0 + (iv + 1) * cv); const Vec3d nu3 = ustNormal(iu, iv); const f32 nx = static_cast(nu3.x), ny = static_cast(nu3.y), nz = static_cast(nu3.z); // ust quad (CCW yukari bakan) const u32 a0 = ekleVertex(xa, ya, hu, nx, ny, nz); const u32 a1 = ekleVertex(xb, ya, hu, nx, ny, nz); const u32 a2 = ekleVertex(xb, yb, hu, nx, ny, nz); const u32 a3 = ekleVertex(xa, yb, hu, nx, ny, nz); cikti.indeks.insert(cikti.indeks.end(), {a0, a1, a2, a0, a2, a3}); // alt quad (asagi bakan) const u32 b0 = ekleVertex(xa, ya, ha, 0, 0, -1); const u32 b1 = ekleVertex(xb, ya, ha, 0, 0, -1); const u32 b2 = ekleVertex(xb, yb, ha, 0, 0, -1); const u32 b3 = ekleVertex(xa, yb, ha, 0, 0, -1); cikti.indeks.insert(cikti.indeks.end(), {b0, b2, b1, b0, b3, b2}); // Yan/ic duvar: komsu bos VEYA komsu ust yukseklik farki > esik -> duvar. const f32 esik = static_cast(std::max(cu, cv)); struct Kom { int dux, dvy; f32 wx0, wy0, wx1, wy1; f32 nx, ny; }; const Kom komsular[4] = { {-1, 0, xa, ya, xa, yb, -1, 0}, // sol { 1, 0, xb, yb, xb, ya, 1, 0}, // sag { 0,-1, xb, ya, xa, ya, 0,-1}, // on { 0, 1, xa, yb, xb, yb, 0, 1}, // arka }; for (const Kom& k : komsular) { const int ju = static_cast(iu) + k.dux; const int jv = static_cast(iv) + k.dvy; f32 komHu = ha; // komsu yoksa/bosssa duvar tabana kadar bool duvar = true; if (ju >= 0 && jv >= 0 && ju < static_cast(nu) && jv < static_cast(nv) && dolu(ju, jv)) { komHu = heightUst_[jv * nu + ju]; duvar = std::fabs(hu - komHu) > esik; // ic duvar (cep kenari) } if (!duvar) continue; const f32 ust = hu, alt = duvar && komHu < hu ? komHu : ha; if (ust <= alt) continue; const u32 v0 = ekleVertex(k.wx0, k.wy0, ust, k.nx, k.ny, 0); const u32 v1 = ekleVertex(k.wx1, k.wy1, ust, k.nx, k.ny, 0); const u32 v2 = ekleVertex(k.wx1, k.wy1, alt, k.nx, k.ny, 0); const u32 v3 = ekleVertex(k.wx0, k.wy0, alt, k.nx, k.ny, 0); cikti.indeks.insert(cikti.indeks.end(), {v0, v1, v2, v0, v2, v3}); } } } } } // namespace fiko::kutuk