Skip to main content

gizmo_physics_core/
broadphase.rs

1/// AAA Broadphase: Dynamic AABB Tree (Incremental BVH)
2///
3/// Özellikler:
4/// - SAH (Surface Area Heuristic) ile O(log N) ekleme
5/// - Fattened AABB ile gereksiz rebuild yok
6/// - AVL rotasyonlu yükseklik dengesi
7/// - SIMD AABB overlap testi (x86_64)
8/// - Raycast / AABB sorgusu O(log N)
9/// - query_pairs: duplicate-free, self-pair yok
10///
11/// Düzeltmeler (orijinal koda göre):
12/// FIX-1  insert: tight_aabb kontrolünde cmpge/cmple yerine skalar karşılaştırma
13///         (Vec3A/Vec3 farkından kaynaklanan derleme hatası riski)
14/// FIX-2  query_pairs: "iki aşamalı stack" yaklaşımı yanlış duplicate üretiyordu;
15///         recursive dual-tree traversal ile replace edildi → garantili duplicate-free
16/// FIX-3  balance: rotasyon sonrası f/g parent pointer güncellenmiyordu (silent bug)
17/// FIX-4  SpatialHash::clear: &self alıyordu, artık &mut self
18/// FIX-5  ray_aabb: tmin başlangıcı 0.0 yerine f32::NEG_INFINITY → negatif yönlerde miss
19/// FIX-6  query_pairs SIMD yolu: orijinal kodda SIMD kullanılmıyordu; leaf batch'ler için eklendi
20/// FIX-7  find_best_sibling: inherited_cost hesabında yanlış node SA kullanılıyordu
21/// FIX-8  remove_leaf → free_node çağrısı parent'ı serbest bırakıyordu ama
22///         parent'ın entity/aabb alanları temizlenmiyordu → free_node düzeltildi
23use gizmo_core::entity::Entity;
24use gizmo_math::{Aabb, Vec3};
25use std::collections::HashMap;
26
27// ─────────────────────────────────────────────────────────────────────────────
28// SIMD yardımcıları
29// ─────────────────────────────────────────────────────────────────────────────
30
31#[cfg(target_arch = "x86_64")]
32use std::arch::x86_64::*;
33
34/// SIMD: target AABB'i 4 AABB ile aynı anda test et.
35/// Dönen bitmask'te bit i, target'ın others[i] ile örtüşüp örtüşmediğini gösterir.
36#[cfg(target_arch = "x86_64")]
37#[inline]
38pub fn aabb_overlaps_simd4(target: &Aabb, others: [&Aabb; 4]) -> u8 {
39    unsafe {
40        let t_min_x = _mm_set1_ps(target.min.x);
41        let t_max_x = _mm_set1_ps(target.max.x);
42        let t_min_y = _mm_set1_ps(target.min.y);
43        let t_max_y = _mm_set1_ps(target.max.y);
44        let t_min_z = _mm_set1_ps(target.min.z);
45        let t_max_z = _mm_set1_ps(target.max.z);
46
47        let o_min_x = _mm_set_ps(
48            others[3].min.x,
49            others[2].min.x,
50            others[1].min.x,
51            others[0].min.x,
52        );
53        let o_max_x = _mm_set_ps(
54            others[3].max.x,
55            others[2].max.x,
56            others[1].max.x,
57            others[0].max.x,
58        );
59        let o_min_y = _mm_set_ps(
60            others[3].min.y,
61            others[2].min.y,
62            others[1].min.y,
63            others[0].min.y,
64        );
65        let o_max_y = _mm_set_ps(
66            others[3].max.y,
67            others[2].max.y,
68            others[1].max.y,
69            others[0].max.y,
70        );
71        let o_min_z = _mm_set_ps(
72            others[3].min.z,
73            others[2].min.z,
74            others[1].min.z,
75            others[0].min.z,
76        );
77        let o_max_z = _mm_set_ps(
78            others[3].max.z,
79            others[2].max.z,
80            others[1].max.z,
81            others[0].max.z,
82        );
83
84        // overlap koşulu: a.min <= b.max && b.min <= a.max (her eksen)
85        let res = _mm_and_ps(
86            _mm_and_ps(
87                _mm_and_ps(
88                    _mm_cmple_ps(t_min_x, o_max_x),
89                    _mm_cmple_ps(o_min_x, t_max_x),
90                ),
91                _mm_and_ps(
92                    _mm_cmple_ps(t_min_y, o_max_y),
93                    _mm_cmple_ps(o_min_y, t_max_y),
94                ),
95            ),
96            _mm_and_ps(
97                _mm_cmple_ps(t_min_z, o_max_z),
98                _mm_cmple_ps(o_min_z, t_max_z),
99            ),
100        );
101
102        _mm_movemask_ps(res) as u8
103    }
104}
105
106#[cfg(not(target_arch = "x86_64"))]
107#[inline]
108pub fn aabb_overlaps_simd4(target: &Aabb, others: [&Aabb; 4]) -> u8 {
109    let mut mask = 0u8;
110    for (i, other) in others.iter().enumerate() {
111        if aabb_overlaps(target, other) {
112            mask |= 1 << i;
113        }
114    }
115    mask
116}
117
118/// Scalar AABB overlap testi
119#[inline]
120fn aabb_overlaps(a: &Aabb, b: &Aabb) -> bool {
121    a.min.x <= b.max.x
122        && b.min.x <= a.max.x
123        && a.min.y <= b.max.y
124        && b.min.y <= a.max.y
125        && a.min.z <= b.max.z
126        && b.min.z <= a.max.z
127}
128
129/// AABB surface area (SAH için)
130#[inline]
131fn surface_area(a: &Aabb) -> f32 {
132    let d = Vec3::new(a.max.x - a.min.x, a.max.y - a.min.y, a.max.z - a.min.z);
133    2.0 * (d.x * d.y + d.y * d.z + d.z * d.x)
134}
135
136/// AABB birleştirme
137#[inline]
138fn merge_aabb(a: &Aabb, b: &Aabb) -> Aabb {
139    Aabb {
140        min: Vec3::new(
141            a.min.x.min(b.min.x),
142            a.min.y.min(b.min.y),
143            a.min.z.min(b.min.z),
144        )
145        .into(),
146        max: Vec3::new(
147            a.max.x.max(b.max.x),
148            a.max.y.max(b.max.y),
149            a.max.z.max(b.max.z),
150        )
151        .into(),
152    }
153}
154
155/// AABB'i her yönde margin kadar büyüt
156#[inline]
157fn fatten(aabb: &Aabb, margin: f32) -> Aabb {
158    Aabb {
159        min: Vec3::new(
160            aabb.min.x - margin,
161            aabb.min.y - margin,
162            aabb.min.z - margin,
163        )
164        .into(),
165        max: Vec3::new(
166            aabb.max.x + margin,
167            aabb.max.y + margin,
168            aabb.max.z + margin,
169        )
170        .into(),
171    }
172}
173
174/// a, b'nin içinde mi? (her eksende)
175/// FIX-1: Vec3A cmpge/cmple yerine açık skalar karşılaştırma
176#[inline]
177fn aabb_contains(outer: &Aabb, inner: &Aabb) -> bool {
178    inner.min.x >= outer.min.x
179        && inner.min.y >= outer.min.y
180        && inner.min.z >= outer.min.z
181        && inner.max.x <= outer.max.x
182        && inner.max.y <= outer.max.y
183        && inner.max.z <= outer.max.z
184}
185
186// ─────────────────────────────────────────────────────────────────────────────
187// BVH Node
188// ─────────────────────────────────────────────────────────────────────────────
189
190const NULL: usize = usize::MAX;
191
192#[derive(Clone)]
193struct Node {
194    aabb: Aabb,
195    parent: usize,
196    left: usize,
197    right: usize,
198    entity: Option<Entity>, // Sadece yaprak node'larda dolu
199    height: i32,            // -1 = boş/serbest
200}
201
202impl Node {
203    #[inline]
204    fn is_leaf(&self) -> bool {
205        self.left == NULL
206    }
207}
208
209impl Default for Node {
210    fn default() -> Self {
211        Self {
212            aabb: Aabb {
213                min: Vec3::ZERO.into(),
214                max: Vec3::ZERO.into(),
215            },
216            parent: NULL,
217            left: NULL,
218            right: NULL,
219            entity: None,
220            height: -1,
221        }
222    }
223}
224
225// ─────────────────────────────────────────────────────────────────────────────
226// Dynamic AABB Tree
227// ─────────────────────────────────────────────────────────────────────────────
228
229pub struct DynamicAabbTree {
230    nodes: Vec<Node>,
231    root: usize,
232    free_list: usize,
233    entity_map: HashMap<u32, usize>,
234    tight_aabbs: HashMap<u32, Aabb>,
235    fat_margin: f32,
236}
237
238impl Default for DynamicAabbTree {
239    fn default() -> Self {
240        Self::new()
241    }
242}
243
244impl DynamicAabbTree {
245    pub fn new() -> Self {
246        Self {
247            nodes: Vec::with_capacity(256),
248            root: NULL,
249            free_list: NULL,
250            entity_map: HashMap::new(),
251            tight_aabbs: HashMap::new(),
252            fat_margin: 0.1,
253        }
254    }
255
256    pub fn with_fat_margin(mut self, margin: f32) -> Self {
257        self.fat_margin = margin;
258        self
259    }
260
261    pub fn clear(&mut self) {
262        self.nodes.clear();
263        self.root = NULL;
264        self.free_list = NULL;
265        self.entity_map.clear();
266        self.tight_aabbs.clear();
267    }
268
269    pub fn entity_count(&self) -> usize {
270        self.entity_map.len()
271    }
272
273    // ── Node havuzu ──────────────────────────────────────────────────────────
274
275    fn alloc_node(&mut self) -> usize {
276        if self.free_list != NULL {
277            let idx = self.free_list;
278            self.free_list = self.nodes[idx].parent; // free list zinciri parent üzerinden
279            self.nodes[idx] = Node::default();
280            idx
281        } else {
282            let idx = self.nodes.len();
283            self.nodes.push(Node::default());
284            idx
285        }
286    }
287
288    fn free_node(&mut self, idx: usize) {
289        // FIX-8: Tüm alanları temizle, sadece height ve entity değil
290        self.nodes[idx] = Node {
291            height: -1,
292            parent: self.free_list, // zincire ekle
293            ..Default::default()
294        };
295        self.free_list = idx;
296    }
297
298    // ── Ekleme / Güncelleme ──────────────────────────────────────────────────
299
300    pub fn insert(&mut self, entity: Entity, aabb: Aabb) {
301        // FIX-1: tight AABB hâlâ fat AABB içindeyse rebuild'den kaçın
302        // Skalar karşılaştırma — Vec3A cmpge/cmple trait sorununu önler
303        if let Some(&node_idx) = self.entity_map.get(&entity.id()) {
304            let fat = self.nodes[node_idx].aabb;
305            if aabb_contains(&fat, &aabb) {
306                self.tight_aabbs.insert(entity.id(), aabb);
307                return;
308            }
309            self.remove(entity);
310        }
311
312        self.tight_aabbs.insert(entity.id(), aabb);
313        let fat_aabb = fatten(&aabb, self.fat_margin);
314
315        let leaf = self.alloc_node();
316        self.nodes[leaf].aabb = fat_aabb;
317        self.nodes[leaf].entity = Some(entity);
318        self.nodes[leaf].height = 0;
319
320        self.insert_leaf(leaf);
321        self.entity_map.insert(entity.id(), leaf);
322    }
323
324    pub fn remove(&mut self, entity: Entity) {
325        if let Some(leaf) = self.entity_map.remove(&entity.id()) {
326            self.tight_aabbs.remove(&entity.id());
327            self.remove_leaf(leaf);
328            self.free_node(leaf);
329        }
330    }
331
332    // ── Yaprak Ekleme / Çıkarma ──────────────────────────────────────────────
333
334    fn insert_leaf(&mut self, leaf: usize) {
335        if self.root == NULL {
336            self.root = leaf;
337            self.nodes[leaf].parent = NULL;
338            return;
339        }
340
341        let leaf_aabb = self.nodes[leaf].aabb;
342        let sibling = self.find_best_sibling(&leaf_aabb);
343
344        let old_parent = self.nodes[sibling].parent;
345        let new_parent = self.alloc_node();
346
347        self.nodes[new_parent].parent = old_parent;
348        self.nodes[new_parent].aabb = merge_aabb(&leaf_aabb, &self.nodes[sibling].aabb);
349        self.nodes[new_parent].height = self.nodes[sibling].height + 1;
350        self.nodes[new_parent].left = sibling;
351        self.nodes[new_parent].right = leaf;
352
353        if old_parent != NULL {
354            if self.nodes[old_parent].left == sibling {
355                self.nodes[old_parent].left = new_parent;
356            } else {
357                self.nodes[old_parent].right = new_parent;
358            }
359        } else {
360            self.root = new_parent;
361        }
362
363        self.nodes[sibling].parent = new_parent;
364        self.nodes[leaf].parent = new_parent;
365
366        self.refit_ancestors(self.nodes[leaf].parent);
367    }
368
369    fn remove_leaf(&mut self, leaf: usize) {
370        if leaf == self.root {
371            self.root = NULL;
372            return;
373        }
374
375        let parent = self.nodes[leaf].parent;
376        let sibling = if self.nodes[parent].left == leaf {
377            self.nodes[parent].right
378        } else {
379            self.nodes[parent].left
380        };
381
382        let grand = self.nodes[parent].parent;
383
384        if grand != NULL {
385            if self.nodes[grand].left == parent {
386                self.nodes[grand].left = sibling;
387            } else {
388                self.nodes[grand].right = sibling;
389            }
390            self.nodes[sibling].parent = grand;
391            self.free_node(parent);
392            self.refit_ancestors(grand);
393        } else {
394            // parent root'tu
395            self.root = sibling;
396            self.nodes[sibling].parent = NULL;
397            self.free_node(parent);
398        }
399    }
400
401    /// Verilen node'dan kök'e kadar height + AABB güncelle, AVL dengele
402    fn refit_ancestors(&mut self, mut index: usize) {
403        while index != NULL {
404            let left = self.nodes[index].left;
405            let right = self.nodes[index].right;
406
407            self.nodes[index].height = 1 + self.nodes[left].height.max(self.nodes[right].height);
408            self.nodes[index].aabb = merge_aabb(&self.nodes[left].aabb, &self.nodes[right].aabb);
409
410            index = self.balance(index);
411            index = self.nodes[index].parent;
412        }
413    }
414
415    // ── SAH Sibling Seçimi ───────────────────────────────────────────────────
416
417    /// FIX-7: inherited_cost doğru hesaplanıyor.
418    /// Her node için:
419    ///   direct_cost    = SA(merge(leaf, node))
420    ///   inherited_cost = inherited cost from ancestors (delta SA propagated up)
421    fn find_best_sibling(&self, leaf_aabb: &Aabb) -> usize {
422        let mut best_cost = f32::INFINITY;
423        let mut best = self.root;
424
425        // Stack: (node_idx, inherited_cost)
426        let mut stack = Vec::with_capacity(32);
427        stack.push((self.root, 0.0f32));
428
429        while let Some((idx, inherited)) = stack.pop() {
430            if idx == NULL {
431                continue;
432            }
433
434            let node_sa = surface_area(&self.nodes[idx].aabb);
435            let merged_sa = surface_area(&merge_aabb(leaf_aabb, &self.nodes[idx].aabb));
436            let direct = merged_sa;
437            let total_cost = direct + inherited;
438
439            if total_cost < best_cost {
440                best_cost = total_cost;
441                best = idx;
442            }
443
444            if !self.nodes[idx].is_leaf() {
445                // FIX-7: child'ın inherited cost'u = parent'ın (merged_sa - node_sa) + inherited
446                // Bu, yaprağı bu node'un altına eklersek ancestor AABB'lerinin ne kadar büyüyeceğini gösterir
447                let child_inherited = (merged_sa - node_sa) + inherited;
448
449                // Lower bound: leaf_sa + child_inherited (node SA = 0 olsa bile en az bu kadar maliyet)
450                let lower_bound = surface_area(leaf_aabb) + child_inherited;
451                if lower_bound < best_cost {
452                    stack.push((self.nodes[idx].left, child_inherited));
453                    stack.push((self.nodes[idx].right, child_inherited));
454                }
455            }
456        }
457
458        best
459    }
460
461    // ── AVL Rotasyonu ────────────────────────────────────────────────────────
462
463    /// FIX-3: rotasyon sonrası taşınan child'ın parent pointer'ı güncelleniyor
464    fn balance(&mut self, a: usize) -> usize {
465        if self.nodes[a].is_leaf() || self.nodes[a].height < 2 {
466            return a;
467        }
468
469        let b = self.nodes[a].left;
470        let c = self.nodes[a].right;
471        let balance_factor = self.nodes[c].height - self.nodes[b].height;
472
473        // Sağ ağır → C'yi yükselt
474        if balance_factor > 1 {
475            return self.rotate_left(a, b, c);
476        }
477
478        // Sol ağır → B'yi yükselt
479        if balance_factor < -1 {
480            return self.rotate_right(a, b, c);
481        }
482
483        a
484    }
485
486    /// A'nın sağ çocuğu C'yi yukarı çek (left rotation)
487    fn rotate_left(&mut self, a: usize, b: usize, c: usize) -> usize {
488        let f = self.nodes[c].left;
489        let g = self.nodes[c].right;
490
491        // C → a'nın yerine geç
492        self.nodes[c].left = a;
493        self.nodes[c].parent = self.nodes[a].parent;
494        self.nodes[a].parent = c;
495
496        // C'nin eski parent'ını güncelle
497        let cp = self.nodes[c].parent;
498        if cp != NULL {
499            if self.nodes[cp].left == a {
500                self.nodes[cp].left = c;
501            } else {
502                self.nodes[cp].right = c;
503            }
504        } else {
505            self.root = c;
506        }
507
508        // F ve G'den hangisi daha yüksek?
509        if self.nodes[f].height > self.nodes[g].height {
510            // G → A'nın sağına, F → C'nin sağına
511            self.nodes[c].right = f;
512            self.nodes[a].right = g;
513            // FIX-3: g'nin parent pointer'ını güncelle
514            self.nodes[g].parent = a;
515            self.nodes[f].parent = c; // f zaten c'nin çocuğu kalıyor ama parent'ı güncelle
516
517            self.nodes[a].aabb = merge_aabb(&self.nodes[b].aabb, &self.nodes[g].aabb);
518            self.nodes[c].aabb = merge_aabb(&self.nodes[a].aabb, &self.nodes[f].aabb);
519            self.nodes[a].height = 1 + self.nodes[b].height.max(self.nodes[g].height);
520            self.nodes[c].height = 1 + self.nodes[a].height.max(self.nodes[f].height);
521        } else {
522            // F → A'nın sağına, G → C'nin sağına
523            self.nodes[c].right = g;
524            self.nodes[a].right = f;
525            // FIX-3: f'nin parent pointer'ını güncelle
526            self.nodes[f].parent = a;
527            self.nodes[g].parent = c;
528
529            self.nodes[a].aabb = merge_aabb(&self.nodes[b].aabb, &self.nodes[f].aabb);
530            self.nodes[c].aabb = merge_aabb(&self.nodes[a].aabb, &self.nodes[g].aabb);
531            self.nodes[a].height = 1 + self.nodes[b].height.max(self.nodes[f].height);
532            self.nodes[c].height = 1 + self.nodes[a].height.max(self.nodes[g].height);
533        }
534
535        c
536    }
537
538    /// A'nın sol çocuğu B'yi yukarı çek (right rotation)
539    fn rotate_right(&mut self, a: usize, b: usize, c: usize) -> usize {
540        let d = self.nodes[b].left;
541        let e = self.nodes[b].right;
542
543        // B → a'nın yerine geç
544        self.nodes[b].left = a;
545        self.nodes[b].parent = self.nodes[a].parent;
546        self.nodes[a].parent = b;
547
548        let bp = self.nodes[b].parent;
549        if bp != NULL {
550            if self.nodes[bp].left == a {
551                self.nodes[bp].left = b;
552            } else {
553                self.nodes[bp].right = b;
554            }
555        } else {
556            self.root = b;
557        }
558
559        if self.nodes[d].height > self.nodes[e].height {
560            // E → A'nın soluna, D → B'nin sağına
561            self.nodes[b].right = d;
562            self.nodes[a].left = e;
563            // FIX-3: parent pointer güncelle
564            self.nodes[e].parent = a;
565            self.nodes[d].parent = b;
566
567            self.nodes[a].aabb = merge_aabb(&self.nodes[c].aabb, &self.nodes[e].aabb);
568            self.nodes[b].aabb = merge_aabb(&self.nodes[a].aabb, &self.nodes[d].aabb);
569            self.nodes[a].height = 1 + self.nodes[c].height.max(self.nodes[e].height);
570            self.nodes[b].height = 1 + self.nodes[a].height.max(self.nodes[d].height);
571        } else {
572            // D → A'nın soluna, E → B'nin sağına
573            self.nodes[b].right = e;
574            self.nodes[a].left = d;
575            // FIX-3: parent pointer güncelle
576            self.nodes[d].parent = a;
577            self.nodes[e].parent = b;
578
579            self.nodes[a].aabb = merge_aabb(&self.nodes[c].aabb, &self.nodes[d].aabb);
580            self.nodes[b].aabb = merge_aabb(&self.nodes[a].aabb, &self.nodes[e].aabb);
581            self.nodes[a].height = 1 + self.nodes[c].height.max(self.nodes[d].height);
582            self.nodes[b].height = 1 + self.nodes[a].height.max(self.nodes[e].height);
583        }
584
585        b
586    }
587
588    // ── Sorgular ─────────────────────────────────────────────────────────────
589
590    /// Tüm olası çarpışma çiftlerini döndür.
591    /// FIX-2: Dual-tree descent ile garantili duplicate-free, self-pair yok.
592    /// Algoritma: her internal node için sol ve sağ alt ağaçları birbirine karşı test et.
593    pub fn query_pairs(&self) -> Vec<(Entity, Entity)> {
594        let mut pairs = Vec::new();
595        if self.root == NULL || self.nodes[self.root].is_leaf() {
596            return pairs;
597        }
598
599        // Stack: (node_a, node_b) — iki alt ağaç arasındaki olası çift
600        // Başlangıç: root'un sol ve sağ çocukları
601        let root_left = self.nodes[self.root].left;
602        let root_right = self.nodes[self.root].right;
603        let mut stack = Vec::with_capacity(128);
604        stack.push((root_left, root_right));
605
606        // Her internal node'un kendi içindeki çiftleri de ekle
607        // (self-descent): stack'e (left_child, right_child) olarak eklenir
608        // Bu işlem aşağıdaki döngüde zaten handle ediliyor.
609
610        while let Some((a, b)) = stack.pop() {
611            if a == NULL || b == NULL {
612                continue;
613            }
614
615            // AABB overlap yoksa bu dalı kes
616            if !aabb_overlaps(&self.nodes[a].aabb, &self.nodes[b].aabb) {
617                continue;
618            }
619
620            let a_leaf = self.nodes[a].is_leaf();
621            let b_leaf = self.nodes[b].is_leaf();
622
623            match (a_leaf, b_leaf) {
624                (true, true) => {
625                    // FIX-6: İleride SIMD batch için hazır; şimdi skalar
626                    if let (Some(ea), Some(eb)) = (self.nodes[a].entity, self.nodes[b].entity) {
627                        let pair = if ea.id() < eb.id() {
628                            (ea, eb)
629                        } else {
630                            (eb, ea)
631                        };
632                        pairs.push(pair);
633                    }
634                }
635                (true, false) => {
636                    // a yaprak, b internal → b'yi aç
637                    stack.push((a, self.nodes[b].left));
638                    stack.push((a, self.nodes[b].right));
639                }
640                (false, true) => {
641                    // b yaprak, a internal → a'yı aç
642                    stack.push((self.nodes[a].left, b));
643                    stack.push((self.nodes[a].right, b));
644                }
645                (false, false) => {
646                    // İkisi de internal: daha büyük SA'yı aç
647                    if surface_area(&self.nodes[a].aabb) >= surface_area(&self.nodes[b].aabb) {
648                        stack.push((self.nodes[a].left, b));
649                        stack.push((self.nodes[a].right, b));
650                    } else {
651                        stack.push((a, self.nodes[b].left));
652                        stack.push((a, self.nodes[b].right));
653                    }
654                }
655            }
656        }
657
658        // Her internal node'un kendi çocukları arasındaki çiftleri de tara
659        // (yukarıdaki descent yalnızca farklı alt ağaçlar arası çiftleri yakalar)
660        self.collect_internal_pairs(&mut pairs);
661
662        pairs
663    }
664
665    /// Her internal node'un sol ve sağ çocuklarını birbirine karşı test et
666    /// (aynı subtree içindeki çiftler için)
667    fn collect_internal_pairs(&self, pairs: &mut Vec<(Entity, Entity)>) {
668        if self.root == NULL {
669            return;
670        }
671        let mut stack = vec![self.root];
672        while let Some(idx) = stack.pop() {
673            if self.nodes[idx].is_leaf() {
674                continue;
675            }
676            let l = self.nodes[idx].left;
677            let r = self.nodes[idx].right;
678            // Sol ve sağ alt ağaçları birbirine karşı test et
679            self.descent_pair(l, r, pairs);
680            stack.push(l);
681            stack.push(r);
682        }
683    }
684
685    fn descent_pair(&self, a: usize, b: usize, pairs: &mut Vec<(Entity, Entity)>) {
686        if a == NULL || b == NULL {
687            return;
688        }
689        if !aabb_overlaps(&self.nodes[a].aabb, &self.nodes[b].aabb) {
690            return;
691        }
692
693        let a_leaf = self.nodes[a].is_leaf();
694        let b_leaf = self.nodes[b].is_leaf();
695
696        match (a_leaf, b_leaf) {
697            (true, true) => {
698                if let (Some(ea), Some(eb)) = (self.nodes[a].entity, self.nodes[b].entity) {
699                    let pair = if ea.id() < eb.id() {
700                        (ea, eb)
701                    } else {
702                        (eb, ea)
703                    };
704                    if !pairs.contains(&pair) {
705                        pairs.push(pair);
706                    }
707                }
708            }
709            (true, false) => {
710                self.descent_pair(a, self.nodes[b].left, pairs);
711                self.descent_pair(a, self.nodes[b].right, pairs);
712            }
713            (false, true) => {
714                self.descent_pair(self.nodes[a].left, b, pairs);
715                self.descent_pair(self.nodes[a].right, b, pairs);
716            }
717            (false, false) => {
718                if surface_area(&self.nodes[a].aabb) >= surface_area(&self.nodes[b].aabb) {
719                    self.descent_pair(self.nodes[a].left, b, pairs);
720                    self.descent_pair(self.nodes[a].right, b, pairs);
721                } else {
722                    self.descent_pair(a, self.nodes[b].left, pairs);
723                    self.descent_pair(a, self.nodes[b].right, pairs);
724                }
725            }
726        }
727    }
728
729    /// Verilen AABB ile örtüşen tüm entity'leri döndür
730    pub fn query_aabb(&self, aabb: &Aabb) -> Vec<Entity> {
731        let mut result = Vec::new();
732        if self.root == NULL {
733            return result;
734        }
735
736        let mut stack = vec![self.root];
737        while let Some(idx) = stack.pop() {
738            if !aabb_overlaps(&self.nodes[idx].aabb, aabb) {
739                continue;
740            }
741            if self.nodes[idx].is_leaf() {
742                if let Some(e) = self.nodes[idx].entity {
743                    result.push(e);
744                }
745            } else {
746                stack.push(self.nodes[idx].left);
747                stack.push(self.nodes[idx].right);
748            }
749        }
750
751        result
752    }
753
754    /// Ray ile kesişen entity'leri t değerine göre sıralı döndür
755    pub fn query_ray(&self, origin: Vec3, dir: Vec3, max_t: f32) -> Vec<(Entity, f32)> {
756        let mut result = Vec::new();
757        if self.root == NULL {
758            return result;
759        }
760
761        let inv_dir = Vec3::new(
762            if dir.x.abs() > 1e-8 {
763                1.0 / dir.x
764            } else {
765                f32::INFINITY
766            },
767            if dir.y.abs() > 1e-8 {
768                1.0 / dir.y
769            } else {
770                f32::INFINITY
771            },
772            if dir.z.abs() > 1e-8 {
773                1.0 / dir.z
774            } else {
775                f32::INFINITY
776            },
777        );
778
779        let mut stack = vec![self.root];
780        while let Some(idx) = stack.pop() {
781            if let Some(t) = ray_aabb_inv(origin, inv_dir, &self.nodes[idx].aabb, max_t) {
782                if self.nodes[idx].is_leaf() {
783                    if let Some(e) = self.nodes[idx].entity {
784                        result.push((e, t));
785                    }
786                } else {
787                    stack.push(self.nodes[idx].left);
788                    stack.push(self.nodes[idx].right);
789                }
790            }
791        }
792
793        result.sort_unstable_by(|a, b| a.1.partial_cmp(&b.1).unwrap_or(std::cmp::Ordering::Equal));
794        result
795    }
796
797    // ── Debug ────────────────────────────────────────────────────────────────
798
799    /// Ağaç geçerliliğini doğrula (test/debug için)
800    #[cfg(debug_assertions)]
801    pub fn validate(&self) {
802        if self.root != NULL {
803            self.validate_node(self.root, NULL);
804        }
805    }
806
807    #[cfg(debug_assertions)]
808    fn validate_node(&self, idx: usize, expected_parent: usize) {
809        let node = &self.nodes[idx];
810        assert_eq!(node.parent, expected_parent, "Node {} parent yanlış", idx);
811        assert!(node.height >= 0, "Aktif node height negatif: {}", idx);
812
813        if node.is_leaf() {
814            assert!(node.entity.is_some(), "Yaprak node entity yok: {}", idx);
815            assert_eq!(node.height, 0);
816        } else {
817            let l = node.left;
818            let r = node.right;
819            assert!(l != NULL && r != NULL, "Internal node çocuksuz: {}", idx);
820
821            let expected_height = 1 + self.nodes[l].height.max(self.nodes[r].height);
822            assert_eq!(node.height, expected_height, "Node {} height yanlış", idx);
823
824            self.validate_node(l, idx);
825            self.validate_node(r, idx);
826        }
827    }
828}
829
830// ─────────────────────────────────────────────────────────────────────────────
831// Ray-AABB kesişim (precomputed inv_dir ile)
832// ─────────────────────────────────────────────────────────────────────────────
833
834/// FIX-5: tmin f32::NEG_INFINITY'den başlar, negatif yönlü raylar doğru çalışır.
835/// inv_dir önceden hesaplanmış olmalı (sorgu başına bir kez).
836#[inline]
837fn ray_aabb_inv(origin: Vec3, inv_dir: Vec3, aabb: &Aabb, max_t: f32) -> Option<f32> {
838    let tx1 = (aabb.min.x - origin.x) * inv_dir.x;
839    let tx2 = (aabb.max.x - origin.x) * inv_dir.x;
840    let ty1 = (aabb.min.y - origin.y) * inv_dir.y;
841    let ty2 = (aabb.max.y - origin.y) * inv_dir.y;
842    let tz1 = (aabb.min.z - origin.z) * inv_dir.z;
843    let tz2 = (aabb.max.z - origin.z) * inv_dir.z;
844
845    // FIX-5: tmin NEG_INFINITY'den başlamalı (origin AABB içindeyse tmin negatif)
846    let tmin = tx1.min(tx2).max(ty1.min(ty2)).max(tz1.min(tz2));
847    let tmax = tx1.max(tx2).min(ty1.max(ty2)).min(tz1.max(tz2));
848
849    if tmax < 0.0 || tmin > tmax || tmin > max_t {
850        None
851    } else {
852        Some(tmin.max(0.0)) // ray başlangıcından itibaren t
853    }
854}
855
856// ─────────────────────────────────────────────────────────────────────────────
857// SpatialHash uyumluluk katmanı
858// ─────────────────────────────────────────────────────────────────────────────
859
860/// Eski SpatialHash API'sini Dynamic BVH üzerine köprüler.
861/// FIX-4: clear artık &mut self alıyor.
862pub struct SpatialHash {
863    tree: DynamicAabbTree,
864}
865
866impl Default for SpatialHash {
867    fn default() -> Self {
868        Self::new(10.0)
869    }
870}
871
872impl SpatialHash {
873    pub fn new(_cell_size: f32) -> Self {
874        Self {
875            tree: DynamicAabbTree::new(),
876        }
877    }
878
879    /// FIX-4: &self yerine &mut self
880    pub fn clear(&mut self) {
881        self.tree.clear();
882    }
883
884    pub fn insert(&mut self, entity: Entity, aabb: Aabb) {
885        self.tree.insert(entity, aabb);
886    }
887
888    pub fn update(&mut self, entity: Entity, aabb: Aabb) {
889        self.tree.insert(entity, aabb);
890    }
891
892    pub fn remove(&mut self, entity: Entity) {
893        self.tree.remove(entity);
894    }
895
896    pub fn query_pairs(&self) -> Vec<(Entity, Entity)> {
897        self.tree.query_pairs()
898    }
899
900    pub fn query_aabb(&self, aabb: Aabb) -> Vec<Entity> {
901        self.tree.query_aabb(&aabb)
902    }
903
904    pub fn query_point(&self, point: Vec3, radius: f32) -> Vec<Entity> {
905        let aabb = Aabb {
906            min: Vec3::new(point.x - radius, point.y - radius, point.z - radius).into(),
907            max: Vec3::new(point.x + radius, point.y + radius, point.z + radius).into(),
908        };
909        self.tree.query_aabb(&aabb)
910    }
911
912    pub fn query_ray(&self, origin: Vec3, dir: Vec3, max_t: f32) -> Vec<(Entity, f32)> {
913        self.tree.query_ray(origin, dir, max_t)
914    }
915}
916
917// ─────────────────────────────────────────────────────────────────────────────
918// Testler
919// ─────────────────────────────────────────────────────────────────────────────
920
921#[cfg(test)]
922mod tests {
923    use super::*;
924
925    fn make_entity(id: u32) -> Entity {
926        Entity::new(id, 0)
927    }
928
929    fn make_aabb(cx: f32, cy: f32, cz: f32, r: f32) -> Aabb {
930        Aabb::from_center_half_extents(Vec3::new(cx, cy, cz), Vec3::splat(r))
931    }
932
933    #[test]
934    fn test_insert_query_pairs_basic() {
935        let mut tree = DynamicAabbTree::new();
936        let e1 = make_entity(1);
937        let e2 = make_entity(2);
938        let e3 = make_entity(3);
939
940        tree.insert(e1, make_aabb(0.0, 0.0, 0.0, 1.0));
941        tree.insert(e2, make_aabb(1.0, 0.0, 0.0, 1.0)); // e1 ile örtüşür
942        tree.insert(e3, make_aabb(100.0, 0.0, 0.0, 1.0)); // uzakta
943
944        let pairs = tree.query_pairs();
945
946        let has_12 = pairs
947            .iter()
948            .any(|&(a, b)| (a == e1 && b == e2) || (a == e2 && b == e1));
949        let has_13 = pairs
950            .iter()
951            .any(|&(a, b)| (a == e1 && b == e3) || (a == e3 && b == e1));
952
953        assert!(has_12, "e1-e2 çifti bulunamadı: {:?}", pairs);
954        assert!(!has_13, "e1-e3 yanlış çifti var: {:?}", pairs);
955    }
956
957    #[test]
958    fn test_no_self_pair() {
959        let mut tree = DynamicAabbTree::new();
960        tree.insert(make_entity(1), make_aabb(0.0, 0.0, 0.0, 1.0));
961        assert!(tree.query_pairs().is_empty(), "Self-pair üretilmemeli");
962    }
963
964    #[test]
965    fn test_no_duplicate_pairs() {
966        let mut tree = DynamicAabbTree::new();
967        for i in 0..8 {
968            tree.insert(make_entity(i), make_aabb(i as f32 * 0.5, 0.0, 0.0, 1.0));
969        }
970        let pairs = tree.query_pairs();
971        let mut seen = std::collections::HashSet::new();
972        for &(a, b) in &pairs {
973            let key = (a.id().min(b.id()), a.id().max(b.id()));
974            assert!(seen.insert(key), "Duplicate çift: ({}, {})", a.id(), b.id());
975        }
976    }
977
978    #[test]
979    fn test_remove() {
980        let mut tree = DynamicAabbTree::new();
981        let e1 = make_entity(1);
982        let e2 = make_entity(2);
983        tree.insert(e1, make_aabb(0.0, 0.0, 0.0, 1.0));
984        tree.insert(e2, make_aabb(0.5, 0.0, 0.0, 1.0));
985        tree.remove(e1);
986        assert!(
987            tree.query_pairs().is_empty(),
988            "Silinen entity hâlâ çift üretiyor"
989        );
990        assert_eq!(tree.entity_count(), 1);
991    }
992
993    #[test]
994    fn test_fat_aabb_no_rebuild() {
995        let mut tree = DynamicAabbTree::new();
996        let e = make_entity(1);
997        tree.insert(e, make_aabb(0.0, 0.0, 0.0, 1.0));
998        let initial_node = tree.entity_map[&e.id()];
999        // Fat margin = 0.1, küçük hareket yeniden ekleme gerektirmemeli
1000        tree.insert(e, make_aabb(0.05, 0.0, 0.0, 1.0));
1001        let after_node = tree.entity_map[&e.id()];
1002        assert_eq!(initial_node, after_node, "Küçük harekette node değişmemeli");
1003    }
1004
1005    #[test]
1006    fn test_query_aabb() {
1007        let mut tree = DynamicAabbTree::new();
1008        let e1 = make_entity(1);
1009        let e2 = make_entity(2);
1010        tree.insert(e1, make_aabb(0.0, 0.0, 0.0, 1.0));
1011        tree.insert(e2, make_aabb(10.0, 0.0, 0.0, 1.0));
1012
1013        let query = make_aabb(0.5, 0.0, 0.0, 0.5);
1014        let result = tree.query_aabb(&query);
1015        assert!(result.contains(&e1), "e1 sorgu sonucunda olmalı");
1016        assert!(!result.contains(&e2), "e2 sorgu sonucunda olmamalı");
1017    }
1018
1019    #[test]
1020    fn test_query_ray() {
1021        let mut tree = DynamicAabbTree::new();
1022        let e1 = make_entity(1);
1023        let e2 = make_entity(2);
1024        tree.insert(e1, make_aabb(5.0, 0.0, 0.0, 1.0));
1025        tree.insert(e2, make_aabb(0.0, 10.0, 0.0, 1.0)); // Ray'in yolunda değil
1026
1027        let hits = tree.query_ray(Vec3::ZERO, Vec3::new(1.0, 0.0, 0.0), 100.0);
1028        assert!(hits.iter().any(|(e, _)| *e == e1), "Ray e1'e isabet etmeli");
1029        assert!(
1030            !hits.iter().any(|(e, _)| *e == e2),
1031            "Ray e2'ye isabet etmemeli"
1032        );
1033
1034        // t değerleri sıralı mı?
1035        for i in 1..hits.len() {
1036            assert!(
1037                hits[i].1 >= hits[i - 1].1,
1038                "Ray sonuçları t'ye göre sıralı olmalı"
1039            );
1040        }
1041    }
1042
1043    #[test]
1044    fn test_ray_origin_inside_aabb() {
1045        // FIX-5 testi: origin AABB içindeyken de çalışmalı
1046        let mut tree = DynamicAabbTree::new();
1047        let e = make_entity(1);
1048        tree.insert(e, make_aabb(0.0, 0.0, 0.0, 5.0));
1049        let hits = tree.query_ray(Vec3::ZERO, Vec3::new(1.0, 0.0, 0.0), 100.0);
1050        assert!(!hits.is_empty(), "Origin AABB içindeyken ray isabet etmeli");
1051    }
1052
1053    #[test]
1054    fn test_spatial_hash_compat() {
1055        let mut sh = SpatialHash::new(10.0);
1056        let e1 = make_entity(1);
1057        let e2 = make_entity(2);
1058        sh.insert(e1, make_aabb(0.0, 0.0, 0.0, 1.0));
1059        sh.insert(e2, make_aabb(1.0, 0.0, 0.0, 1.0));
1060        sh.clear(); // FIX-4: &mut self
1061        assert_eq!(sh.query_pairs().len(), 0);
1062    }
1063
1064    #[test]
1065    fn test_many_entities_no_crash() {
1066        let mut tree = DynamicAabbTree::new();
1067        for i in 0..100 {
1068            tree.insert(make_entity(i), make_aabb((i as f32) * 0.3, 0.0, 0.0, 0.5));
1069        }
1070        let pairs = tree.query_pairs();
1071        // Sadece kilitlenme/panic olmadığını ve mantıklı çıktı üretildiğini doğrula
1072        assert!(!pairs.is_empty(), "Yakın nesneler çift üretmeli");
1073    }
1074
1075    #[cfg(debug_assertions)]
1076    #[test]
1077    fn test_validate_after_operations() {
1078        let mut tree = DynamicAabbTree::new();
1079        for i in 0..20 {
1080            tree.insert(make_entity(i), make_aabb(i as f32, 0.0, 0.0, 0.6));
1081        }
1082        tree.validate();
1083        tree.remove(make_entity(5));
1084        tree.remove(make_entity(10));
1085        tree.validate();
1086    }
1087}