#version 430 core
////////////////////////////////////////////////////////////////////////////////
// <copyright>
// Copyright (c) 2015 Hue AS. All rights reserved.
//
// All rights are reserved. Reproduction or transmission in whole or in part, in
// any form or by any means, electronic, mechanical or otherwise, is prohibited
// without the prior written permission of the copyright owner.
// </copyright>
////////////////////////////////////////////////////////////////////////////////

#define F $REDUCE_FACTOR$

layout(binding=0) uniform usampler2D counts;
layout(binding=1) uniform usampler2D offsets;
layout(binding=2) uniform sampler2D colors;
layout(binding=3) uniform sampler2D depths;

uniform uint pitch;
uniform uint alignment;

layout(pixel_center_integer) in vec4 gl_FragCoord;
layout(location = 0) out vec4 color;

ivec2 indexToPos(uint index)
{
  return ivec2(index % (pitch / F), index / (pitch / F)) * F + ivec2(gl_FragCoord.xy) % F;
}

void main()
{
  uint count = texelFetch(counts, ivec2(gl_FragCoord.xy), 0).x;
  if (count == 0u) discard;

  uint offset = texelFetch(offsets, ivec2(gl_FragCoord.xy), 0).x - alignment - count;

  float previousDepth = -1.0e30;
  uint previousIndex = uint(-1);

  color = vec4(0.0);
  gl_FragDepth = 1.0;
  for (uint i = 0u; i < count && color.w < 0.9961; ++i)
  {
    float bestDepth = 1.0e30;
    uint bestIndex = uint(-1);

    for (uint j = 0u; j < count; ++j)
    {
      ivec2 imgPos = indexToPos(offset + j);

      float depth = texelFetch(depths, imgPos, 0).x;
      if (depth < bestDepth && (depth > previousDepth || (depth == previousDepth && j > previousIndex)))
      {
        bestDepth = depth;
        bestIndex = j;
      }
    }

    if (i == 0u) gl_FragDepth = bestDepth;

    ivec2 imgPos = indexToPos(offset + bestIndex);
    color += texelFetch(colors, imgPos, 0) * (1 - color.w);

    previousDepth = bestDepth;
    previousIndex = bestIndex;
  }
}
