Jump to content
  • Advertisement
Sign in to follow this  
bronxbomber92

Quake 3 BSP

This topic is 4137 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I'm writing a Quake 3 BSP loader/renderer, and it's going on pretty well. Right now I'm having a hard time understanding the difference between Polygon faces and Mesh faces. Specifically, how the indices are stored for each, and where. If someone could explain to me how those work I'd really appreciate! Thanks, Jedd [Edited by - bronxbomber92 on July 17, 2007 4:04:42 PM]

Share this post


Link to post
Share on other sites
Advertisement
Well, after researching a little more, it seems that the Mesh faces and polygon faces are the same. But I'm not sure about this.

This is how I was thinking I would render a single polygon face:
     Q3BspFace currentFace = m_pFaces[faceIndex];

glVertexPointer( 3, GL_FLOAT, sizeof(Q3BspVertex), &m_pVertices[currentFace.iVertex].fPosition );

glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements( GL_TRIANGLE_FAN, currentFace.iNumVertices, GL_UNSIGNED_INT, &m_pMeshVerts[currentFace.iVertex] )
Where Q3BspFace is
struct Q3BspFace
{
int iTexture; // Texture index
int iEffect;
int iType; // 1 = polygon, 2 = patch, 3 = mesh, 4 = billboard
int iVertex; // Index of first vertex
int iNumVertices;
int iMeshVert; // Index of first MeshVert
int iNumMeshVerts;
int iLightMap; // Lightmap index
int iLightMapCorner[2]; // Corner of this face's lightmap image in lightmap
int iLightMapSize[2]; // Size of the fac'es lightmap
float fLightMapOrigin[3]; // World space origin of the lightmap
float fLightMapVec[2][3]; // World space s & t unit vectors
float fNormal[3];
int iSize[2]; // Patch dimension
};


I don't know if the Q3BspFace.iVertex is a index into the m_pMeshVerts arrays (http://graphics.stanford.edu/~kekoa/q3/#Meshverts), or in the the actual array of Vertices (http://graphics.stanford.edu/~kekoa/q3/#Vertexes). T

The same questions goes for Mesh faces and the iMeshVert index.

Thanks!

Share this post


Link to post
Share on other sites
If memory serves, one is triangles and one is polygons. It's been a while though.

Share this post


Link to post
Share on other sites
Meshes and polygons use the same method for rendering:

glVertexPointer( 3, GL_FLOAT, sizeof( Q3BspVertex ), &Vertices[ surf->iVertex ].Pos );
glDrawElements( GL_TRIANGLES, surf->iNumIndices, GL_UNSIGNED_INT, Indices + surf->iIndex );

Where Vertices is the contents of lump 10, and Indices is the contents of lump 11.

Where you've got iMeshVert and iNumMeshVerts, I've called iIndex and iNumIndex, as they're references into the index table.

That should work. Like Promit, it's been a while. :-)

Meshes are what models compiled into the map are turned into, whereas Polygons are the brush surfaces. The compiler decomposes both into a list of indexed triangles, so you treat them the same.

Share this post


Link to post
Share on other sites
Thanks a lot. My problem is that now everything crashes or freezes. Here's how I'm drawing it:
void Q3Bsp::DrawMeshFace( int faceIndex )
{
/*glVertexPointer( 3, GL_FLOAT, sizeof(Q3BspVertex), &m_pVertices[m_pFaces[faceIndex].iVertex].fPosition );

glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements( GL_TRIANGLES, m_pFaces[faceIndex].iNumMeshVerts, GL_UNSIGNED_INT, &m_pMeshVerts[m_pFaces[faceIndex].iMeshVert] );*/

printf( "Test\n" );
Q3BspFace *pFace = &m_pFaces[faceIndex];
glVertexPointer(3, GL_FLOAT, sizeof(Q3BspVertex), &(m_pVertices[pFace->iVertex].fPosition));
glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements(GL_TRIANGLES, pFace->iNumMeshVerts, GL_UNSIGNED_INT, m_pMeshVerts + pFace->iMeshVert );
}

