Sign in to follow this  

BSP rendering: How to go from strips/fans to triangle lists?

Recommended Posts

blueshogun96    2264
I've been trying to fix my BSP renderer for a long time now, and so far, I can't get certain maps to load properly. I know I've already created 2 threads about this, but so far, my final problem remains, how can I re-order my geometry into triangle lists? I've searched the net for solutions, but found nothing time after time after time again. So far, I just heard that using triangle strips instead of fans and strips fixes the problems I have.

Here's the code that I am using right now. The first is my definition of the BSP face:

// BSP face structure
struct tBSPFace
int textureID; // The index into the texture array
int effect; // The index for the effects (-1 == none)
int type; // 1 = Polygon, 2 = Patch, 3 = Mesh, 4 = Billboard
int startVertexIndex; // The starting index into this face's first vertex
int numOfVerts; // The number of vertices for this face
int meshVertexIndex; // The index into the first mesh vertex
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
XGVec3 lMapPos; // The 3D origin of lightmap
XGVec3 lMapVecs[2]; // The 3D space for s and t unit vector
XGVec3 vNormal; // The face normal
int size[2]; // The besier patch dimensions

This way, you can get a better understanding of what each field is compared to your own loaders. Next is my code for the loader, but I'll only show up to the part where the vertex buffer is created and filled so you understand what I am doing:

// File: CQuake3BSP::LoadBSP
// Desc:
bool CQuake3BSP::LoadBSP( char* szFileName )
FILE* fp = NULL;
int i = 0;

// Open the .bsp file
if( ( fp = fopen( szFileName, "rb" ) ) == NULL )
MessageBoxA( NULL, "Error loading the .bsp file!", "BSP Demo", MB_OK );
return false;

// Initialize the header and lump structures
tBSPHeader header = {0};
tBSPLump lumps[kMaxLumps] = {0};

// Read in the header and lump data
fread( &header, 1, sizeof( tBSPHeader ), fp );
fread( &lumps, kMaxLumps, sizeof( tBSPLump ), fp );

// Allocate vertex memory
m_NumOfVerts = lumps[kVertices].length / sizeof( tBSPVertex );
m_pVerts = new tBSPVertex[m_NumOfVerts];

// Allocate the face memory
m_NumOfFaces = lumps[kFaces].length / sizeof( tBSPFace );
m_pFaces = new tBSPFace[m_NumOfFaces];

// Allocate memory for texture information
m_NumOfTextures = lumps[kTextures].length / sizeof( tBSPTexture );
tBSPTexture* pTextures = new tBSPTexture[m_NumOfTextures];

// Seek to the position in the file that stores vertex information
fseek( fp, lumps[kVertices].offset, SEEK_SET );

// Create a vertex buffer to store all of our vertex data
V( DXUTGetD3D9Device()->CreateVertexBuffer( m_NumOfVerts * sizeof( tBSPRenderVertex ), 0,
D3DPOOL_MANAGED, &m_pVertexBuffer, NULL ) );

// Lock the vertex buffer and start giving it vertex data
tBSPRenderVertex* pVerts = NULL;
V( m_pVertexBuffer->Lock( 0, 0, (void**) &pVerts, 0 ) );

// Swap the z coordinate with the y coordinate so that the BSP is rendered
// correctly.
for( i = 0; i < m_NumOfVerts; i++ )
// Read current vertex
fread( &m_pVerts[i], 1, sizeof( tBSPVertex ), fp );

// Swap the y and z values and negate the z so y is up
float temp = m_pVerts[i].vecPosition.y;
m_pVerts[i].vecPosition.y = m_pVerts[i].vecPosition.z;
m_pVerts[i].vecPosition.z = -temp;

// Negate the the u tex coord for Direct3D
m_pVerts[i].vecTextureCoord.x *= -1;

// Write the most important vertex data to the vertex buffer
pVerts[i].vecPosition = m_pVerts[i].vecPosition;
pVerts[i].vecTextureCoord = m_pVerts[i].vecTextureCoord;

// Unlock the vertex buffer
V( m_pVertexBuffer->Unlock() );


Now, for the rendering part. This is my code for rendering faces. I haven't added support for patches, curves or surfaces yet because I haven't gotten that far. I need the general stuff to work first so I can get this game up and running ASAP.

// Name: CQuake3BSP::RenderFace
// Desc:
void CQuake3BSP::RenderFace( int FaceIndex )
IDirect3DDevice9* pD3DDevice = DXUTGetD3D9Device();

// Grab the face from the index passed in
tBSPFace* pFace = &m_pFaces[FaceIndex];

// Set the texture
V( pD3DDevice->SetTexture( 0, m_ppTextures[pFace->textureID] ) );

// Render the face
V( pD3DDevice->SetStreamSource( 0, m_pVertexBuffer, 0, sizeof( tBSPRenderVertex ) ) );
V( pD3DDevice->SetFVF( tBSPRenderVertex::FVF ) );
V( pD3DDevice->DrawPrimitive( D3DPT_TRIANGLEFAN, pFace->startVertexIndex, pFace->numOfVerts - 2 ) );

m_NumOfPrimitives += pFace->numOfVerts - 2;

/*V( pD3DDevice->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, pFace->numOfVerts,
(m_pVerts + (pFace->startVertexIndex*sizeof(tBSPVertex))),
sizeof(tBSPVertex) ) );*/


How would I go about re-ordering all of this into triangle lists? I've tried various methods, but I can't get anything to work better than what I already have. This sucks. Any ideas?? Thanks.

Share this post

Link to post
Share on other sites
Hodgman    51222
How to go from strips/fans to triangle lists?
Count how many tris are in the fan/strip.
Allocate an index buffer with that number times 3 space.
For each triangle in the fan/strip, add the 3 indices to the index buffer.
Use the original vertex buffer along with the new index buffer to render an indexed tri list.

Not tested, but something like this:
bool isStrip = ...;//fan or strip
int numVerts = ...;
int numTris = numVerts-2;
uint16 indices = new uint16[numTris*3];
for( int tri=2; tri!=numVerts; ++tri )
indices[i++] = isStrip ? tri-2 : 0;
indices[i++] = tri-1;
indices[i++] = tri;

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this