/* SPDX-FileCopyrightText: 2023 Blender Authors
 *
 * SPDX-License-Identifier: GPL-2.0-or-later */

#pragma once

#ifndef SELECT_ENABLE
/* Avoid requesting the select_id when not in selection mode. */
#  define select_id_set(select_id)
#  define select_id_output(select_id)

#elif defined(GPU_VERTEX_SHADER)

void select_id_set(uint id)
{
  /* Declared in the create info. */
  select_id = id;
}

#elif defined(GPU_FRAGMENT_SHADER)

void select_id_output(uint id)
{
  if (id == uint(-1)) {
    /* Invalid index */
    return;
  }

  if (select_info_buf.mode == SELECT_ALL) {
    /* Set the bit of the select id in the bitmap. */
    atomicOr(out_select_buf[id / 32u], 1u << (id % 32u));
  }
  else if (select_info_buf.mode == SELECT_PICK_ALL) {
    /* Stores the nearest depth for this select id. */
    atomicMin(out_select_buf[id], floatBitsToUint(gl_FragCoord.z));
  }
  else if (select_info_buf.mode == SELECT_PICK_NEAREST) {
    /* Stores the nearest depth with the distance to the cursor. */

    /* Distance function to the cursor. Currently a simple pixel ring distance. */
    int2 coord = abs(int2(gl_FragCoord.xy) - select_info_buf.cursor);
    uint dist = uint(max(coord.x, coord.y));

    uint depth = uint(gl_FragCoord.z * float(0x00FFFFFFu));

    /* Reject hits outside of valid range. */
    if (dist < 0xFFu) {
      /* Packed values to ensure the atomicMin is performed on the whole result. */
      atomicMin(out_select_buf[id], (depth << 8u) | dist);
    }
  }
}

#endif
