

// Input LOD 0
layout(binding = 0, rgba16ui)
  uniform readonly uimage3D inputLOD0;

// Output LOD 2
layout(binding = 2, rgba16ui)
  uniform writeonly uimage3D inputLOD2;

layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in;


// temporary storage for each lod 2 bit.

shared bool bit_local [4*4*4];


/////////////////////////////////////////////////////////////////////////////
// main
//

void main()
{
  uint
    uSpaceLeapingTileSizeLOD2 = uSpaceLeapingTileSize / 4u;

  uint
    uID = gl_WorkGroupID.x;

  uint
    uCube = gl_WorkGroupID.y;

  uint
    uXOut =  uID % uSpaceLeapingTileSizeLOD2,
	uYOut = (uID /uSpaceLeapingTileSizeLOD2) % uSpaceLeapingTileSizeLOD2,
	uZOut = (uID /uSpaceLeapingTileSizeLOD2/ uSpaceLeapingTileSizeLOD2  ) %uSpaceLeapingTileSizeLOD2;

  uvec3
     cubeOutOffset = uvec3 (uXOut, uYOut, uZOut);

  uvec3
    cubeInOffset = 4u * cubeOutOffset;

  /*
    Following bit packing magic detailed and also run in HueVirtualTextureSpaceLeaping.cpp.
  */

  uint
    u2;

  if (uCube % 2 == 0)
  {
    u2 = coordinateSetValue[uCube/2].y;
  }
  else
  {
    u2 = coordinateSetValue[uCube/2].w;
  }

  uvec3
    uvecOutMin = uvec3 ( (u2 >> 0u) & (( 1u << 10u) -1u), (u2 >> 10u)  & (( 1u << 10u) -1u), (u2 >> 20u)  & (( 1u << 10u) -1u) );

  ivec3
    outPosition = ivec3 (uSpaceLeapingTileSize * uvecOutMin/4 + cubeOutOffset);

  uvec3
    inPositionThread = uSpaceLeapingTileSize * uvecOutMin + cubeInOffset + gl_LocalInvocationID;

  uint
    bit_offset = gl_LocalInvocationID.z * 4u * 4u + gl_LocalInvocationID.y * 4u + gl_LocalInvocationID.x;

  uvec4
    outValue = imageLoad(inputLOD0, ivec3(inPositionThread));
	
  if (outValue[0] == 0xFFFF && outValue[1] == 0xFFFF && outValue[2] == 0xFFFF && outValue[3] == 0xFFFF)
  {
	bit_local[bit_offset] = true;
  }
  else
  {
    bit_local[bit_offset] = false;
  }

  barrier();

  // Gather set bit_local into the singel 4x4x4 texel using a single thread per workgroup

  if (gl_LocalInvocationID.x == 0 && gl_LocalInvocationID.y == 0 && gl_LocalInvocationID.z == 0)
  {
	uint
	  vec[4];

	vec[0] = 0;
	vec[1] = 0;
	vec[2] = 0;
	vec[3] = 0;

	for (int k = 0; k < 4; k++)
	{
	  for (int j = 0; j < 4; j++)
	  {
		for (int i = 0; i < 4; i++)
		{
		  int
		    ibitindex = k * 4 * 4 + j * 4 + i;

          if (bit_local[ibitindex])
		  {
			uint
			  thisbit = uint(4 * j + i);

		    uint
			  mask = 1u << thisbit;

            vec[k] = vec[k] | mask;
		  }
		}
	  }
	}
	
	
	
	uvec4
	  outValue = uvec4 (vec[0], vec[1], vec[2], vec[3]);
	
	imageStore(inputLOD2, outPosition, outValue);
  }
}

