phys-collision 2.0.1-beta.0

Provides collision detection ability
// Copyright (C) 2020-2025 phys-collision authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use glam_det::nums::{f32x4, Num};
use glam_det::{UnitQuatx4, Vec3x4};
use test::Bencher;

use crate::collision_tasks::tests::common::{ConvexHullInput, TestInput};
use crate::convex_contact_manifold::Convex4ContactManifoldWide;
use crate::traits::{BaseShapeWide, ContactManifoldWide, CreateShapeWide};
use crate::{ConvexContactManifold, ConvexHull, ConvexHullId, ShapeContainer};

macro_rules! impl_bench {
    ($Type:ident,$TypeA:ident,$TypeB:ident,$ManifoldType:ident,$N:expr) => {
        impl BenchShapePairTest for $Type {
            type ShapeAWide = $TypeA;
            type ShapeBWide = $TypeB;

            const N: usize = $N;

            #[inline]
            fn test_wide(
                shape_a: &Self::ShapeAWide,
                shape_b: &Self::ShapeBWide,
                speculative_margin: f32x4,
                offset_b: Vec3x4,
                orientation_a: UnitQuatx4,
                orientation_b: UnitQuatx4,
                container: Option<&ShapeContainer>,
                manifold: &mut Convex4ContactManifoldWide,
            ) {
                let contact_context = crate::traits::ContactContext {
                    orientation_a: &orientation_a,
                    orientation_b: &orientation_b,
                    offset_b: &offset_b,
                    speculative_margin,
                    pair_count: 4,
                    complex_shape_container: container,
                };
                ShapeWideTester::test(shape_a, shape_b, &contact_context, manifold)
            }
        }
    };
}

macro_rules! bench {

    ($InputType:ident,$Type:ident,$path_root:tt,$( <$id:tt,$name:tt>),*) => {
        bench!($InputType,$InputType, $Type,$path_root,$( <$id,$name>),*);
    };

     ($InputType:ident,$BenchType:ident, $Type:ident,$path_root:tt,$( <$id:tt,$name:tt>),*) => {
$(
    paste!{
                #[bench]
                pub fn [<id_ $id _ $name _with_transfer_wide_info>](b: &mut Bencher) {

                        let input_with_container:WithContainer<$BenchType> = {
                            let slice = include_bytes!(concat!("../tests/resource/",$path_root,stringify!($name),".json"));
                            let input: $InputType = serde_json::from_slice(slice).expect("file should be proper JSON");
                            input.into()
                        };
                        $Type::bench_shape_pair_with_transfer_wide_test(b,&input_with_container.0,&input_with_container.1);
                }

                #[bench]
                pub fn [<id_ $id _ $name>](b: &mut Bencher) {

                        let input_with_container:WithContainer<$BenchType> = {
                            let slice = include_bytes!(concat!("../tests/resource/",$path_root,stringify!($name),".json"));
                            let input: $InputType = serde_json::from_slice(slice).expect("file should be proper JSON");
                            input.into()
                        };
                        $Type::bench_shape_pair_test(b,&input_with_container.0,&input_with_container.1);
                }
    }
)*
    };
}

pub(super) struct WithContainer<T>(pub T, pub Option<ShapeContainer>);

impl<ShapeA, ShapeB> From<TestInput<ShapeA, ShapeB>> for WithContainer<TestInput<ShapeA, ShapeB>> {
    fn from(input: TestInput<ShapeA, ShapeB>) -> Self {
        Self(input, None)
    }
}

impl<ShapeA> From<TestInput<ShapeA, ConvexHullInput>>
    for WithContainer<TestInput<ShapeA, ConvexHullId>>
{
    fn from(input: TestInput<ShapeA, ConvexHullInput>) -> Self {
        let mut container = ShapeContainer::default();
        let convex_hull = ConvexHull::new_unchecked(&input.b.vertices);
        let convex_hull_id = container.add(convex_hull);
        assert!(container.get::<ConvexHull>(convex_hull_id).is_some());
        Self(
            TestInput {
                a: input.a,
                b: convex_hull_id,
                speculative_margin: input.speculative_margin,
                offset_b: input.offset_b,
                orientation_a: input.orientation_a,
                orientation_b: input.orientation_b,
            },
            Some(container),
        )
    }
}

impl<ShapeB> From<TestInput<ConvexHullInput, ShapeB>>
    for WithContainer<TestInput<ConvexHullId, ShapeB>>
{
    fn from(input: TestInput<ConvexHullInput, ShapeB>) -> Self {
        let mut container = ShapeContainer::default();
        let convex_hull = ConvexHull::new_unchecked(&input.a.vertices);
        let convex_hull_id = container.add(convex_hull);
        assert!(container.get::<ConvexHull>(convex_hull_id).is_some());
        Self(
            TestInput {
                a: convex_hull_id,
                b: input.b,
                speculative_margin: input.speculative_margin,
                offset_b: input.offset_b,
                orientation_a: input.orientation_a,
                orientation_b: input.orientation_b,
            },
            Some(container),
        )
    }
}

