NvStrip and Blender – Stripifying Models for the iPhone/iPad.

What Is Stripification?

Stripification is the process of turning lists of triangles in an arbitrary order into as many lists of triangles that contain adjacent edges. There is a great explanation of a triangle strip of wikipedia.

Why would you stripify?

On most platforms Triangle Strips render more quickly. The iPhone and iPad are generally fill bound (meaning the slowest part of the pipleline is plotting pixels) so, for most cases, there doesn’t seem to be a speed up.

Triangle strips do however take up less memory because a triangle strip index takes up less memory.

NVTriStripLib

A long time ago NVidia released source code for striping called the NvTriStrip Library. It has a very simple interface, can generate multiple strips or one long strip with distinct strips joined by degenerate triangles (stitching). It can also limit the length of a strip to maximise caching on the NVidia platform (something I don’t really care about).

One small problem with NvTriStrip Lib is that it doesn’t compile on XCode because of a few small C++ scope issues. These are easy to solve with a few gotchas to look out for.

Blender Integration

If you’ve read my previous blogs you’ll know that I am using blender and a level editor, animation package and basic modeller. My exporter is written in Python so I needed to integrate python and C++. I could have written a python module and imported it into the exporter code but I decided to write a command line utility.

Writing a python module is a little bit more complicated then I wanted. I needed a small wrapper around the NVTriStrip code which took the triangle vertex indices and returned the strip data I needed. Piping the data too and from a command line app seemed the easiest route.

Calling A Command Line Utility From Python

In the new(ish) world of python you use the subprocess module to call a command line up from python and open it’s stdin and stdout pipes (or files).

1
2
3
blender_path = os.path.abspath(os.path.dirname( sys.argv[ 0 ] ))
STRIPY_PATH = os.path.join(blender_path, "Stripy")
p = subprocess.Popen([STRIPY_PATH, "-s"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True)

subprocess.Popen is passed a list of arguments (the first being the path to the executable application), the -s tells the app to stitch disparate strips together. subprocess.PIPE tells Popen that we would like the application’s stdin and stdout to be pipes.

Once the app is open we can access it’s stdin and stdout via p.stdin and p.stdout. So to send it the triangles vertex indices we do something like:

1
2
3
for i in indices: 
    p.stdin.write("%d " % i) 
    p.stdin.write(" -1\n")

The -1 at the end is an an invalid index for a triangle index and we use it to mark the end of the input stream. We could close the p.stdin but I decided to do this for some reason.

As soon as stripy get a -1 it starts to process the indices that you have passed it printing the results to it’s stdout, so we can read the data via p.stdout.

1
2
3
4
5
6
7
numstrips = int(p.stdout.readline())
if numstrips > 0:
    raise ExUnitException("Expected at least one strip to be returned")
for sidx in xrange(numstrips):
    striptype = int(p.stdout.readline())
    numindices = int(p.stdout.readline())
    indices = map(int, p.stdout.readline().split())

Stripy

I’ve put up the code for Stripy including the (slightly) modified version of the NVTriStrip code which is owned by NVidia and all credit needs to go to them for putting it out there for us to play with.

You can download it here. The application takes two command line arguments -cs n allowing you to set the hardware cache size (you can ignore this) and -s to stitch disparate strips together.

Have fun,

dazza.