Exemplo n.º 1
0
// Polygon addition routine: this is the function that actually turns a cubelet into polygons.
// This code is aesthetically based off of Paul Bourke's tutorial code at:
//
//  http://www.swin.edu.au/astronomy/pbourke/modelling/polygonise/
//
// It's not like I copied it, but it is laid out similarly (especially the vertex interpolation part.)
CubePolygonizer::CubeletLocation CubePolygonizer::polygonize(const MarchingCube* cube, float surfaceThreshold, int& neighborsOut, bool addPolys)
{
  assert(mesh != 0);
  assert(sampler != 0);
  currCube = cube;
 
  // First, get the cubelet corner values.
  float cubeValues[8];
  evaluateCubelet(cubeValues);

  // Now aggregate the bitmask used to index into the lookup table.  One bit for each vertex, indicating
  // whether it's inside or outside the surface.
  int cornerBits = 0;
  for (int x=0; x<8; x++)
  {
    // If this one is outside the surface, set its bit to 1.  Otherwise set the bit to 0.
    cornerBits |= (cubeValues[x] < surfaceThreshold) ? (1<<x) : 0;
  }
  
  // Fast reject -- it's either wholly outside or inside the surface.  Determine which...
  if (edgesNeeded[cornerBits] == 0)
  {
    // If one was outside, they all were...
    if (cubeValues[0] < surfaceThreshold)
    {
      return OUTSIDE_SURFACE;
    }

    // ... and vice versa.
    else
    {
      return INSIDE_SURFACE;
    }
  }
  
  // Figure out which vertices we'll need, generate them.  Note that what we get back is an index,
  // as the interp function goes ahead and adds them to the mesh to hide from us whether it's 
  // reusing existing verts.  Also, the edges we need vertices along indicates which neighboring cells
  // will contain polygons, so build the neighbors flag during this stage.
  neighborsOut = 0;
  int vertexIndices[19];
  if (edgesNeeded[cornerBits] & (1<<0))
  {
    vertexInterp(0,1,cubeValues,surfaceThreshold, vertexIndices[0]);
    neighborsOut = neighborsOut | NEIGHBOR_NEG_Y;
    neighborsOut = neighborsOut | NEIGHBOR_NEG_Z;
  }
  if (edgesNeeded[cornerBits] & (1<<1))
  {
    vertexInterp(1,2,cubeValues,surfaceThreshold, vertexIndices[1]);
    neighborsOut = neighborsOut | NEIGHBOR_POS_X;
    neighborsOut = neighborsOut | NEIGHBOR_NEG_Z;
  }
  if (edgesNeeded[cornerBits] & (1<<2))
  {
    vertexInterp(2,3,cubeValues,surfaceThreshold, vertexIndices[2]);
    neighborsOut = neighborsOut | NEIGHBOR_POS_Y;
    neighborsOut = neighborsOut | NEIGHBOR_NEG_Z;
  }
  if (edgesNeeded[cornerBits] & (1<<3))
  {
    vertexInterp(3,0,cubeValues,surfaceThreshold, vertexIndices[3]);
    neighborsOut = neighborsOut | NEIGHBOR_NEG_X;
    neighborsOut = neighborsOut | NEIGHBOR_NEG_Z;
  }
  if (edgesNeeded[cornerBits] & (1<<4))
  {
    vertexInterp(4,5,cubeValues,surfaceThreshold, vertexIndices[4]);
    neighborsOut = neighborsOut | NEIGHBOR_NEG_Y;
    neighborsOut = neighborsOut | NEIGHBOR_POS_Z;
  }
  if (edgesNeeded[cornerBits] & (1<<5))
  {              
    vertexInterp(5,6,cubeValues,surfaceThreshold, vertexIndices[5]);
    neighborsOut = neighborsOut | NEIGHBOR_POS_X;
    neighborsOut = neighborsOut | NEIGHBOR_POS_Z;
  }
  if (edgesNeeded[cornerBits] & (1<<6))
  {
    vertexInterp(6,7,cubeValues,surfaceThreshold, vertexIndices[6]);
    neighborsOut = neighborsOut | NEIGHBOR_POS_Y;
    neighborsOut = neighborsOut | NEIGHBOR_POS_Z;
  }
  if (edgesNeeded[cornerBits] & (1<<7))
  {
    vertexInterp(7,4,cubeValues,surfaceThreshold, vertexIndices[7]);
    neighborsOut = neighborsOut | NEIGHBOR_NEG_X;
    neighborsOut = neighborsOut | NEIGHBOR_POS_Z;
  }
  if (edgesNeeded[cornerBits] & (1<<8))
  {
    vertexInterp(0,4,cubeValues,surfaceThreshold, vertexIndices[8]);
    neighborsOut = neighborsOut | NEIGHBOR_NEG_X;
    neighborsOut = neighborsOut | NEIGHBOR_NEG_Y;
  }
  if (edgesNeeded[cornerBits] & (1<<9))
  {
    vertexInterp(1,5,cubeValues,surfaceThreshold, vertexIndices[9]);
    neighborsOut = neighborsOut | NEIGHBOR_POS_X;
    neighborsOut = neighborsOut | NEIGHBOR_NEG_Y;
  }
  if (edgesNeeded[cornerBits] & (1<<10))
  {
    vertexInterp(2,6,cubeValues,surfaceThreshold, vertexIndices[10]);
    neighborsOut = neighborsOut | NEIGHBOR_POS_X;
    neighborsOut = neighborsOut | NEIGHBOR_POS_Y;
  }
  if (edgesNeeded[cornerBits] & (1<<11))
  {
    vertexInterp(3,7,cubeValues,surfaceThreshold, vertexIndices[11]);
    neighborsOut = neighborsOut | NEIGHBOR_NEG_X;
    neighborsOut = neighborsOut | NEIGHBOR_POS_Y;
  }

// Much as I hate ifdefs, I want this to be easy to flip between, but it's so time critical (this function
// gets called about a bazillion times during tessellation) that I don't want it built it if we're using
// marching cubes.  This is the code that calculates the cross-edges that you need for the tetrahedrons
// (since they split the cube up and introduce new edges in doing so) but not for the marching cubes approach.
#ifdef MARCHING_TETRAHEDRONS

  // Cross-edge ones added for the marching tetrahedron code.
  if (edgesNeeded[cornerBits] & (1<<12))
  {
    vertexInterp(1,4,cubeValues,surfaceThreshold, vertexIndices[12]);
    neighborsOut = neighborsOut | NEIGHBOR_NEG_Y;
  }
  if (edgesNeeded[cornerBits] & (1<<13))
  {
    vertexInterp(2,5,cubeValues,surfaceThreshold, vertexIndices[13]);
    neighborsOut = neighborsOut | NEIGHBOR_POS_X;
  }
  if (edgesNeeded[cornerBits] & (1<<14))
  {
    vertexInterp(2,7,cubeValues,surfaceThreshold, vertexIndices[14]);
    neighborsOut = neighborsOut | NEIGHBOR_POS_Y;
  }
  if (edgesNeeded[cornerBits] & (1<<15))
  {
    vertexInterp(3,4,cubeValues,surfaceThreshold, vertexIndices[15]);
    neighborsOut = neighborsOut | NEIGHBOR_NEG_X;
  }
  if (edgesNeeded[cornerBits] & (1<<16))
  {
    vertexInterp(1,3,cubeValues,surfaceThreshold, vertexIndices[16]);
    neighborsOut = neighborsOut | NEIGHBOR_NEG_Z;
  }
  if (edgesNeeded[cornerBits] & (1<<17))
  {
    vertexInterp(5,7,cubeValues,surfaceThreshold, vertexIndices[17]);
    neighborsOut = neighborsOut | NEIGHBOR_POS_Z;
  }
  if (edgesNeeded[cornerBits] & (1<<18))
  {
    vertexInterp(3,5,cubeValues,surfaceThreshold, vertexIndices[18]);
  }
#endif // MARCHING_TETRAHEDRONS
  
  // Loop over the table of indices and add triangles until we hit the end.  Since we don't necessarily 
  // know the length of each array (depending on whether we're using the marching cubes table, or the
  // marching tetrahedrons table), we pad a -1 at the end of every array, hence the termination condition.
  if (addPolys)
  {
    for (int i=0; newTriIndices[cornerBits][i] != -1; i += 3) 
    {
      int a, b, c;
      a = vertexIndices[newTriIndices[cornerBits][i+0]];
      b = vertexIndices[newTriIndices[cornerBits][i+1]];
      c = vertexIndices[newTriIndices[cornerBits][i+2]];
      mesh->addTri(a, b, c);
      /*DEG somehow I think this is where color interpolation stuff should go. hard to say*/
    }
  }

  // Say we found polygons.
  return ON_SURFACE;
}
void ofxMarchingCubes::polygonise(unsigned int i, unsigned int j, unsigned int k, bool bCalcNormals){
	int cubeindex;
	
	cubeindex = 0;
	if (isoValues[i][j][k] < threshold) cubeindex |= 1;
	if (isoValues[i+1][j][k] < threshold) cubeindex |= 2;
	if (isoValues[i+1][j+1][k] < threshold) cubeindex |= 4;
	if (isoValues[i][j+1][k] < threshold) cubeindex |= 8;
	if (isoValues[i][j][k+1] < threshold) cubeindex |= 16;
	if (isoValues[i+1][j][k+1] < threshold) cubeindex |= 32;
	if (isoValues[i+1][j+1][k+1] < threshold) cubeindex |= 64;
	if (isoValues[i][j+1][k+1] < threshold) cubeindex |= 128;
	if (edgeTable[cubeindex] == 0){
	return;
	}
	
	if (edgeTable[cubeindex] & 1){
		vertexInterp(threshold, gridPoints[i][j][k], gridPoints[i+1][j][k], isoValues[i][j][k] ,isoValues[i+1][j][k], vertList[0]);
	}
	if (edgeTable[cubeindex] & 2){
		vertexInterp(threshold, gridPoints[i+1][j][k], gridPoints[i+1][j+1][k], isoValues[i+1][j][k], isoValues[i+1][j+1][k], vertList[1]);
	}
	if (edgeTable[cubeindex] & 4){
		 vertexInterp(threshold, gridPoints[i+1][j+1][k], gridPoints[i][j+1][k], isoValues[i+1][j+1][k], isoValues[i][j+1][k], vertList[2]);
	}
	if (edgeTable[cubeindex] & 8){
		 vertexInterp(threshold, gridPoints[i][j+1][k], gridPoints[i][j][k], isoValues[i][j+1][k], isoValues[i][j][k], vertList[3]);
	}
	if (edgeTable[cubeindex] & 16){
		 vertexInterp(threshold, gridPoints[i][j][k+1], gridPoints[i+1][j][k+1], isoValues[i][j][k+1], isoValues[i+1][j][k+1], vertList[4]);
	}
	if (edgeTable[cubeindex] & 32){
		 vertexInterp(threshold, gridPoints[i+1][j][k+1], gridPoints[i+1][j+1][k+1], isoValues[i+1][j][k+1], isoValues[i+1][j+1][k+1], vertList[5]);
	}
	if (edgeTable[cubeindex] & 64){
		vertexInterp(threshold, gridPoints[i+1][j+1][k+1], gridPoints[i][j+1][k+1], isoValues[i+1][j+1][k+1], isoValues[i][j+1][k+1], vertList[6]);
	}
	if (edgeTable[cubeindex] & 128){
		vertexInterp(threshold, gridPoints[i][j+1][k+1], gridPoints[i][j][k+1], isoValues[i][j+1][k+1], isoValues[i][j][k+1], vertList[7]); 
	}
	if (edgeTable[cubeindex] & 256){
		vertexInterp(threshold, gridPoints[i][j][k], gridPoints[i][j][k+1], isoValues[i][j][k], isoValues[i][j][k+1], vertList[8]);
	}
	if (edgeTable[cubeindex] & 512){
		vertexInterp(threshold, gridPoints[i+1][j][k], gridPoints[i+1][j][k+1], isoValues[i+1][j][k], isoValues[i+1][j][k+1], vertList[9]); 
	}
	if (edgeTable[cubeindex] & 1024){
		vertexInterp(threshold, gridPoints[i+1][j+1][k], gridPoints[i+1][j+1][k+1], isoValues[i+1][j+1][k], isoValues[i+1][j+1][k+1], vertList[10]); 
	}
	if (edgeTable[cubeindex] & 2048){
		vertexInterp(threshold,	gridPoints[i][j+1][k], gridPoints[i][j+1][k+1], isoValues[i][j+1][k], isoValues[i][j+1][k+1], vertList[11]); 
	}
	for (i=0;triTable[cubeindex][i]!=-1;i+=3) {
		if(bCalcNormals){
			ofVec3f a = vertList[triTable[cubeindex][i+1]] - vertList[triTable[cubeindex][i]];
			ofVec3f b = vertList[triTable[cubeindex][i+2]] - vertList[triTable[cubeindex][i+1]];
			//cross product - a cross b
			ofVec3f normalVec = a.crossed(b);   
			normalVec.normalize();
			normals.push_back(normalVec);
			normals.push_back(normalVec);
			normals.push_back(normalVec);
		}
		vertices.push_back(ofPoint(vertList[triTable[cubeindex][i]].x, vertList[triTable[cubeindex][i]].y, vertList[triTable[cubeindex][i]].z));
		vertices.push_back(ofPoint(vertList[triTable[cubeindex][i+1]].x, vertList[triTable[cubeindex][i+1]].y, vertList[triTable[cubeindex][i+1]].z));
		vertices.push_back(ofPoint(vertList[triTable[cubeindex][i+2]].x, vertList[triTable[cubeindex][i+2]].y, vertList[triTable[cubeindex][i+2]].z));
		numTriangles++;
	}	
}
Exemplo n.º 3
0
int MCube::polygonise(const GridCell& grid, float isolevel, Triangle *triangles)
{
    int   ntriang;
    int   cubeindex;
    BBox::Point vertlist[12];

    /*
       Determine the index into the edge table which
       tells us which vertices are inside of the surface
    */
    cubeindex = 0;
    if (grid.val[0] < isolevel) cubeindex |= 1;
    if (grid.val[1] < isolevel) cubeindex |= 2;
    if (grid.val[2] < isolevel) cubeindex |= 4;
    if (grid.val[3] < isolevel) cubeindex |= 8;
    if (grid.val[4] < isolevel) cubeindex |= 16;
    if (grid.val[5] < isolevel) cubeindex |= 32;
    if (grid.val[6] < isolevel) cubeindex |= 64;
    if (grid.val[7] < isolevel) cubeindex |= 128;

    /* Cube is entirely in/out of the surface */
    if (Table::edgeTable[cubeindex] == 0)
        return(0);

    /* Find the vertices where the surface intersects the cube */
    if (Table::edgeTable[cubeindex] & 1)
        vertlist[0] =
            vertexInterp(isolevel,grid.p[0],grid.p[1],grid.val[0],grid.val[1]);
    if (Table::edgeTable[cubeindex] & 2)
        vertlist[1] =
            vertexInterp(isolevel,grid.p[1],grid.p[2],grid.val[1],grid.val[2]);
    if (Table::edgeTable[cubeindex] & 4)
        vertlist[2] =
            vertexInterp(isolevel,grid.p[2],grid.p[3],grid.val[2],grid.val[3]);
    if (Table::edgeTable[cubeindex] & 8)
        vertlist[3] =
            vertexInterp(isolevel,grid.p[3],grid.p[0],grid.val[3],grid.val[0]);
    if (Table::edgeTable[cubeindex] & 16)
        vertlist[4] =
            vertexInterp(isolevel,grid.p[4],grid.p[5],grid.val[4],grid.val[5]);
    if (Table::edgeTable[cubeindex] & 32)
        vertlist[5] =
            vertexInterp(isolevel,grid.p[5],grid.p[6],grid.val[5],grid.val[6]);
    if (Table::edgeTable[cubeindex] & 64)
        vertlist[6] =
            vertexInterp(isolevel,grid.p[6],grid.p[7],grid.val[6],grid.val[7]);
    if (Table::edgeTable[cubeindex] & 128)
        vertlist[7] =
            vertexInterp(isolevel,grid.p[7],grid.p[4],grid.val[7],grid.val[4]);
    if (Table::edgeTable[cubeindex] & 256)
        vertlist[8] =
            vertexInterp(isolevel,grid.p[0],grid.p[4],grid.val[0],grid.val[4]);
    if (Table::edgeTable[cubeindex] & 512)
        vertlist[9] =
            vertexInterp(isolevel,grid.p[1],grid.p[5],grid.val[1],grid.val[5]);
    if (Table::edgeTable[cubeindex] & 1024)
        vertlist[10] =
            vertexInterp(isolevel,grid.p[2],grid.p[6],grid.val[2],grid.val[6]);
    if (Table::edgeTable[cubeindex] & 2048)
        vertlist[11] =
            vertexInterp(isolevel,grid.p[3],grid.p[7],grid.val[3],grid.val[7]);

    /* Create the triangle */
    ntriang = 0;
    for (int i=0;Table::triTable[cubeindex][i]!=-1;i += 3)
    {
        triangles[ntriang].p[0] = vertlist[Table::triTable[cubeindex][i  ]];
        triangles[ntriang].p[1] = vertlist[Table::triTable[cubeindex][i+1]];
        triangles[ntriang].p[2] = vertlist[Table::triTable[cubeindex][i+2]];
        ntriang++;
    }

    return ntriang;
}
Exemplo n.º 4
0
/*
   Given a grid cell and an isolevel, calculate the triangular
   facets required to represent the isosurface through the cell.
   Return the number of triangular facets, the array "Triangles"
   will be loaded up with the vertices at most 5 triangular facets.
	0 will be returned if the grid cell is either totally above
   of totally below the isolevel.
*/
int polygonise( GridCell grid, float isolevel, Triangle *Triangles ) {
	int i,ntriang;
	int cubeindex;
	FVec3 vertlist[12];

	static int edgeTable[256]={
		0x0  , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
		0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
		0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
		0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
		0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
		0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
		0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
		0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
		0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
		0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
		0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
		0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
		0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
		0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
		0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
		0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
		0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
		0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
		0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
		0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
		0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
		0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
		0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
		0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
		0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
		0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
		0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
		0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
		0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
		0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
		0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
		0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0
	};
	static int triTable[256][16] = {
		{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
		{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
		{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
		{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
		{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
		{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
		{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
		{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
		{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
		{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
		{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
		{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
		{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
		{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
		{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
		{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
		{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
		{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
		{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
		{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
		{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
		{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
		{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
		{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
		{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
		{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
		{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
		{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
		{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
		{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
		{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
		{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
		{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
		{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
		{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
		{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
		{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
		{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
		{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
		{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
		{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
		{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
		{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
		{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
		{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
		{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
		{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
		{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
		{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
		{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
		{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
		{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
		{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
		{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
		{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
		{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
		{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
		{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
		{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
		{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
		{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
		{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
		{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
		{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
		{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
		{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
		{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
		{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
		{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
		{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
		{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
		{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
		{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
		{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
		{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
		{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
		{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
		{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
		{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
		{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
		{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
		{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
		{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
		{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
		{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
		{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
		{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
		{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
		{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
		{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
		{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
		{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
		{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
		{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
		{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
		{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
		{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
		{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
		{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
		{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
		{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
		{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
		{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
		{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
		{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
		{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
		{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
		{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
		{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
		{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
		{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
		{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
		{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
		{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
		{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
		{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
		{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
		{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
		{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
		{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
		{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
		{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
		{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
		{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
		{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
		{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
		{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
		{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
		{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
		{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
		{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
		{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
		{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
		{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
		{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
		{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
		{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
		{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
		{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
		{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
		{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
		{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
		{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
		{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
		{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
		{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
		{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
		{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
		{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
		{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
		{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
		{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
		{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
		{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
		{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
		{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
		{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
		{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
		{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
		{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
		{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
		{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
		{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
		{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
		{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
		{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
		{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
		{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
		{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
		{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
		{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
		{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
		{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
		{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
		{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
		{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
		{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
		{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
		{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
		{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
		{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
		{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
		{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
		{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
		{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
		{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
		{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
		{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
		{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
		{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
	};

	/*
	  Determine the index into the edge table which
	  tells us which vertices are inside of the surface
	*/
	cubeindex = 0;
	if (grid.val[0] < isolevel) cubeindex |= 1;
	if (grid.val[1] < isolevel) cubeindex |= 2;
	if (grid.val[2] < isolevel) cubeindex |= 4;
	if (grid.val[3] < isolevel) cubeindex |= 8;
	if (grid.val[4] < isolevel) cubeindex |= 16;
	if (grid.val[5] < isolevel) cubeindex |= 32;
	if (grid.val[6] < isolevel) cubeindex |= 64;
	if (grid.val[7] < isolevel) cubeindex |= 128;

	/* Cube is entirely in/out of the surface */
	if (edgeTable[cubeindex] == 0)
	  return(0);

	/* Find the vertices where the surface intersects the cube */
	if (edgeTable[cubeindex] & 1)
	  vertlist[0] =
		 vertexInterp(isolevel,grid.p[0],grid.p[1],grid.val[0],grid.val[1]);
	if (edgeTable[cubeindex] & 2)
	  vertlist[1] =
		 vertexInterp(isolevel,grid.p[1],grid.p[2],grid.val[1],grid.val[2]);
	if (edgeTable[cubeindex] & 4)
	  vertlist[2] =
		 vertexInterp(isolevel,grid.p[2],grid.p[3],grid.val[2],grid.val[3]);
	if (edgeTable[cubeindex] & 8)
	  vertlist[3] =
		 vertexInterp(isolevel,grid.p[3],grid.p[0],grid.val[3],grid.val[0]);
	if (edgeTable[cubeindex] & 16)
	  vertlist[4] =
		 vertexInterp(isolevel,grid.p[4],grid.p[5],grid.val[4],grid.val[5]);
	if (edgeTable[cubeindex] & 32)
	  vertlist[5] =
		 vertexInterp(isolevel,grid.p[5],grid.p[6],grid.val[5],grid.val[6]);
	if (edgeTable[cubeindex] & 64)
	  vertlist[6] =
		 vertexInterp(isolevel,grid.p[6],grid.p[7],grid.val[6],grid.val[7]);
	if (edgeTable[cubeindex] & 128)
	  vertlist[7] =
		 vertexInterp(isolevel,grid.p[7],grid.p[4],grid.val[7],grid.val[4]);
	if (edgeTable[cubeindex] & 256)
	  vertlist[8] =
		 vertexInterp(isolevel,grid.p[0],grid.p[4],grid.val[0],grid.val[4]);
	if (edgeTable[cubeindex] & 512)
	  vertlist[9] =
		 vertexInterp(isolevel,grid.p[1],grid.p[5],grid.val[1],grid.val[5]);
	if (edgeTable[cubeindex] & 1024)
	  vertlist[10] =
		 vertexInterp(isolevel,grid.p[2],grid.p[6],grid.val[2],grid.val[6]);
	if (edgeTable[cubeindex] & 2048)
	  vertlist[11] =
		 vertexInterp(isolevel,grid.p[3],grid.p[7],grid.val[3],grid.val[7]);

	/* Create the Triangle */
	ntriang = 0;
	for (i=0;triTable[cubeindex][i]!=-1;i+=3) {
		Triangles[ntriang].p[0] = vertlist[triTable[cubeindex][i  ]];
		Triangles[ntriang].p[1] = vertlist[triTable[cubeindex][i+1]];
		Triangles[ntriang].p[2] = vertlist[triTable[cubeindex][i+2]];
		ntriang++;
	}

	return(ntriang);
}