## Utility Function: indexedTrisToString

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) * @license MIT */ 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!