void Q3Bsp::Draw( CFrustum frustum, Camera camera )
{
frustum.CalculateFrustum();
int currentLeaf = FindCurrentLeaf( camera.Position() );

for( int i = 0; i < m_iNumLeafs; i++ )
{
if( IsClusterVisible( currentLeaf, m_pLeafs.iCluster ) )
{
if( frustum.BoxInFrustum( (float)m_pLeafs.iAABBMin[0], (float)m_pLeafs.iAABBMin[1], (float)m_pLeafs.iAABBMin[2],
(float)m_pLeafs.iAABBMax[0], (float)m_pLeafs.iAABBMax[1], (float)m_pLeafs.iAABBMax[2] ) )
{
for( int index = m_pLeafs.iLeafFace; index < m_pLeafs.iLeafFace + m_pLeafs.iNumLeafFaces; index++ )
{
DrawMeshFace( m_pLeafFaces[index] );
}
}
}
}
}

The DrawMeshFace() does execute (it does print "Test" repeatedly). But it randomly either crashes, freezes totally (and brings up the debugger), or freeze to point where nothing displays and part of the screen is white while te rest is black, yet the windows and printing statements remain functional.

I don't understand why it isn't drawing. I've gone over my loading function several times and I can't find anything.. Maybe it's worth someone else reading it.

