// language: metal2.4
#include <metal_stdlib>
#include <simd/simd.h>

using metal::uint;
struct _RayQuery {
    metal::raytracing::intersector<metal::raytracing::instancing, metal::raytracing::triangle_data, metal::raytracing::world_space_data> intersector;
    metal::raytracing::intersector<metal::raytracing::instancing, metal::raytracing::triangle_data, metal::raytracing::world_space_data>::result_type intersection;
    bool ready = false;
};
constexpr metal::uint _map_intersection_type(const metal::raytracing::intersection_type ty) {
    return ty==metal::raytracing::intersection_type::triangle ? 1 : 
        ty==metal::raytracing::intersection_type::bounding_box ? 4 : 0;
}

struct RayIntersection {
    uint kind;
    float t;
    uint instance_custom_index;
    uint instance_id;
    uint sbt_record_offset;
    uint geometry_index;
    uint primitive_index;
    metal::float2 barycentrics;
    bool front_face;
    char _pad9[11];
    metal::float4x3 object_to_world;
    metal::float4x3 world_to_object;
};
struct RayDesc {
    uint flags;
    uint cull_mask;
    float tmin;
    float tmax;
    metal::float3 origin;
    metal::float3 dir;
};
struct Output {
    uint visible;
    char _pad1[12];
    metal::float3 normal;
};

RayIntersection query_loop(
    metal::float3 pos,
    metal::float3 dir,
    metal::raytracing::instance_acceleration_structure acs
) {
    _RayQuery rq_1 = {};
    RayDesc _e8 = RayDesc {4u, 255u, 0.1, 100.0, pos, dir};
    rq_1.intersector.assume_geometry_type(metal::raytracing::geometry_type::triangle);
    rq_1.intersector.set_opacity_cull_mode((_e8.flags & 64) != 0 ? metal::raytracing::opacity_cull_mode::opaque : (_e8.flags & 128) != 0 ? metal::raytracing::opacity_cull_mode::non_opaque : metal::raytracing::opacity_cull_mode::none);
    rq_1.intersector.force_opacity((_e8.flags & 1) != 0 ? metal::raytracing::forced_opacity::opaque : (_e8.flags & 2) != 0 ? metal::raytracing::forced_opacity::non_opaque : metal::raytracing::forced_opacity::none);
    rq_1.intersector.accept_any_intersection((_e8.flags & 4) != 0);
    rq_1.intersection = rq_1.intersector.intersect(metal::raytracing::ray(_e8.origin, _e8.dir, _e8.tmin, _e8.tmax), acs, _e8.cull_mask);    rq_1.ready = true;
    while(true) {
        bool _e9 = rq_1.ready;
        rq_1.ready = false;
        if (_e9) {
        } else {
            break;
        }
#define LOOP_IS_BOUNDED { volatile bool unpredictable_break_from_loop = false; if (unpredictable_break_from_loop) break; }
        LOOP_IS_BOUNDED
    }
    return RayIntersection {_map_intersection_type(rq_1.intersection.type), rq_1.intersection.distance, rq_1.intersection.user_instance_id, rq_1.intersection.instance_id, {}, rq_1.intersection.geometry_id, rq_1.intersection.primitive_id, rq_1.intersection.triangle_barycentric_coord, rq_1.intersection.triangle_front_facing, {}, rq_1.intersection.object_to_world_transform, rq_1.intersection.world_to_object_transform};
}

metal::float3 get_torus_normal(
    metal::float3 world_point,
    RayIntersection intersection
) {
    metal::float3 local_point = intersection.world_to_object * metal::float4(world_point, 1.0);
    metal::float2 point_on_guiding_line = metal::normalize(local_point.xy) * 2.4;
    metal::float3 world_point_on_guiding_line = intersection.object_to_world * metal::float4(point_on_guiding_line, 0.0, 1.0);
    return metal::normalize(world_point - world_point_on_guiding_line);
}

kernel void main_(
  metal::raytracing::instance_acceleration_structure acc_struct [[user(fake0)]]
, device Output& output [[user(fake0)]]
) {
    metal::float3 pos_1 = metal::float3(0.0);
    metal::float3 dir_1 = metal::float3(0.0, 1.0, 0.0);
    RayIntersection _e7 = query_loop(pos_1, dir_1, acc_struct);
    output.visible = static_cast<uint>(_e7.kind == 0u);
    metal::float3 _e18 = get_torus_normal(dir_1 * _e7.t, _e7);
    output.normal = _e18;
    return;
}


kernel void main_candidate(
  metal::raytracing::instance_acceleration_structure acc_struct [[user(fake0)]]
, device Output& output [[user(fake0)]]
) {
    _RayQuery rq = {};
    metal::float3 pos_2 = metal::float3(0.0);
    metal::float3 dir_2 = metal::float3(0.0, 1.0, 0.0);
    RayDesc _e12 = RayDesc {4u, 255u, 0.1, 100.0, pos_2, dir_2};
    rq.intersector.assume_geometry_type(metal::raytracing::geometry_type::triangle);
    rq.intersector.set_opacity_cull_mode((_e12.flags & 64) != 0 ? metal::raytracing::opacity_cull_mode::opaque : (_e12.flags & 128) != 0 ? metal::raytracing::opacity_cull_mode::non_opaque : metal::raytracing::opacity_cull_mode::none);
    rq.intersector.force_opacity((_e12.flags & 1) != 0 ? metal::raytracing::forced_opacity::opaque : (_e12.flags & 2) != 0 ? metal::raytracing::forced_opacity::non_opaque : metal::raytracing::forced_opacity::none);
    rq.intersector.accept_any_intersection((_e12.flags & 4) != 0);
    rq.intersection = rq.intersector.intersect(metal::raytracing::ray(_e12.origin, _e12.dir, _e12.tmin, _e12.tmax), acc_struct, _e12.cull_mask);    rq.ready = true;
    RayIntersection intersection_1 = RayIntersection {_map_intersection_type(rq.intersection.type), rq.intersection.distance, rq.intersection.user_instance_id, rq.intersection.instance_id, {}, rq.intersection.geometry_id, rq.intersection.primitive_id, rq.intersection.triangle_barycentric_coord, rq.intersection.triangle_front_facing, {}, rq.intersection.object_to_world_transform, rq.intersection.world_to_object_transform};
    output.visible = static_cast<uint>(intersection_1.kind == 3u);
    return;
}
