 layout(lines_adjacency) in;
 layout(triangle_strip,max_vertices=21) out;
 
-struct vertex_data {
-  vec4 p;
-  vec4 n;
-  vec3 d;
-};
-
 uniform vec2 nearfar;
 
 in vec4 inverted_position[4];

noperspective out vec3 integrand_over_w_back;
noperspective out vec2 texPosition;

#if 0
// Swap two things
// Passing elements of an array as inout parameters appears to be
// broken with version 325 of Nvidia drivers.
void swap(inout vertex_data a, inout vertex_data b)
{
  vertex_data t = a;
  a = b;
  b = t;
}
#endif

vec4 vector_inverse(vec4 a)
{
  float w = a.w;
  a.w = 1.0;
  a /= w;
  return a;
}

// Return +/- 1, depending on the orientation of triangle a -> b -> c

      ;
    else if (orient02 > 0.) {
      // 0 and 2 match, so swap 1 with 2
      swap4(n1, n2);
      swap3(i1, i2);
    } else {
      // 0 and 3 match, so swap 1 with 3
      swap4(n1, n3);
      swap3(i1, i3);
    }

    bad_case(n0, n1, n2, n3, i0, i1, i2, i3);
  }
}

vec4 vector_inverse(vec4 a)
{
  float w = a.w;
  a.w = 1.0;
  a /= w;
  return a;
}

void intersect_nearclip(out vec4 nc, out vec3 ic,
                        vec4 px, vec3 ix, vec4 py, vec3 iy)
{
  float near = nearfar[0];
  float t = (near - py.w) / (px.w - py.w);
  nc = vector_inverse(t * px + (1-t) * py);
  ic = t * ix + (1-t) * iy;
}

void main(void)
{
  vec4 p0 = gl_in[0].gl_Position;
  vec4 p1 = gl_in[1].gl_Position;
  vec4 p2 = gl_in[2].gl_Position;
  vec4 p3 = gl_in[3].gl_Position;

  // Number of vertices clipped by the near plane
  int num_clipped = 0;

  // Count how many vertices are clipped
  float near = nearfar[0];
  if (p0.w < near)
    ++num_clipped;
  if (p1.w < near)
    ++num_clipped;
  if (p2.w < near)
    ++num_clipped;
  if (p3.w < near)
    ++num_clipped;

  if (num_clipped == 4)
    return;

  vec4 n0 = inverted_position[0];
  vec4 n1 = inverted_position[1];
  vec4 n2 = inverted_position[2];
  vec4 n3 = inverted_position[3];

  vec3 i0 = integrand[0];
  vec3 i1 = integrand[1];
  vec3 i2 = integrand[2];
  vec3 i3 = integrand[3];

  if (num_clipped == 0) {
    handle_tetrahedron(n0, n1, n2, n3, i0, i1, i2, i3);
    return;
  }

  // Handle the near clipping plane. This is the "slow" execution path.

  // Move clipped vertices to the front of the array using a "sorting network"
  if (p0.w >= near && p2.w < near) {
    swap4(p0, p2);
    swap4(n0, n2);
    swap3(i0, i2);
  }
  if (p1.w >= near && p3.w < near) {
    swap4(p1, p3);
    swap4(n1, n3);
    swap3(i1, i3);
  }
  if (p0.w >= near && p1.w < near) {
    swap4(p0, p1);
    swap4(n0, n1);
    swap3(i0, i1);
  }
  if (p2.w >= near && p3.w < near) {
    swap4(p2, p3);
    swap4(n2, n3);
    swap3(i2, i3);
  }
  if (p1.w >= near && p2.w < near) {
    swap4(p1, p2);
    swap4(n1, n2);
    swap3(i1, i2);
  }

  switch (num_clipped) {

  case 1:

    {
      // One vertex clipped:
      // Must determine the intersections of the 0-to-i segments
      // with the near clipping plane, and construct three new tetrahedra
      // to render.

      vec4 n03;
      vec3 i03;
      intersect_nearclip(n03, i03, p0, i0, p3, i3);
      handle_tetrahedron(n1, n2, n3, n03,
                         i1, i2, i3, i03);

      vec4 n02;
      vec3 i02;
      intersect_nearclip(n02, i02, p0, i0, p2, i2);
      handle_tetrahedron(n1, n2, n02, n03,
                         i1, i2, i02, i03);

      vec4 n01;
      vec3 i01;
      intersect_nearclip(n01, i01, p0, i0, p1, i1);
      handle_tetrahedron(n1, n01, n02, n03,
                         i1, i01, i02, i03);
    }

    return;

  case 2:

    {
      // Two vertices clipped:
      // Must determine the intersections of the (0,1)-to-(2,3) segments
      // with the near clipping plane, and construct three new tetrahedra
      // to render.
      vec4 n02;
      vec3 i02;
      intersect_nearclip(n02, i02, p0, i0, p2, i2);

      vec4 n12;
      vec3 i12;
      intersect_nearclip(n12, i12, p1, i1, p2, i2);

      handle_tetrahedron(n2, n3, n02, n12,
                         i2, i3, i02, i12);

      vec4 n03;
      vec3 i03;
      intersect_nearclip(n03, i03, p0, i0, p3, i3);

      handle_tetrahedron(n3, n02, n12, n03,
                         i3, i02, i12, i03);

      vec4 n13;
      vec3 i13;
      intersect_nearclip(n13, i13, p1, i1, p3, i3);

      handle_tetrahedron(n3, n12, n03, n13,
                         i3, i12, i03, i13);
    }

    return;

  case 3:

    // Three vertices clipped:
    // Must replace 0-2 with their projections toward 3 at
    // the point they intersect the near clipping plane.
    vec4 n03;
    vec3 i03;
    intersect_nearclip(n03, i03, p0, i0, p3, i3);

    vec4 n13;
    vec3 i13;
    intersect_nearclip(n13, i13, p1, i1, p3, i3);

    vec4 n23;
    vec3 i23;
    intersect_nearclip(n23, i23, p2, i2, p3, i3);

    handle_tetrahedron(n03, n13, n23, n3,
                       i03, i13, i23, i3);

    return;

  default:

    return;

  }
}