// Add texture loading of textures and lightmaps
void Q3Bsp::LoadBsp( const char* filename )
{
FILE* pFile = fopen( filename, "rb" );

if( !pFile )
{
printf( "error opening BSP map!\n Exit...\n" );
exit(1);
}

fread( &m_BspHeader, 1, sizeof(Q3BspHeader), pFile );

// Allocate memory
m_iNumFaces = m_BspHeader.Lumps[Faces].iLength / sizeof(Q3BspFace);
m_pFaces = new Q3BspFace[m_iNumFaces];

m_iNumVertices = m_BspHeader.Lumps[Vertices].iLength / sizeof(Q3BspVertex);
m_pVertices = new Q3BspVertex[m_iNumFaces];

m_iNumMeshVerts = m_BspHeader.Lumps[MeshVerts].iLength / sizeof(int);
m_pMeshVerts = new int[m_iNumMeshVerts];

m_iNumLeafs = m_BspHeader.Lumps[Leafs].iLength / sizeof(Q3BspLeaf);
m_pLeafs = new Q3BspLeaf[m_iNumLeafs];

m_iNumLeafFaces = m_BspHeader.Lumps[LeafFaces].iLength / sizeof(int);
m_pLeafFaces = new int[m_iNumLeafFaces];

m_iNumLeafBrushes = m_BspHeader.Lumps[LeafBrushes].iLength / sizeof(int);
m_pLeafBrushes = new int[m_iNumLeafBrushes];

m_iNumTexs = m_BspHeader.Lumps[Textures].iLength / sizeof(Q3BspTexture);
m_pTextures = new Q3BspTexture[m_iNumTexs];

m_iNumPlanes = m_BspHeader.Lumps[Planes].iLength / sizeof(Q3BspPlane);
m_pPlanes = new Q3BspPlane[m_iNumPlanes];

m_iNumNodes = m_BspHeader.Lumps[Nodes].iLength / sizeof(Q3BspNode);
m_pNodes = new Q3BspNode[m_iNumNodes];

m_iNumModels = m_BspHeader.Lumps[Models].iLength / sizeof(Q3BspModel);
m_pModels = new Q3BspModel[m_iNumModels];

m_iNumLightMaps = m_BspHeader.Lumps[LightMaps].iLength / sizeof(Q3BspLightMap);
m_pLightMaps = new Q3BspLightMap[m_iNumLightMaps];

m_iNumBrushes = m_BspHeader.Lumps[Brushes].iLength / sizeof(Q3BspBrush);
m_pBrushes = new Q3BspBrush[m_iNumBrushes];

m_iNumBrushSides = m_BspHeader.Lumps[BrushSides].iLength / sizeof(Q3BspBrushSides);
m_pBrushSides = new Q3BspBrushSides[m_iNumBrushSides];

m_iNumEffects = m_BspHeader.Lumps[Effects].iLength / sizeof(Q3BspEffect);
m_pEffects = new Q3BspEffect[m_iNumEffects];

m_pImages = new BDTexture[m_iNumTexs];

// Read in data
fseek( pFile, m_BspHeader.Lumps[VisData].iOffset, SEEK_SET );
//if( m_BspHeader.Lumps[VisData].iLength )
fread( &m_VisData, 1, sizeof( Q3BspVisData ), pFile );

fseek( pFile, m_BspHeader.Lumps[Faces].iOffset, SEEK_SET );
fread( m_pFaces, m_iNumFaces, sizeof( Q3BspFace ), pFile );

fseek( pFile, m_BspHeader.Lumps[Vertices].iOffset, SEEK_SET );
fread( m_pVertices, m_iNumVertices, sizeof( Q3BspVertex ), pFile );

fseek( pFile, m_BspHeader.Lumps[MeshVerts].iOffset, SEEK_SET );
fread( m_pMeshVerts, m_iNumMeshVerts, sizeof( int ), pFile );

fseek( pFile, m_BspHeader.Lumps[Leafs].iOffset, SEEK_SET );
fread( m_pLeafs, m_iNumLeafs, sizeof( Q3BspLeaf ), pFile );

fseek( pFile, m_BspHeader.Lumps[LeafFaces].iOffset, SEEK_SET );
fread( m_pLeafFaces, m_iNumLeafFaces, sizeof( int ), pFile );

fseek( pFile, m_BspHeader.Lumps[LeafBrushes].iOffset, SEEK_SET );
fread( m_pLeafBrushes, m_iNumLeafBrushes, sizeof( int ), pFile );

fseek( pFile, m_BspHeader.Lumps[Textures].iOffset, SEEK_SET );
fread( m_pTextures, m_iNumTexs, sizeof( Q3BspTexture ), pFile );

fseek( pFile, m_BspHeader.Lumps[Planes].iOffset, SEEK_SET );
fread( m_pPlanes, m_iNumPlanes, sizeof( Q3BspPlane ), pFile );

fseek( pFile, m_BspHeader.Lumps[Nodes].iOffset, SEEK_SET );
fread( m_pNodes, m_iNumNodes, sizeof( Q3BspNode ), pFile );

fseek( pFile, m_BspHeader.Lumps[Models].iOffset, SEEK_SET );
fread( m_pModels, m_iNumModels, sizeof( Q3BspModel ), pFile );

fseek( pFile, m_BspHeader.Lumps[LightMaps].iOffset, SEEK_SET );
fread( m_pLightMaps, m_iNumLightMaps, sizeof( Q3BspLightMap ), pFile );

fseek( pFile, m_BspHeader.Lumps[Brushes].iOffset, SEEK_SET );
fread( m_pBrushes, m_iNumBrushes, sizeof( Q3BspBrush ), pFile );

fseek( pFile, m_BspHeader.Lumps[BrushSides].iOffset, SEEK_SET );
fread( m_pBrushSides, m_iNumBrushSides, sizeof( Q3BspBrushSides ), pFile );

fseek( pFile, m_BspHeader.Lumps[Effects].iOffset, SEEK_SET );
fread( m_pEffects, m_iNumEffects, sizeof( Q3BspEffect ), pFile );

// Load each texture
/*for( int i = 0; i < m_iNumTexs; i++ )
{
FILE *test;
char *strTest = m_pTextures.cName
if( (test = fopen( strcat(strTest, ".jpg" ) != NULL) || (test = fopen( strcat(strTest, ".jpeg" ) != NULL) )
m_pImages.Load( (const char*)strTest );
else
{
strTest = {0};
strTest = m_pTextures.cName;
m_pImages.Load( (const char*)strcat(strTest, ".png") );
}
}*/


// Swizzle all vertex positions, vertex normals, plane normals,
// and all bounding box min and max vectors to correct coordinate system
// **MIGHT HAVE TO SWIZZEL TEXTURE COORDS**
for( int i = 0; i < m_iNumPlanes; i++ )
{
//SwizzleVertex( m_pPlanes.fNormal );

float temp = m_pPlanes.fNormal[1];
m_pPlanes.fNormal[1] = m_pPlanes.fNormal[2];
m_pPlanes.fNormal[2] = -temp;
}

for( int i = 0; i < m_iNumNodes; i++ )
{
//SwizzleVertex( m_pNodes.iAABBMin );
//SwizzleVertex( m_pNodes.iAABBMax );

int temp = m_pNodes.iAABBMin[1];
m_pNodes.iAABBMin[1] = m_pNodes.iAABBMin[2];
m_pNodes.iAABBMin[2] = -temp;

temp = m_pNodes.iAABBMax[1];
m_pNodes.iAABBMax[1] = m_pNodes.iAABBMax[2];
m_pNodes.iAABBMax[2] = -temp;
}

for( int i = 0; i < m_iNumLeafs; i++ )
{
//SwizzleVertex( m_pLeafs.iAABBMin );
//SwizzleVertex( m_pLeafs.iAABBMax );

int temp = m_pLeafs.iAABBMin[1];
m_pLeafs.iAABBMin[1] = m_pLeafs.iAABBMin[2];
m_pLeafs.iAABBMin[2] = -temp;

temp = m_pLeafs.iAABBMax[1];
m_pLeafs.iAABBMax[1] = m_pLeafs.iAABBMax[2];
m_pLeafs.iAABBMax[2] = -temp;
}

for( int i = 0; i < m_iNumModels; i++ )
{
//SwizzleVertex( m_pModels.fAABBMin );
//SwizzleVertex( m_pModels.fAABBMax );

float temp = m_pModels.fAABBMin[1];
m_pModels.fAABBMin[1] = m_pModels.fAABBMin[2];
m_pModels.fAABBMin[2] = -temp;

temp = m_pModels.fAABBMax[1];
m_pModels.fAABBMax[1] = m_pModels.fAABBMax[2];
m_pModels.fAABBMax[2] = -temp;
}

for( int i = 0; i < m_iNumVertices; i++ )
{
//SwizzleVertex( m_pVertices.fPosition );
//SwizzleVertex( m_pVertices.fNormal );

float temp = m_pVertices.fPosition[1];
m_pVertices.fPosition[1] = m_pVertices.fPosition[2];
m_pVertices.fPosition[2] = -temp;

temp = m_pVertices.fNormal[1];
m_pVertices.fNormal[1] = m_pVertices.fNormal[2];
m_pVertices.fNormal[2] = -temp;
}

fclose( pFile );
}


