
#if (VOXEL_TYPE == VOXEL_TYPE_FLOAT)

layout(binding=0)
  uniform sampler3D samplerData;

#else

layout(binding=0)
  uniform isampler3D isamplerData;

#endif


#ifdef VIRTUAL_TEXTURE_FORMAT

#else
#error Voxel format not defined.
#endif

#ifdef VOXEL_TYPE

#else
#eror Voxel type not defined
#endif



#if (VOXEL_TYPE == VOXEL_TYPE_INTEGER)

/////////////////////////////////////////////////////////////////////////////
// GetVoxelInteger
//

int
GetVoxelInteger(int x, int y, int z, out bool isNoValue)
{
  ivec3
    samplePosition = ivec3 (x, y, z);

  ivec4
    sampleValue = texelFetch(isamplerData, samplePosition, 0);

  int
    red = sampleValue.x;

#ifdef USE_VOLUME_NO_VALUE
  if (red == nIntegerNoValue)
  {
    isNoValue = true;
  }
  else
  {
    isNoValue = false;
  }
#else
  isNoValue = false;
#endif

  return red;
}

#endif

#if (VOXEL_TYPE == VOXEL_TYPE_FLOAT)

/////////////////////////////////////////////////////////////////////////////
// GetVoxelFloatU8U16R32
//
//
// U8, U16, R32

float
GetVoxelFloatU8U16R32(int x, int y, int z, out bool isNoValue)
{
  ivec3
    samplePosition = ivec3 (x, y, z);

  vec4
    sampleValue = texelFetch(samplerData, samplePosition, 0);

#ifdef USE_VOLUME_NO_VALUE

  float
    red;

  if (sampleValue.x == rComparisonNoValue)
  {
    isNoValue = true;
    red = rReplacementNoValue;
  }
  else
  {
    isNoValue = false;
    red = sampleValue.x * rVoxelScale + rVoxelOffset;
  }
#else

  float
    red = sampleValue.x * rVoxelScale + rVoxelOffset;

  isNoValue = false;

#endif

  return red;
}

#endif

#if (VOXEL_TYPE == VOXEL_TYPE_FLOAT)

/////////////////////////////////////////////////////////////////////////////
// GetVoxelFloat1Bit
//

float
GetVoxelFloat1Bit(int x, int y, int z, out bool isNoValue)
{
  ivec3
    samplePosition = ivec3 (x / 8, y, z);

  uint
    sampleBit = uint( x % 8);

  vec4
    samplerValue = texelFetch(samplerData, samplePosition, 0);

  float
    rValue = samplerValue.x;

  uint
    uRedByte = uint (rValue * 255.f);

  uint
    uRedBit =  (uRedByte >> sampleBit) & 1u;

  float
    red = (uRedBit != 0) ? 1.f : 0.f;

  isNoValue = false;

  return red;
}

#endif

/////////////////////////////////////////////////////////////////////////////
// GetVoxel
//

#if (VOXEL_TYPE == VOXEL_TYPE_FLOAT)

float
GetVoxelFloat(int x, int y, int z, out bool isNoValue)
{
#if VIRTUAL_TEXTURE_FORMAT == VIRTUAL_TEXTURE_FORMAT_1BIT
  return GetVoxelFloat1Bit(x, y, z, isNoValue);
#else
  return GetVoxelFloatU8U16R32(x, y, z, isNoValue);
#endif
}

#endif

#if (VOXEL_TYPE == VOXEL_TYPE_FLOAT)
/////////////////////////////////////////////////////////////////////////////
// GetRedMinMaxFloat
//

vec2
GetRedMinMaxFloat(ivec3 iMin, ivec3 iMax, out bool isNoValue)
{
  float
    rLow = FLT_MAX,
    rHigh = -FLT_MAX;

  isNoValue = false;

  for (int z_in = iMin.z; z_in < iMax.z; z_in++)
  {
    for (int y_in = iMin.y; y_in < iMax.y; y_in++)
    {
      for (int x_in = iMin.x; x_in < iMax.x ; x_in++)
      {
        bool
          isNoValueVoxel;
        
        float
          red = GetVoxelFloat(x_in, y_in, z_in, isNoValueVoxel);

        isNoValue = isNoValue || isNoValueVoxel;

        rHigh = max(rHigh, red);
        rLow  = min(rLow , red);
      }
    }
  }
  return vec2 (rLow, rHigh);
}
#endif