impl From<TestInput<ConvexHullInput, ConvexHullInput>>
    for WithContainer<TestInput<ConvexHullId, ConvexHullId>>
{
    fn from(input: TestInput<ConvexHullInput, ConvexHullInput>) -> Self {
        let mut container = ShapeContainer::default();
        let a = {
            let convex_hull = ConvexHull::new_unchecked(&input.a.vertices);
            container.add(convex_hull)
        };
        let b = {
            let convex_hull = ConvexHull::new_unchecked(&input.b.vertices);
            container.add(convex_hull)
        };
        assert!(container.get::<ConvexHull>(a).is_some());
        assert!(container.get::<ConvexHull>(b).is_some());
        Self(
            TestInput {
                a,
                b,
                speculative_margin: input.speculative_margin,
                offset_b: input.offset_b,
                orientation_a: input.orientation_a,
                orientation_b: input.orientation_b,
            },
            Some(container),
        )
    }
}

pub(super) trait BenchShapePairTest {
    type ShapeAWide: BaseShapeWide + Default;
    type ShapeBWide: BaseShapeWide + Default;

    const N: usize;

    fn bench_shape_pair_with_transfer_wide_test(
        b: &mut Bencher,
        data: &TestInput<
            <Self::ShapeAWide as BaseShapeWide>::TShape,
            <Self::ShapeBWide as BaseShapeWide>::TShape,
        >,
        container: &Option<ShapeContainer>,
    ) where
        <Self as BenchShapePairTest>::ShapeAWide: CreateShapeWide<4>,
        <Self as BenchShapePairTest>::ShapeBWide: CreateShapeWide<4>,
    {
        let pair_count = 4_usize;
        b.iter(
            #[inline]
            || {
                let a = <Self::ShapeAWide as CreateShapeWide<4>>::create([data.a; 4].iter());
                let b = <Self::ShapeBWide as CreateShapeWide<4>>::create([data.b; 4].iter());
                let speculative_margin = f32x4::splat(data.speculative_margin);
                let offset_b = Vec3x4::splat_soa(data.offset_b);
                let orientation_a = UnitQuatx4::splat_soa(data.orientation_a);
                let orientation_b = UnitQuatx4::splat_soa(data.orientation_b);
                let mut manifold = Convex4ContactManifoldWide::default();
                Self::test_wide(
                    &a,
                    &b,
                    speculative_margin,
                    offset_b,
                    orientation_a,
                    orientation_b,
                    container.as_ref(),
                    &mut manifold,
                );
                let mut result = ConvexContactManifold::default();
                for i in 0..pair_count {
                    manifold.get_manifold(i, Self::N, &offset_b, &mut result);
                    test::black_box(&mut result);
                }
                test::black_box(result);
            },
        );
    }

    fn bench_shape_pair_test(
        bencher: &mut Bencher,
        data: &TestInput<
            <Self::ShapeAWide as BaseShapeWide>::TShape,
            <Self::ShapeBWide as BaseShapeWide>::TShape,
        >,
        container: &Option<ShapeContainer>,
    ) where
        <Self as BenchShapePairTest>::ShapeAWide: CreateShapeWide<4>,
        <Self as BenchShapePairTest>::ShapeBWide: CreateShapeWide<4>,
    {
        let a = <Self::ShapeAWide as CreateShapeWide<4>>::create([data.a; 4].iter());
        let b = <Self::ShapeBWide as CreateShapeWide<4>>::create([data.b; 4].iter());
        let speculative_margin = f32x4::splat(data.speculative_margin);
        let offset_b = Vec3x4::splat_soa(data.offset_b);
        let orientation_a = UnitQuatx4::splat_soa(data.orientation_a);
        let orientation_b = UnitQuatx4::splat_soa(data.orientation_b);
        let mut result = Convex4ContactManifoldWide::default();
        bencher.iter(
            #[inline]
            || {
                Self::test_wide(
                    &a,
                    &b,
                    speculative_margin,
                    offset_b,
                    orientation_a,
                    orientation_b,
                    container.as_ref(),
                    &mut result,
                );
            },
        );
        test::black_box(result);
    }

    #[allow(clippy::too_many_arguments)]
    fn test_wide(
        shape_a: &Self::ShapeAWide,
        shape_b: &Self::ShapeBWide,
        speculative_margin: f32x4,
        offset_b: Vec3x4,
        orientation_a: UnitQuatx4,
        orientation_b: UnitQuatx4,
        container: Option<&ShapeContainer>,
        manifold: &mut Convex4ContactManifoldWide,
    );
}