

// 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;

uniform uvec3 cubeCoordinate[128];

// temporary storage for each lod 2 bit.

shared bool bit_local [4*4*4];


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

void main()
{
  int
    x_local = int (gl_LocalInvocationID.x),
	y_local = int (gl_LocalInvocationID.y),
	z_local = int (gl_LocalInvocationID.z);

  uint
    iCube = gl_WorkGroupID.x;


  ivec3
    inPosition = ivec3 ( cubeCoordinate[iCube].x + x_local, cubeCoordinate[iCube].y + y_local, cubeCoordinate[iCube].z + z_local);

  int
    bit_offset = z_local * 4 * 4 + y_local * 4 + x_local;

  uvec4
    outValue = imageLoad(inputLOD0, inPosition);
	
  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 (x_local == 0 && y_local == 0 && z_local == 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 = 4 * j + i;

		    uint
			  mask = 1 << thisbit;

            vec[k] = vec[k] | mask;
		  }
		}
	  }
	}
	
	ivec3
	  outPosition = ivec3 (cubeCoordinate[iCube].x /4, cubeCoordinate[iCube].y /4, cubeCoordinate[iCube].z /4);
	
	uvec4
	  outValue = uvec4 (vec[0], vec[1], vec[2], vec[3]);
	
	imageStore(inputLOD2, outPosition, outValue);
  }
}

