Hi !
I have SERIOUS trouble getting the size of Q2 lightmaps. I read trough three other Q2 engine sources, I can’t figure out what I’m doing wrong. Could you please look at my code an tell me ?
// BSP.cpp: Implementation of the class CBSP.
//
//////////////////////////////////////////////////////////////////////#include “stdafx.h”
#include “BSP.h”//////////////////////////////////////////////////////////////////////
// Construction / destruction
//////////////////////////////////////////////////////////////////////CBSP::CBSP()
{
////////////////////////////////////////////////////////////////////////
// Initialize the member data
////////////////////////////////////////////////////////////////////////m_pVertices = 0;
m_pEdges = 0;
m_pFaces = 0;
m_pFaceEdges = 0;
m_pPlanes = 0;
m_pNodes = 0;
m_pLeaves = 0;
m_pLeafFaces = 0;
m_pTexInfos = 0;
m_pTextures = 0;
m_pLightmaps = 0;memset(&m_sCount, 0, sizeof(BSP_LumpCount));
}CBSP::~CBSP()
{
////////////////////////////////////////////////////////////////////////
// Free the member data
////////////////////////////////////////////////////////////////////////BSP_Texture *pCurTex = 0;
BSP_Texture *pNextTex = 0;if (m_pVertices)
delete m_pVertices;
m_pVertices = 0;
if (m_pEdges)
delete m_pEdges;
m_pEdges = 0;
if (m_pFaces)
delete m_pFaces;
m_pFaces = 0;
if (m_pFaceEdges)
delete m_pFaceEdges;
m_pFaceEdges = 0;
if (m_pPlanes)
delete m_pPlanes;
m_pPlanes = 0;
if (m_pNodes)
delete m_pNodes;
m_pNodes = 0;
if (m_pLeaves)
delete m_pLeaves;
m_pLeaves = 0;
if (m_pLeafFaces)
delete m_pLeafFaces;
m_pLeafFaces = 0;
if (m_pTexInfos)
delete m_pTexInfos;
m_pTexInfos = 0;
if (m_pLightmaps)
delete m_pLightmaps;
m_pLightmaps = 0;if (m_pTextures)
{
// Start cleaning up with the first node
pCurTex = m_pTextures;// Remove the linked list do { assert(pCurTex); // Save pointer to next texture pNextTex = pCurTex->pNextTexture; // Delete current texture delete pCurTex; pCurTex = 0; // Process the next texture pCurTex = pNextTex; } while (pCurTex); // Continue if this is not the tail node m_pTextures = 0;
}
}void CBSP::RenderWithoutHSR()
{
////////////////////////////////////////////////////////////////////////
// Brute-force approach to render all geometry
////////////////////////////////////////////////////////////////////////unsigned long int iCurFace, iCurFaceEdge;
BSP_Texture *pCurTexture = 0;
unsigned int iTexWidth;
int iVertex1, iVertex2, iTempVertex;
BSP_TexInfo *pTexInfo = 0;
float fU, fV;
static int iDisplayList = -1;
CTexture cMultitexturing;
char szLastTextureName[32] = { ‘\0’ };assert(m_pEdges);
assert(m_pFaces);
assert(m_pVertices);
assert(m_pTextures);
assert(m_pLightmaps);
assert(m_pFaceEdges);// Has the display list already been generated ?
if (iDisplayList != -1)
{
// Just call the list and exit
glCallList(iDisplayList);
return;
}// This is the first time we render the scene. Create a display
// list and render the scene into the list while passing it to OpenGL.
iDisplayList = glGenLists(1);
glNewList(iDisplayList, GL_COMPILE);// Save rendering state
glPushAttrib(GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT);// Enable multitexturing
cMultitexturing.InitMultitexturing();// Additive blending for the second TMU
cMultitexturing.ChoseActiveTMU(GL_TEXTURE1_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD);// Use fullbright textures for the first TMU
cMultitexturing.ChoseActiveTMU(GL_TEXTURE0_ARB);
glDisable(GL_LIGHTING);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);// Loop trough all faces
for (iCurFace=0; iCurFace<m_sCount.iFaceCount; iCurFace++)
{
// Save ‘shortcut’ pointer to access the texture informations
pTexInfo = &m_pTexInfos[m_pFaces[iCurFace].iTexInfo];// Start with the first texture in the linked list pCurTexture = m_pTextures; // Find the current texture and bind it to the first TMU do { assert(pCurTexture); if (_stricmp(pTexInfo->szTextureName, pCurTexture->szTextureName) == 0) { // Texture found. Is a state change neccessary ? if (_stricmp(szLastTextureName, pCurTexture->szTextureName) != 0) { // This texture differs from the last one. Make it the current one cMultitexturing.ChoseActiveTMU(GL_TEXTURE0_ARB); pCurTexture->cTexure.Bind(); // Save texture width for calculating the texture coordinates. You have to // divide the planar texture coords by the width of the texture to get a // correct mapping iTexWidth = pCurTexture->cTexure.GetTexWidth(); } break; } // Current texture is not the requested one, advance to the next pCurTexture = pCurTexture->pNextTexture; } while (pCurTexture); // Stop when there are no more textures // Assign lightmap to the second TMU cMultitexturing.ChoseActiveTMU(GL_TEXTURE1_ARB); m_pLightmaps[iCurFace].cLightmap.Bind(); // Begin drawing the face glBegin(GL_TRIANGLE_FAN); // Loop trough all face edges of the current face for (iCurFaceEdge=0; iCurFaceEdge<m_pFaces[iCurFace].iNumEdges; iCurFaceEdge++) { // Don't read behind the face edge array assert(m_pFaces[iCurFace].lFirstEdge + iCurFaceEdge < m_sCount.iFaceEdgeCount); // Don't read behind the edge array. Drop a possible negative sign // because this is only used to indicate the 'winding' of the edge assert((unsigned long) abs(m_pFaceEdges[m_pFaces[iCurFace].lFirstEdge + iCurFaceEdge]) < m_sCount.iEdgeCount); // Look up the two edge vertex indexes in the edge array iVertex1 = m_pEdges[abs(m_pFaceEdges[m_pFaces[iCurFace].lFirstEdge + iCurFaceEdge])].iVertex1; iVertex2 = m_pEdges[abs(m_pFaceEdges[m_pFaces[iCurFace].lFirstEdge + iCurFaceEdge])].iVertex2; // Reverse the vertex order if (m_pFaceEdges[m_pFaces[iCurFace].lFirstEdge + iCurFaceEdge] > 0) { iTempVertex = iVertex1; iVertex1 = iVertex2; iVertex2 = iTempVertex; } // Texture coordinate for the first vertex fU = (m_pVertices[iVertex1].x * pTexInfo->UAxis.x + m_pVertices[iVertex1].y * pTexInfo->UAxis.y + m_pVertices[iVertex1].z * pTexInfo->UAxis.z + pTexInfo->UOffset) / iTexWidth; fV = (m_pVertices[iVertex1].x * pTexInfo->VAxis.x + m_pVertices[iVertex1].y * pTexInfo->VAxis.y + m_pVertices[iVertex1].z * pTexInfo->VAxis.z + pTexInfo->VOffset) / iTexWidth; // Pass the coordinates for world and lightmap texture cMultitexturing.MultiTexCoord2f(GL_TEXTURE0_ARB, fU, fV); cMultitexturing.MultiTexCoord2f(GL_TEXTURE1_ARB, (float) (m_pLightmaps[iCurFace].cLightmap.GetTexWidth() / 2.0f) + (fU - m_pLightmaps[iCurFace].fMidFaceU) / 16.0f, (float) (m_pLightmaps[iCurFace].cLightmap.GetTexHeight() / 2.0f) + (fV - m_pLightmaps[iCurFace].fMidFaceV) / 16.0f); // Pass the first vertex glVertex3f(m_pVertices[iVertex1].x, m_pVertices[iVertex1].y, m_pVertices[iVertex1].z); // Texture coordinate for the second vertex fU = (m_pVertices[iVertex2].x * pTexInfo->UAxis.x + m_pVertices[iVertex2].y * pTexInfo->UAxis.y + m_pVertices[iVertex2].z * pTexInfo->UAxis.z + pTexInfo->UOffset) / iTexWidth; fV = (m_pVertices[iVertex2].x * pTexInfo->VAxis.x + m_pVertices[iVertex2].y * pTexInfo->VAxis.y + m_pVertices[iVertex2].z * pTexInfo->VAxis.z + pTexInfo->VOffset) / iTexWidth; // Pass the texture coordinates for world and lightmap texture cMultitexturing.MultiTexCoord2f(GL_TEXTURE0_ARB, fU, fV); cMultitexturing.MultiTexCoord2f(GL_TEXTURE1_ARB, (float) (m_pLightmaps[iCurFace].cLightmap.GetTexWidth() / 2.0f) + (fU - m_pLightmaps[iCurFace].fMidFaceU) / 16.0f, (float) (m_pLightmaps[iCurFace].cLightmap.GetTexHeight() / 2.0f) + (fV - m_pLightmaps[iCurFace].fMidFaceV) / 16.0f); // Pass the second vertex glVertex3f(m_pVertices[iVertex2].x, m_pVertices[iVertex2].y, m_pVertices[iVertex2].z); } // Finished drawing the face glEnd();
}
// Restore previous rendering state and finish display list
glPopAttrib();
glEndList();
}bool CBSP::LoadBSP(PSTR pszFileName, PSTR pszTexturePath, PSTR pszPalettePath)
{
////////////////////////////////////////////////////////////////////////
// Load a Q2 BSP file
////////////////////////////////////////////////////////////////////////FILE *hFile = 0; // File handle for the BSP file
BSP_Header sHeader; // Header of the BSP file
CProgressWindow cLoadingStatus; // Progress window to show loading status// Create the progress window. The progress bar is accessed trough a
// static member function. The window is automatically destroied when the
// object goes out of scope
cLoadingStatus.CreateProgressWindow(“Loading Quake 2 BSP File”);// Open the file in binary mode
hFile = fopen(pszFileName, “rb”);if (!hFile)
{
assert(hFile);
return false;
}////////////////////////////////////////////////////////////////////////
// Read header and lump informations
////////////////////////////////////////////////////////////////////////// Read header with lump informations
SaveRead(&sHeader, sizeof(BSP_Header), 1, hFile);// Is the file a BSP file ?
if (sHeader.szMagic[0] != ‘I’ | |
sHeader.szMagic[1] != ‘B’ | |
sHeader.szMagic[2] != ‘S’ | |
sHeader.szMagic[3] != ‘P’)
{
// Wrong ‘magic’, no BSP file !
assert(sHeader.szMagic[0] == ‘I’);
fclose(hFile);
return false;
}// Do we load the correct BSP file version ?
if (sHeader.lVersion != 38)
{
// Wrong BSP version, probably Q3 or a modified Q2 engine game
assert(sHeader.lVersion == 38);
fclose(hFile);
return false;
}// Obtain the item count for the lumps
GetItemCount(&sHeader, &m_sCount);////////////////////////////////////////////////////////////////////////
// Allocate memory
////////////////////////////////////////////////////////////////////////m_pVertices = new Point3f[m_sCount.iVertexCount]; // Vertices
m_pEdges = new BSP_Edge[m_sCount.iEdgeCount]; // Edges
m_pFaces = new BSP_Face[m_sCount.iFaceCount]; // Faces
m_pFaceEdges = new long int[m_sCount.iFaceEdgeCount]; // Face edges
m_pPlanes = new BSP_Plane[m_sCount.iPlaneCount]; // Planes
m_pNodes = new BSP_Node[m_sCount.iNodeCount]; // Nodes
m_pLeaves = new BSP_Leaf[m_sCount.iLeafCount]; // Leaves
m_pLeafFaces = new unsigned short int[m_sCount.iLeafFaceCount]; // Leaf faces
m_pTexInfos = new BSP_TexInfo[m_sCount.iTexInfoCount]; // Texture informations
m_pLightmaps = new BSP_Lightmap[m_sCount.iFaceCount]; // Lightmaps////////////////////////////////////////////////////////////////////////
// Load all needed lumb data
////////////////////////////////////////////////////////////////////////// Load all vertices
SeekToLump(L_VERTICES, &sHeader, hFile);
SaveRead(m_pVertices, sizeof(m_pVertices[0]), m_sCount.iVertexCount, hFile);
// Load all edges
SeekToLump(L_EDGES, &sHeader, hFile);
SaveRead(m_pEdges, sizeof(m_pEdges[0]), m_sCount.iEdgeCount, hFile);
// Load all faces
SeekToLump(L_FACES, &sHeader, hFile);
SaveRead(m_pFaces, sizeof(m_pFaces[0]), m_sCount.iFaceCount, hFile);
// Load all face edges
SeekToLump(L_FACE_EDGE_TABLE, &sHeader, hFile);
SaveRead(m_pFaceEdges, sizeof(m_pFaceEdges[0]), m_sCount.iFaceEdgeCount, hFile);
// Load all planes
SeekToLump(L_PLANES, &sHeader, hFile);
SaveRead(m_pPlanes, sizeof(m_pPlanes[0]), m_sCount.iPlaneCount, hFile);
// Load all nodes
SeekToLump(L_NODES, &sHeader, hFile);
SaveRead(m_pNodes, sizeof(m_pNodes[0]), m_sCount.iNodeCount, hFile);
// Load all leaves
SeekToLump(L_LEAVES, &sHeader, hFile);
SaveRead(m_pLeaves, sizeof(m_pLeaves[0]), m_sCount.iLeafCount, hFile);
// Load all leaf faces
SeekToLump(L_LEAF_FACE_TABLE, &sHeader, hFile);
SaveRead(m_pLeafFaces, sizeof(m_pLeafFaces[0]), m_sCount.iLeafFaceCount, hFile);
// Load all texture informations
SeekToLump(L_TEXTURE_INFORMATION, &sHeader, hFile);
SaveRead(m_pTexInfos, sizeof(m_pTexInfos[0]), m_sCount.iTexInfoCount, hFile);// Load the textures
if (!LoadTextures(m_pTextures, pszTexturePath, pszPalettePath))
return false;// Load lightmaps
if (!LoadLightmaps(hFile, &sHeader))
return false;////////////////////////////////////////////////////////////////////////
// Close file
////////////////////////////////////////////////////////////////////////fclose(hFile);
return true;
}bool CBSP::LoadLightmaps(FILE *hFile, BSP_Header *pHeader)
{
////////////////////////////////////////////////////////////////////////
// Load the lightmaps from the lightmap lump in the BSP file
////////////////////////////////////////////////////////////////////////unsigned long int iCurFace;
bool bReturn;
unsigned char *pLightmapData = 0;
unsigned int iLightmapWidth, iLightmapHeight;assert(m_pFaces);
assert(m_pTexInfos);
assert(hFile);
assert(pHeader);CProgressWindow::SetTask(“Loading Lightmaps…”);
if (!hFile)
{
assert(hFile);
return false;
}// Allocate space for the lightmaps
pLightmapData = new unsigned char [pHeader->Lump[L_LIGHTMAPS].iLength];// Move the file pointer to the start of the lightmap lump
SeekToLump(L_LIGHTMAPS, pHeader, hFile);// Load the whole lightmap lump out of the file
bReturn = SaveRead(pLightmapData, pHeader->Lump[L_LIGHTMAPS].iLength, 1, hFile);if (!bReturn)
{
delete pLightmapData;
pLightmapData = 0;
return false;
}// Build the lightmap for every face
for (iCurFace=0; iCurFace<m_sCount.iFaceCount; iCurFace++)
{
// Display status
CProgressWindow::SetProgress(iCurFace * 100 / m_sCount.iFaceCount);// Calculate the size of the lightmap. The average texture coordinate is // also returned and in the lightmap array GetLightmapSize(iCurFace, &iLightmapWidth, &iLightmapHeight, &m_pLightmaps[iCurFace].fMidFaceU, &m_pLightmaps[iCurFace].fMidFaceV); // Create a texture from the data stored in pLightmapData. The lightmap's // offset in the file is the same as in the array bReturn = m_pLightmaps[iCurFace].cLightmap.LoadTextureArray (&pLightmapData[m_pFaces[iCurFace].lLightmapOffset], iLightmapWidth, iLightmapHeight); assert(bReturn);
}
// Clean up
delete pLightmapData;
pLightmapData = 0;return true;
}void CBSP::GetLightmapSize(unsigned int iFace, unsigned int *pWidth,
unsigned int *pHeight, float *fMidFaceU,
float *fMidFaceV)
{
////////////////////////////////////////////////////////////////////////
// Calculate the size of a lightmap for a face. Also return the average
// texture coordinate for the lightmap’s face, it will be stored with
// the lightmap
////////////////////////////////////////////////////////////////////////float fU, fV;
float fMinU = (float) +3.4E38, fMaxU = (float) -3.4E38;
float fMinV = (float) +3.4E38, fMaxV = (float) -3.4E38;
unsigned int iCurFaceEdge;
int iVertex1, iVertex2;
BSP_TexInfo *pTexInfo = 0;assert(m_pTexInfos);
assert(m_pFaceEdges);
assert(m_pFaces);
assert(m_pVertices);
assert(pWidth);
assert(pHeight);
assert(fMidFaceU);
assert(fMidFaceV);// Save ‘shortcut’ pointer to access the texture informations
pTexInfo = &m_pTexInfos[m_pFaces[iFace].iTexInfo];// Loop trough all face edges of the face
for (iCurFaceEdge=0; iCurFaceEdge<m_pFaces[iFace].iNumEdges; iCurFaceEdge++)
{
// Look up the two edge vertex indexes in the edge array
iVertex1 = m_pEdges[abs(m_pFaceEdges[m_pFaces[iFace].lFirstEdge +
iCurFaceEdge])].iVertex1;
iVertex2 = m_pEdges[abs(m_pFaceEdges[m_pFaces[iFace].lFirstEdge +
iCurFaceEdge])].iVertex2;// Texture coordinate for the first vertex fU = (m_pVertices[iVertex1].x * pTexInfo->UAxis.x + m_pVertices[iVertex1].y * pTexInfo->UAxis.y + m_pVertices[iVertex1].z * pTexInfo->UAxis.z + pTexInfo->UOffset); fV = (m_pVertices[iVertex1].x * pTexInfo->VAxis.x + m_pVertices[iVertex1].y * pTexInfo->VAxis.y + m_pVertices[iVertex1].z * pTexInfo->VAxis.z + pTexInfo->VOffset); // Have we found a new smallest / biggest texture coordinate ? fMinU = __min(fMinU, fU); fMaxU = __max(fMaxU, fU); fMinV = __min(fMinV, fV); fMaxV = __max(fMaxV, fV); // Texture coordinate for the second vertex fU = (m_pVertices[iVertex2].x * pTexInfo->UAxis.x + m_pVertices[iVertex2].y * pTexInfo->UAxis.y + m_pVertices[iVertex2].z * pTexInfo->UAxis.z + pTexInfo->UOffset); fV = (m_pVertices[iVertex2].x * pTexInfo->VAxis.x + m_pVertices[iVertex2].y * pTexInfo->VAxis.y + m_pVertices[iVertex2].z * pTexInfo->VAxis.z + pTexInfo->VOffset); // Have we found a new smallest / biggest texture coordinate ? fMinU = __min(fMinU, fU); fMaxU = __max(fMaxU, fU); fMinV = __min(fMinV, fV); fMaxV = __max(fMaxV, fV);
}
// We know the min. and max. UV coordinates. Now calculate the lightmap size and
// store it in the passed pointers
*pWidth = (unsigned int) ceil(fMaxU / 16.0f) -
(unsigned int) floor(fMinU / 16.0f) + 1;
*pHeight = (unsigned int) ceil(fMaxV / 16.0f) -
(unsigned int) floor(fMinV / 16.0f) + 1;// Calculate the average texture coordinate
*fMidFaceU = (fMinU + fMaxU) / 2.0f;
*fMidFaceV = (fMinV + fMaxV) / 2.0f;// Quake 2 BSP don’t allow lightmaps larger than 16x16
if (*pWidth > 16)
*pWidth = 16;
if (*pHeight > 16)
*pHeight = 16;
}bool CBSP::LoadTextures(BSP_Texture *&pHeadNode, PSTR pszTexturePath, PSTR pszPalettePath)
{
////////////////////////////////////////////////////////////////////////
// Load texture information and store the in the linked-list
////////////////////////////////////////////////////////////////////////char szTexturePath[_MAX_PATH]; // Buffer to store the full path of a texture
unsigned int i;
bool bAdd = true;
BSP_Texture *pCurTexture = 0, *pTex = 0;assert(m_pTexInfos);
CProgressWindow::SetTask(“Loading Textures…”);
// Allocate memory for the head node of the texture linked-list
pHeadNode = new BSP_Texture;
pHeadNode->pNextTexture = 0;// Load all textures and add them to the list
for (i=0; i<m_sCount.iTexInfoCount; i++)
{
// Display status
CProgressWindow::SetProgress(i * 100 / m_sCount.iTexInfoCount);// Is the texture a new texture ? pTex = pHeadNode; bAdd = true; do { assert(pTex); // Is the current texture equal to the one we are about to add ? if (_stricmp(pTex->szTextureName, m_pTexInfos[i].szTextureName) == 0) { // Texture already exists bAdd = false; break; } // Advance to the next texture pTex = pTex->pNextTexture; } while (pTex); // Skip this entry if we already added the texture if (!bAdd) continue; // First take the base path of all textures szTexturePath[0] = '\0'; strcpy(szTexturePath, pszTexturePath); // Add slash to the texture path (if needed) if (szTexturePath[strlen(szTexturePath)] != '/' | | szTexturePath[strlen(szTexturePath)] != '\\') { strcat(szTexturePath, "/"); } // Add the relative texture pathname strcat(szTexturePath, m_pTexInfos[i].szTextureName); // Add the .WAL extension strcat(szTexturePath, ".WAL"); // Is this the first node ? if (i == 0) { // Fill the first node // Load the texture if (!pHeadNode->cTexure.LoadWALTexture (szTexturePath, pszPalettePath)) return false; // Store the texture name in the linked-list strcpy(pHeadNode->szTextureName, m_pTexInfos[i].szTextureName); // Set current node pointer to the first node pCurTexture = pHeadNode; } else { // Add a node assert(pCurTexture); // Allocate memory for the node pCurTexture->pNextTexture = new BSP_Texture; // Save the new node in the current node pointer pCurTexture = pCurTexture->pNextTexture; // Load the texture if (!pCurTexture->cTexure.LoadWALTexture (szTexturePath, pszPalettePath)) return false; // Store the texture name in the linked-list strcpy(pCurTexture->szTextureName, m_pTexInfos[i].szTextureName); // Set the next node pointer to zero pCurTexture->pNextTexture = 0; }
}
return true;
}bool CBSP::SaveRead(void *buffer, size_t size, size_t count, FILE *stream)
{
////////////////////////////////////////////////////////////////////////
// Performs a normal fread operations and makes sure that all items
// have been read
////////////////////////////////////////////////////////////////////////size_t iReadCount;
// Perform the fread() call
iReadCount = fread(buffer, size, count, stream);// Verify the number of succesfully read items
if (iReadCount == count)
{
return true;
}
else
{
// Insufficient amount of items read
assert(iReadCount == count);
return false;
}
}void CBSP::SeekToLump(unsigned int iLumpIndex, BSP_Header *pHeader, FILE *hFile)
{
////////////////////////////////////////////////////////////////////////
// Place the file pointer at the start of a given lump
////////////////////////////////////////////////////////////////////////int iSeekReturn;
assert(pHeader);
assert(hFile);iSeekReturn = fseek(hFile, pHeader->Lump[iLumpIndex].iOffset, SEEK_SET);
assert(iSeekReturn == 0);
}void CBSP::GetItemCount(BSP_Header *pHeader, BSP_LumpCount *pLumpCount)
{
////////////////////////////////////////////////////////////////////////
// Calculate the count of items in a lump
////////////////////////////////////////////////////////////////////////// Initialize and verify data
assert(pHeader);
assert(pLumpCount);
memset(pLumpCount, 0, sizeof(BSP_LumpCount));// Calculate the amount of vertices
pLumpCount->iVertexCount =
pHeader->Lump[L_VERTICES].iLength / sizeof(Point3f);
assert(pLumpCount->iVertexCount > 0);// Calculate the amount of edges
pLumpCount->iEdgeCount =
pHeader->Lump[L_EDGES].iLength / (sizeof(BSP_Edge));
assert(pLumpCount->iEdgeCount > 0);// Calculate the amount of faces
pLumpCount->iFaceCount =
pHeader->Lump[L_FACES].iLength / sizeof(BSP_Face);
assert(pLumpCount->iFaceCount > 0);// Calculate the amount of face edges
pLumpCount->iFaceEdgeCount =
pHeader->Lump[L_FACE_EDGE_TABLE].iLength / sizeof(long int);
assert(pLumpCount->iFaceEdgeCount > 0);// Calculate the amount of planes
pLumpCount->iPlaneCount =
pHeader->Lump[L_PLANES].iLength / sizeof(BSP_Plane);
assert(pLumpCount->iPlaneCount > 0);// Calculate the amount of nodes
pLumpCount->iNodeCount =
pHeader->Lump[L_NODES].iLength / sizeof(BSP_Node);
assert(pLumpCount->iNodeCount > 0);// Calculate the amount of leaves
pLumpCount->iLeafCount =
pHeader->Lump[L_LEAVES].iLength / sizeof(BSP_Leaf);
assert(pLumpCount->iLeafCount > 0);// Calculate the amount of leaf faces
pLumpCount->iLeafFaceCount =
pHeader->Lump[L_LEAF_FACE_TABLE].iLength / sizeof(short int);
assert(pLumpCount->iLeafFaceCount > 0);// Calculate the amount of texture informations
pLumpCount->iTexInfoCount =
pHeader->Lump[L_TEXTURE_INFORMATION].iLength / sizeof(BSP_TexInfo);
assert(pLumpCount->iTexInfoCount > 0);
}