Friday, August 8, 2008

Life Intrudes Again

I've been very busy at work and at home for the past week, so not much has been done. About the only progress is some refactoring of the code to separate all of the wx windows GUI code from the opengl code. This is in preparation to writing the tutorials so that the tutorials can completely focus on the opengl code. When the refactoring is complete (I've only done one file so far) I will write an explanation of the framework code similar to the parser code.

The next two weeks don't look good for progress either with the olympics on TV.

Oh Well,

Till next time,
Naltai

Sunday, August 3, 2008

Appendix A: BSP Parser

This Appendix explains the BSP parser code. This code is used by the tutorials to obtain data out of a BSP file. The code is completely self contained in the ibsp.py file.

The BSP parser code, like the BSP file format itself, is based around the concept of lumps. A lump is basically an array of one type of data. There are seventeen lumps in the Quake3 BSP file format, each of which contains a different type of data. Whilst the parser handles all of the Lump types, only a couple are used as examples in this document. For complete details of all of the lumps see Unoffical Quake3 Map Specs.

The parser extensively uses the python struct module. This module takes binary data in python strings (such as that you get from reading a binary file) and turns it into python base types such as integers and floating point numbers. For example, a plane object is read with the following line:


x, y, z, self.dist = struct.unpack("ffff", data)


The first argument specifies that we are reading 4 floating point numbers, the second argument is the string containing the data, which must be of the appropriate length, in this case 16 bytes (each float is 4 bytes long). The function returns a tuple containing the read values as the appropriate type, here we are using pythons ability to automatically unpack tuples with an assignment to place the values exactly where we want them. All uses of the struct module in this parser fall into this general usage pattern.

The parser is structured as a single class object that contains seventeen lump objects, named after their types. For example IBSP vectors is a lump of vectors. An IBSP object is created through its constructor which takes a standard python file object. It reads this file and makes a local copy of all the data which it holds internally. After the IBSP object is created, if the file is deleted or modified it will not affect the functioning of the program.

A lump is represented as a pseudo python list object. There are two ways to obtain data from each lump, either use standard list access syntax which will return a helper object representing the data. It is also possible to access the raw data in each lump using the .data property. This is useful for passing to functions which require the raw data, such as glVertexPointer.

There is a helper class for each type of data in the BSP file, for example the Plane class represents the objects in the planes lump. Helper classes are very simple, they have a constructor which reads the raw object data and converts it into object attributes of more useful types. They also have a pretty printing function which allows for relatively simple debugging.

The Leaffaces, leafbrushes and meshverts lumps have the type of a simple integer. Rather than make a simple integer helper class, a special lump class IntLump handles these three types. This will return the data as python integers which is a naturally useful interface to these types of data.

The final part of the file is a small test script that is executed when this script is run as a standalone script. This simply reads a supplied BSP file and pretty prints the first item of data from each lump as a test of the script.

Enjoy,
Naltai