# [翻译]quake3bsp

1295人阅读 评论(0)

Introduction

This document was created as an aid to the Quake3 BSP  tutorial series featured on www.GameTutorials.com.      The information is what I have found, and it's possibly that it's incorrect or just blatently wrong.  I suggest you use this as a reference and a guide, not the end all file format doc for the Quake3 .bsp file format.  With that out of the way, let's load some sweet levels!

The Quake3 level format, .bsp, stores most of the information about the level.  There are other files such as .shader, .arena and .aas, which store bot and texture shader information.  The .bsp file is stored in what is called a IBSP format.  That means that the length and offsets of different sections in the file are stored in what's know as lumps.  The older version of Quake use this same lump format, but different information is stored in each version of Quake.  If you can read in Quake 3 levels, it's not a lot of changes to write a Quake 2 level loader.

If you don't know what BSP stands for yet, it means Binary Space Partition(ing).  You would create a BSP tree.  That means that there is a parent node, and at most, 2 children attached to each parent.  These children are called the front and back children.  I won't attempt to teach you how to create or manage a BSP tree here, but there is a BSP FAQ that SGI put out floating around the internet somewhere that has a ton of information.  Better yet, I suggest you take the BSP class at www.GameInstitute.com.  I personally took this class and was quite satisfied.  It teaches all you need to know about BSP trees.

Lumps

Like we mentioned before, lumps hold the length in bytes and offset into the file for a given section.  Below is an enum eLumps that holds all the lumps and their order in the file:

enum eLumps
{
    kEntities = 0,     // Stores player/object positions, etc...
    kTextures,         // Stores texture information
    kPlanes,           // Stores the splitting planes
    kNodes,            // Stores the BSP nodes
    kLeafs,            // Stores the leafs of the nodes
    kLeafFaces,        // Stores the leaf's indices into the faces
    kLeafBrushes,      // Stores the leaf's indices into the brushes
    kModels,           // Stores the info of world models
    kBrushes,          // Stores the brushes info (for collision)
    kBrushSides,       // Stores the brush surfaces info
    kVertices,         // Stores the level vertices
    kMeshVerts,        // Stores the model vertices offsets
    kShaders,          // Stores the shader files (blending, anims..)
    kFaces,            // Stores the faces for the level
    kLightmaps,        // Stores the lightmaps for the level
    kLightVolumes,     // Stores extra world lighting information
    kVisData,          // Stores PVS and cluster info (visibility)
    kMaxLumps          // A constant to store the number of lumps
};

Each on of these sections has a offset and a size in bytes that need to be read in.  In the next sections we will examine the structures needed to read in each lump.

Here is a lump structure.  The offset is the position into the file that is the starting point of the current section.  The length is the number of bytes that this lump stores.

struct tBSPLump
{
    int offset;
    int length;
};

Let's give an example of reading in the vertices (kVertices) for the level.  Once the lumps are read in, to find the number of vertices in the level we do this:

numOfVerts = lumps[kVertices].length / sizeof(tBSPVertex);

We index the lumps[] array with the kVertices constant, then divide that lumps length by the size of the tBSPVertex structure in bytes, which we will define later on.  It just so happens it's 44 bytes.  If the length is 3388, then 3388 / 44 = 77.  We now know there is 77 vertices in the .bsp file.  We then need to position the file pointer to the lump's offset, and start reading in 77 tBSPVertex structures into our dynamically allocated vertex array.  I use fread() and fseek() for the file manipulation.  This is of course, ONLY if you are not reading from the .zip file.  I am strictly speaking of loading the .bsp file unzipped.

Now that we understand the basics of lumps, let's move on to the header structure, along with the rest of the structures for each lump read in.

The very first thing that needs to be read in for the .bsp file is the header.  The header contains a 4 character ID, then an integer that holds the version.

{

char strID[4];     // This should always be 'IBSP'

int version;       // This should be 0x2e for Quake 3 files

};

Vertices

This structure stores the vertex information.  There is a position, texture and lightmap coordinates, the vertex normal and color.  To calculate the number of vertices in the lump you divide the length of the lump by the.

struct tBSPVertex

{

float vPosition[3];      // (x, y, z) position.

float vTextureCoord[2];  // (u, v) texture coordinate

float vLightmapCoord[2]; // (u, v) lightmap coordinate

float vNormal[3];        // (x, y, z) normal vector

byte color[4];           // RGBA color for the vertex

};

Faces

This structure holds the face information for each polygon of the level.  It mostly holds indices into all the vertex and texture arrays.  To calculate the number of faces in the lump you divide the length of the lump by the sizeof(tBSPFace).

struct tBSPFace

{

int textureID;        // The index into the texture array

int effect;           // The index for the effects (or -1 = n/a)

int type;             // 1=polygon, 2=patch, 3=mesh, 4=billboard

int vertexIndex;      // The index into this face's first vertex

int numOfVerts;       // The number of vertices for this face

int meshVertIndex;    // The index into the first meshvertex

int numMeshVerts;     // The number of mesh vertices

int lightmapID;       // The texture index for the lightmap

int lMapCorner[2];    // The face's lightmap corner in the image

int lMapSize[2];      // The size of the lightmap section

float lMapPos[3];     // The 3D origin of lightmap.

float lMapVecs[2][3]; // The 3D space for s and t unit vectors.

float vNormal[3];     // The face normal.

int size[2];          // The bezier patch dimensions.

};

If the face type is 1 (normal polygons), the vertexIndex and numOfVerts can be used to index into the vertex array to render triangle fans.

If the face type is 2 (bezier path), the vertexIndex and numOfVerts act as a 2D grid of control points, where the grid dimensions are described by the size[2] array.  You can render the bezier patches with just the vertices and not fill in the curve information, but it looks horrible and blocky.

The point of the curved surfaces are to be able to create a more defined surface, depending on the specs of the computer that is running that application.  Some computers with horrible speed and video cards would make the smallest amount of polygons from the curve, where as the fast computers using Geforce cards could use the highest amount of polygons to form a perfect curve.

If the face type is 3 (mesh vertices), the vertexIndex and numOfVerts also work the same as if the type is 1

If the face type is 4, the vertexIndex is the position of the billboard.  The billboards are used for light effects such as flares, etc...

0
0

* 以上用户言论只代表其个人观点，不代表CSDN网站的观点或立场
个人资料
• 访问：8352次
• 积分：119
• 等级：
• 排名：千里之外
• 原创：4篇
• 转载：0篇
• 译文：0篇
• 评论：2条
文章存档
评论排行
最新评论