/*
Crafter®.Graphics
Copyright (C) 2026 Catcrafts®
catcrafts.net

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License version 3.0 as published by the Free Software Foundation;
*/

// Portable RT types & constants.
//
// Native: aliases the Vulkan struct so existing code that passes
// `RenderingElement3D::instance` directly into vkCmdBuildAccelerationStructuresKHR
// is a no-op layout-wise.
// DOM: provides a POD with the same byte layout + the same field names, so
// user code touching `instance.mask`, `instance.flags`, `instance.transform`
// etc. compiles unchanged.
//
// Flag constants are spelled out as Crafter::kRT* so portable user code can
// avoid referencing VK_* on the DOM target. The values match
// VkGeometryInstanceFlagBitsKHR / VkRayTracingShaderGroupTypeKHR so the
// constants compare-equal on Vulkan if the user wants to mix surfaces.

module;
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
#include "vulkan/vulkan.h"
#endif
export module Crafter.Graphics:RT;
import std;

export namespace Crafter {
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
    using RTTransformMatrix = VkTransformMatrixKHR;
    using RTInstance        = VkAccelerationStructureInstanceKHR;
#else
    // Mirrors VkTransformMatrixKHR: row-major affine 3x4.
    struct RTTransformMatrix {
        float matrix[3][4];
    };
    static_assert(sizeof(RTTransformMatrix) == 48);

    // Mirrors VkAccelerationStructureInstanceKHR byte-for-byte.
    // On WebGPU the `accelerationStructureReference` slot holds the BLAS
    // handle returned by MeshWebGPU::blasHandle (a u32 widened to u64).
    struct RTInstance {
        RTTransformMatrix transform;
        std::uint32_t instanceCustomIndex                    : 24;
        std::uint32_t mask                                   : 8;
        std::uint32_t instanceShaderBindingTableRecordOffset : 24;
        std::uint32_t flags                                  : 8;
        std::uint64_t accelerationStructureReference;
    };
    static_assert(sizeof(RTInstance) == 64);
#endif

    // VkGeometryInstanceFlagBitsKHR mirror. Values verbatim so equal on both.
    inline constexpr std::uint8_t kRTGeometryInstanceTriangleFacingCullDisable = 0x1;
    inline constexpr std::uint8_t kRTGeometryInstanceTriangleFlipFacing        = 0x2;
    inline constexpr std::uint8_t kRTGeometryInstanceForceOpaque               = 0x4;
    inline constexpr std::uint8_t kRTGeometryInstanceForceNoOpaque             = 0x8;

    // Hit-group identification. Matches VkRayTracingShaderGroupTypeKHR.
    //   General           — raygen / miss / callable
    //   TrianglesHitGroup — closest-hit/any-hit over triangle geometry
    //   ProceduralHitGroup — closest-hit/any-hit + an intersection shader
    //                        over AABB (VK_GEOMETRY_TYPE_AABBS_KHR) geometry
    enum class RTShaderGroupType : std::uint8_t {
        General            = 0,   // raygen / miss / callable
        TrianglesHitGroup  = 1,
        ProceduralHitGroup = 2,
    };

    // Cross-backend description of one entry in the shader-group array
    // passed to PipelineRT::Init. Mirrors the meaningful subset of
    // VkRayTracingShaderGroupCreateInfoKHR: per group, the type and the
    // indices (into the SBT's shader array) for general / closestHit /
    // anyHit / intersection, with kRTShaderUnused == VK_SHADER_UNUSED_KHR
    // for "none". `intersectionShader` is only consulted for
    // ProceduralHitGroup; it names the shader run for each AABB the ray
    // enters (the analog of VkRayTracingShaderGroupCreateInfoKHR::
    // intersectionShader).
    inline constexpr std::uint32_t kRTShaderUnused = 0xFFFFFFFFu;

    struct RTShaderGroup {
        RTShaderGroupType type               = RTShaderGroupType::General;
        std::uint32_t      generalShader      = kRTShaderUnused;
        std::uint32_t      closestHitShader   = kRTShaderUnused;
        std::uint32_t      anyHitShader       = kRTShaderUnused;
        std::uint32_t      intersectionShader = kRTShaderUnused;
    };
}
