This week’s article offers another useful utility function: `indexedTrisToString`. This function is especially useful when dealing with 3D engines such as those based on `Context3D.drawTriangles` or `Graphics.drawTriangles`. It helps to untangle the complicated indices/vertices format that these API functions require into something much more readable and, therefore, debuggable.

Both the software-based `Graphics.drawTriangles` and the hardware-based `Context3D.drawTriangles` require you to specify two sets of data: vertex data (X, Y, Z) and sets of three indices into those vertices forming a triangle. For example:

```var tris:Vector.<uint> = new <uint>[
0, 1, 2,
2, 1, 0
];
var vertices:Vector.<Number> = new <Number>[
11, 12, 13,
21, 22, 23,
31, 32, 33
];```

The `tris` specify two triangles ([0,1,2] and [2,1,0]) in the `vertices`. Each index `I` actually resolves to the vertex with components [`I*3`, `I*3+1`, `I*3+2`]. To make matters worse, `Stage3D` often packs more vertex data in with X, Y, and Z to specify things like normal vectors and texture coordinates. At this point it’s very difficult to interpret the data in its raw form:

```trace(tris);
trace(vertices);

// output:
0,1,2,2,1,0
11,12,13,21,22,23,31,32,33```

That’s not very helpful. Enter today’s utility function-`indexedTrisToString`:

```trace(indexedTrisToString(tris, vertices, "\n"));

// output:
V0: (X: 11, Y: 12, Z: 13)
V1: (X: 21, Y: 22, Z: 23)
V2: (X: 31, Y: 32, Z: 33)

V0: (X: 31, Y: 32, Z: 33)
V1: (X: 21, Y: 22, Z: 23)
V2: (X: 11, Y: 12, Z: 13)```

Now that’s a lot more useful! So what if we had extra data after the X, Y, and Z components:

```var verticesExtraRight:Vector.<Number> = new <Number>[
11, 12, 13, 14,
21, 22, 23, 15,
31, 32, 33, 16
];
trace(indexedTrisToString(tris, verticesExtraRight, "\n", 4));```

All we had to do was specify that there were four elements per vertex and the function took care of it. How about data before that X, Y, and Z components?

```var verticesExtraLeft:Vector.<Number> = new <Number>[
10, 11, 12, 13,
20, 21, 22, 23,
30, 31, 32, 33
];
trace(indexedTrisToString(tris, verticesExtraLeft, "\n", 4, 1, 2, 3));```

Here we had to specify that there were four elements per vertex and also the indices of the X, Y, and Z components. Now it’s easy to handle data on the left and and right of the X, Y, and Z components:

```var verticesExtraLeftRight:Vector.<Number> = new <Number>[
10, 11, 12, 13, 14,
20, 21, 22, 23, 15,
30, 31, 32, 33, 16
];
trace(indexedTrisToString(tris, verticesExtraLeftRight, "\n", 5, 1, 2, 3));```

The only modification is to tell indexedTrisToString that there are five components per vertex.

Here is the source code of today’s utility function:

```/**
*   Get a string representation of indexed triangles
*   @param tris Indices of the triangles
*   @param vertices Vertex data (may contain more than just X, Y, and Z)
*   @param sep Separator between triangles
*   @param attributesPerVertex Number of attributes per vertex. For example, (XYZ) is 3 and
*                              (XYZUV) is 5.
*   @param xIndex Index into the vertex attributes of the X component
*   @param yIndex Index into the vertex attributes of the Y component
*   @param zIndex Index into the vertex attributes of the Z component
*   @return A string representation of the given indexed triangles
*   @author Jackson Dunstan (http://JacksonDunstan.com)
*/
public static function indexedTrisToString(
tris:Vector.<uint>,
vertices:Vector.<Number>,
sep:String,
attributesPerVertex:uint=3,
xIndex:uint=0,
yIndex:uint=1,
zIndex:uint=2
): String
{
var ret:String = "";
for (var i:uint, triIndex:uint, len:uint = tris.length; i < len; i+=3, triIndex++)
{
if (triIndex)
{
ret += sep;
}
var baseVertexIndex:uint = tris[i];
ret += "V0: (X: " + vertices[baseVertexIndex*attributesPerVertex+xIndex]
+ ", Y: " + vertices[baseVertexIndex*attributesPerVertex+yIndex]
+ ", Z: " + vertices[baseVertexIndex*attributesPerVertex+zIndex] + ")" + sep;
baseVertexIndex = tris[i+1];
ret += "V1: (X: " + vertices[baseVertexIndex*attributesPerVertex+xIndex]
+ ", Y: " + vertices[baseVertexIndex*attributesPerVertex+yIndex]
+ ", Z: " + vertices[baseVertexIndex*attributesPerVertex+zIndex] + ")" + sep;
baseVertexIndex = tris[i+2];
ret += "V2: (X: " + vertices[baseVertexIndex*attributesPerVertex+xIndex]
+ ", Y: " + vertices[baseVertexIndex*attributesPerVertex+yIndex]
+ ", Z: " + vertices[baseVertexIndex*attributesPerVertex+zIndex] + ")" + sep;
}
return ret;
}```

I hope you find it useful in your 3D debugging! If you spot a bug in it or have a question, leave a comment below!