// This shader is used with a cloned GPUParticles3D system that is rendered in an offscreen SubViewport 
// (sized 8×2 pixels) on a dedicated layer (e.g. layer 20). Its purpose is to check each particle’s full 3D 
// world-space position against up to eight static target areas. Each target area is defined by a center (vec3), 
// extents (vec3, representing half-sizes), and a precomputed inverse basis (mat3) that converts world space into 
// the target’s local space. If a particle is within a target, the shader maps its geometry to a quad occupying the 
// horizontal slice corresponding to that target (i.e. one pixel column in the 8×1 output). The fragment outputs red 
// with a configurable alpha value. With additive blending, the red intensity in each slice roughly indicates the number 
// of particles hitting that target.
// 
// Targets with zero extents are considered disabled.

shader_type spatial;
render_mode unshaded, depth_draw_never, cull_disabled, blend_add;

const int MAX_TARGETS = 8;

uniform vec3 target_center[MAX_TARGETS];       // 3D centers for each target.
uniform vec3 target_extents[MAX_TARGETS];        // 3D half-sizes for each target.
uniform mat3 target_inv_basis[MAX_TARGETS];      // Precomputed inverse bases (inverts the target's rotation).

void vertex() {
    // Compute the particle's 3D world-space center (assumes local origin is the center).
    vec3 world_pos = (MODEL_MATRIX * vec4(0.0, 0.0, 0.0, 1.0)).xyz;
    
    int hit_target = -1;
    // Loop through targets.
    for (int i = 0; i < MAX_TARGETS; i++) {
        // Skip disabled targets.
        if (target_extents[i] == vec3(0.0))
            continue;
        // Transform the world position into the target's local space.
        vec3 local_pos = target_inv_basis[i] * (world_pos - target_center[i]);
        // Check if within the target's extents on all three axes.
        if (abs(local_pos.x) <= target_extents[i].x &&
            abs(local_pos.y) <= target_extents[i].y &&
            abs(local_pos.z) <= target_extents[i].z) {
            hit_target = i;
            break;
        }
    }
    
    if (hit_target == -1) {
        // Particle is not inside any target: send its geometry offscreen.
        POSITION = vec4(2.0, 2.0, 2.0, 1.0);
    } else {
        // Map the target index to a horizontal slice of clip space.
        float slice_width = 2.0 / float(MAX_TARGETS);
        float x_min = -1.0 + slice_width * float(hit_target);
        float x_max = x_min + slice_width;
        // Output a quad covering the full vertical range.
        if (VERTEX_ID == 0) {
            POSITION = vec4(x_min, -1.0, 0.0, 1.0);
        } else if (VERTEX_ID == 1) {
            POSITION = vec4(x_max, -1.0, 0.0, 1.0);
        } else if (VERTEX_ID == 2) {
            POSITION = vec4(x_min, 1.0, 0.0, 1.0);
        } else {
            POSITION = vec4(x_max, 1.0, 0.0, 1.0);
        }
    }
}

void fragment() {
    ALBEDO = vec3(1.0, 0.0, 0.0);
    ALPHA = 0.01f;
}