Thanks for all the help!

Share this post


Link to post
Share on other sites

// Allocate memory
m_iNumFaces = m_BspHeader.Lumps[Faces].iLength / sizeof(Q3BspFace);
m_pFaces = new Q3BspFace[m_iNumFaces];

m_iNumVertices = m_BspHeader.Lumps[Vertices].iLength / sizeof(Q3BspVertex);
m_pVertices = new Q3BspVertex[m_iNumFaces];


You're using m_iNumFaces to allocate your Q3BspVertex array.

Share this post


Link to post
Share on other sites
Nice catch! I can't believe I didn't see that.
Unfortunately, it still freezes (but doesn't crash anymore). As you can see my the folllowing screenshot, the bottom of the screen is just white.
http://img79.imageshack.us/img79/8971/picture1ng7.png

edit - Nevermind! I figured it out... Just another dumb mistake on my side >.<

Thanks for all your help!

[Edited by - bronxbomber92 on July 14, 2007 11:29:14 AM]

Share this post


Link to post
Share on other sites
I have another question, this time about Billboards. Is there any documents about billboards, or any info you guys know about it? All I've been able to find is that the vertex index is its world position.

Share this post


Link to post
Share on other sites
Quote:
Original post by bronxbomber92
I have another question, this time about Billboards. Is there any documents about billboards, or any info you guys know about it? All I've been able to find is that the vertex index is its world position.



billboards are 2d objects in 3d space that are constantly oriented to face the camera.

If you have a camera matrix you can create the quad off of that.

Get a vector from the center of the billboard quad/triangle to the camera.
normalize it. call it the z vector.
cross the world up vector(0,1,0) with the z vector you just got.
normalize that one and call it the xvector
cross the zvecotr and the xvector and call that result, after normalizing it, the yvector.

The x, y and z vectors you have now are the x,y and z axis local to your billboarded quad. You can build the quad from there, or set it's orientation etc what ever you have to do to render the object with those axis.

particles for instance are generally billboarded. Duke3D had billboarded enemies and objects.

Share this post


Link to post
Share on other sites
Quote:
Original post by bronxbomber92
I have another question, this time about Billboards. Is there any documents about billboards, or any info you guys know about it? All I've been able to find is that the vertex index is its world position.


I haven't dealt with billboards in Q3 maps, so can't help you there. The Q3 source code is easy reading though. You could look up how the engine uses them.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!