#include "fiko/girdi/dokunma_jest.hpp" #include namespace fiko::girdi { namespace { // Sema tablolari tek yerde — semaEsleme + semaCoz ayni kaynaktan okur (iki tablo // birbirinden kayarsa "Ozel"e dusme bugu olurdu). constexpr DokunmaEylem kFikoYT[(size_t)DokunmaJest::Sayi] = { DokunmaEylem::Dondur, // TekParmakSurukle — CAD standardi (Onshape/Fusion) DokunmaEylem::Pan, // IkiParmakSurukle DokunmaEylem::Zoom, // IkiParmakPinch DokunmaEylem::Yok, // UcParmakSurukle DokunmaEylem::Isaretci, // KalemUcSurukle — kalem hassas isaretci (secim/sketch) DokunmaEylem::Dondur, // KalemGovdeSurukle }; constexpr DokunmaEylem kCatia[(size_t)DokunmaJest::Sayi] = { DokunmaEylem::Pan, // TekParmakSurukle — CATIA orta-tus = pan refleksi DokunmaEylem::Dondur, // IkiParmakSurukle DokunmaEylem::Zoom, // IkiParmakPinch DokunmaEylem::Pan, // UcParmakSurukle DokunmaEylem::Isaretci, // KalemUcSurukle DokunmaEylem::Pan, // KalemGovdeSurukle }; constexpr DokunmaEylem kFare[(size_t)DokunmaJest::Sayi] = { DokunmaEylem::Isaretci, // TekParmakSurukle — tek parmak sol-tus gibi (trap kutusu calisir) DokunmaEylem::Dondur, // IkiParmakSurukle DokunmaEylem::Zoom, // IkiParmakPinch DokunmaEylem::Pan, // UcParmakSurukle DokunmaEylem::Isaretci, // KalemUcSurukle DokunmaEylem::Dondur, // KalemGovdeSurukle }; const DokunmaEylem* semaTablo(DokunmaSema s) { switch (s) { case DokunmaSema::Catia: return kCatia; case DokunmaSema::Fare: return kFare; default: return kFikoYT; // FikoYT + Ozel baslangici } } } // namespace void DokunmaEsleme::semaDoldur(DokunmaEsleme& e, DokunmaSema s) { const DokunmaEylem* t = semaTablo(s); for (size_t i = 0; i < (size_t)DokunmaJest::Sayi; ++i) e.eylem[i] = t[i]; } DokunmaEsleme DokunmaEsleme::semaEsleme(DokunmaSema s) { DokunmaEsleme e; semaDoldur(e, s); return e; } DokunmaSema DokunmaEsleme::semaCoz() const { for (u8 s = 0; s < (u8)DokunmaSema::Ozel; ++s) { const DokunmaEylem* t = semaTablo((DokunmaSema)s); bool ayni = true; for (size_t i = 0; i < (size_t)DokunmaJest::Sayi && ayni; ++i) ayni = (eylem[i] == t[i]); if (ayni) return (DokunmaSema)s; } return DokunmaSema::Ozel; } DokunmaJestSistemi::Isaretci* DokunmaJestSistemi::bul(u32 kimlik) { for (auto& i : isaretciler_) if (i.var && i.kimlik == kimlik) return &i; return nullptr; } const DokunmaJestSistemi::Isaretci* DokunmaJestSistemi::bul(u32 kimlik) const { for (const auto& i : isaretciler_) if (i.var && i.kimlik == kimlik) return &i; return nullptr; } DokunmaJestSistemi::Isaretci* DokunmaJestSistemi::bosYuva() { for (auto& i : isaretciler_) if (!i.var) return &i; return nullptr; // 5'ten fazla parmak → yoksay (jest zaten tanimsiz) } bool DokunmaJestSistemi::tekIsaretciHam(Vec2f& konum, bool& suruklendi) const { if (aktif_ != 1) return false; for (const auto& i : isaretciler_) { if (!i.var) continue; konum = i.konum; suruklendi = i.suruklendi; return true; } return false; } bool DokunmaJestSistemi::tekIsaretciKonum(Vec2f& konum) const { if (aktif_ != 1) return false; for (const auto& i : isaretciler_) { if (!i.var) continue; if (i.suruklendi) return false; konum = i.konum; return true; } return false; } void DokunmaJestSistemi::ozet(Vec2f& merkez, f32& yayilim, int& adet) const { merkez = {}; yayilim = 0.0f; adet = 0; for (const auto& i : isaretciler_) if (i.var) { merkez += i.konum; ++adet; } if (adet == 0) return; merkez *= (1.0f / (f32)adet); // Yayilim = merkeze ortalama uzaklik. Iki parmakta = yarim pinch mesafesi; // ORAN kullandigimiz icin (log) katsayi onemsiz, parmak sayisindan bagimsiz calisir. for (const auto& i : isaretciler_) if (i.var) yayilim += (i.konum - merkez).uzunluk(); yayilim /= (f32)adet; } void DokunmaJestSistemi::temeliTazele() { int adet = 0; ozet(oncekiMerkez_, oncekiYayilim_, adet); cokParmakTemeli_ = (adet >= 2); } void DokunmaJestSistemi::basildi(u32 kimlik, Vec2f konum, IsaretciTur tur, bool govdeTusu) { if (bul(kimlik)) return; // yinelenen DOWN (platform tekrari) → yoksay Isaretci* i = bosYuva(); if (!i) return; *i = Isaretci{}; i->var = true; i->kimlik = kimlik; i->tur = tur; i->govdeTusu = govdeTusu; i->basKonum = i->konum = i->oncekiKonum = konum; ++aktif_; // Parmak sayisi degisti → cok-parmak temelini YENIDEN kur (aksi halde ikinci // parmak indigi kare merkez/yayilim sicrar → model firlar). temeliTazele(); if (aktif_ >= 2) cokParmakOldu_ = true; } void DokunmaJestSistemi::hareket(u32 kimlik, Vec2f konum, bool govdeTusu) { Isaretci* i = bul(kimlik); if (!i) return; i->konum = konum; // Govde tusu surukleme ORTASINDA basilabilir/birakilabilir; jest secimi her kare // guncel duruma bakar (kalem tus durumu MOVE mesajlarinda gelir). i->govdeTusu = govdeTusu; if (!i->suruklendi && (konum - i->basKonum).uzunluk() >= ayar.suruklemeEsik) i->suruklendi = true; } void DokunmaJestSistemi::birakildi(u32 kimlik) { Isaretci* i = bul(kimlik); if (!i) return; // Tik/CiftTik: yalniz TEK isaretci, esik alti hareket, kisa sure ve bu etkilesimde // hic cok-parmak jesti olmadiysa (iki parmak pan'inin son parmagi tik saymasin). const bool tikOlur = !i->suruklendi && !i->uzunYayildi && !cokParmakOldu_ && aktif_ == 1 && i->sure <= ayar.tikSure; if (tikOlur) { // Isaretci eylemine bagli jest (kalem ucu / "Fare" semasinda tek parmak) zaten // sol-tus gibi surulur → secimi UYGULAMA yapar, ikinci kez tik yayma. const DokunmaJest jest = (i->tur == IsaretciTur::Kalem) ? (i->govdeTusu ? DokunmaJest::KalemGovdeSurukle : DokunmaJest::KalemUcSurukle) : DokunmaJest::TekParmakSurukle; if (esleme.al(jest) != DokunmaEylem::Isaretci) { const bool cift = sonTikGecen_ <= 0.35f && (i->konum - sonTikKonum_).uzunluk() <= ayar.suruklemeEsik; cikti_.olayNokta = i->konum; cikti_.olayKalem = (i->tur == IsaretciTur::Kalem); cikti_.olayGovdeTusu = cikti_.olayKalem && i->govdeTusu; if (cift) { cikti_.ciftTik = true; sonTikGecen_ = 1e9f; } else { cikti_.tik = true; sonTikGecen_ = 0.0f; sonTikKonum_ = i->konum; } } } i->var = false; --aktif_; if (aktif_ <= 0) { aktif_ = 0; cokParmakOldu_ = false; navAktif_ = false; } temeliTazele(); } void DokunmaJestSistemi::iptal() { for (auto& i : isaretciler_) i.var = false; aktif_ = 0; cokParmakTemeli_ = false; cokParmakOldu_ = false; navAktif_ = false; } void DokunmaJestSistemi::eylemUygula(DokunmaEylem e, Vec2f delta, f32 logOran, Vec2f merkez) { switch (e) { case DokunmaEylem::Dondur: cikti_.dondurX += delta.x * ayar.dondurHassasiyet; cikti_.dondurY += delta.y * ayar.dondurHassasiyet; navAktif_ = true; break; case DokunmaEylem::Pan: cikti_.panX += delta.x * ayar.panHassasiyet; cikti_.panY += delta.y * ayar.panHassasiyet; navAktif_ = true; break; case DokunmaEylem::Zoom: cikti_.zoomLogOran += logOran * ayar.zoomHassasiyet; cikti_.zoomMerkez = merkez; navAktif_ = true; break; case DokunmaEylem::Isaretci: cikti_.isaretciBasili = true; cikti_.isaretciNokta = merkez; break; default: break; } } void DokunmaJestSistemi::guncelle(f32 dt) { sonTikGecen_ += dt; for (auto& i : isaretciler_) { if (!i.var) continue; i.sure += dt; // Uzun bas: tek isaretci, hareketsiz, esik sure asildi → baglam menusu (sag-tik). // Isaretci eylemine bagliysa da yayilir: kalem ucuyla uzun bas = sag-tik beklenir. if (!i.uzunYayildi && !i.suruklendi && aktif_ == 1 && !cokParmakOldu_ && i.sure >= ayar.uzunBasSure) { i.uzunYayildi = true; cikti_.uzunBas = true; cikti_.olayNokta = i.konum; cikti_.olayKalem = (i.tur == IsaretciTur::Kalem); cikti_.olayGovdeTusu = cikti_.olayKalem && i.govdeTusu; } } if (aktif_ == 0) { cokParmakTemeli_ = false; return; } if (aktif_ == 1) { Isaretci* tek = nullptr; for (auto& i : isaretciler_) if (i.var) { tek = &i; break; } // Uzun bas tetiklendiyse jest baglam menusune gitti → nav/isaretci surme (menu // acikken model firlamasin, arkada secim kutusu acilmasin). if (tek && !tek->uzunYayildi) { const DokunmaJest jest = (tek->tur == IsaretciTur::Kalem) ? (tek->govdeTusu ? DokunmaJest::KalemGovdeSurukle : DokunmaJest::KalemUcSurukle) : DokunmaJest::TekParmakSurukle; const DokunmaEylem e = esleme.al(jest); // Isaretci (sol-tus esdegeri): DOKUNUR DOKUNMAZ basili — esik bekleme yok, // yoksa kalem ucuyla sketch cizimi/trap ilk 8px'i kaybederdi. if (e == DokunmaEylem::Isaretci) { cikti_.isaretciBasili = true; cikti_.isaretciNokta = tek->konum; } else if (tek->suruklendi) { eylemUygula(e, tek->konum - tek->oncekiKonum, 0.0f, tek->konum); } } cokParmakTemeli_ = false; } else { // Cok parmak: merkez kaymasi (surukle) + yayilim orani (pinch) AYNI ANDA. Vec2f merkez{}; f32 yayilim = 0.0f; int adet = 0; ozet(merkez, yayilim, adet); if (cokParmakTemeli_) { const DokunmaJest surukleJest = (adet >= 3) ? DokunmaJest::UcParmakSurukle : DokunmaJest::IkiParmakSurukle; eylemUygula(esleme.al(surukleJest), merkez - oncekiMerkez_, 0.0f, merkez); // Pinch: yayilim ORANI (log). Esik → parmaklar birlikte kayarken kucuk // yayilim gurultusu zoom'a sizmasin. if (adet == 2 && oncekiYayilim_ > 1e-3f && yayilim > 1e-3f && std::abs(yayilim - oncekiYayilim_) * 2.0f >= ayar.pinchEsik) eylemUygula(esleme.al(DokunmaJest::IkiParmakPinch), {}, std::log(yayilim / oncekiYayilim_), merkez); } oncekiMerkez_ = merkez; oncekiYayilim_ = yayilim; cokParmakTemeli_ = true; } for (auto& i : isaretciler_) if (i.var) i.oncekiKonum = i.konum; } DokunmaCikti DokunmaJestSistemi::tuket() { const DokunmaCikti c = cikti_; cikti_ = DokunmaCikti{}; return c; } } // namespace fiko::girdi