📄 q3bsp.cpp
字号:
}
DeletePtr(pTga);
return TRUE;
}
//
// Load lightvols
//
boolean CQ3BSP::LoadLightvols(direntry* pEntry)
{
m_dwLightvolCount = pEntry->iLength / sizeof(lightvol_lump);
m_pLightvols = new lightvol_lump[m_dwLightvolCount];
// read the lump
m_pVfs->SeekTo(pEntry->iOffset);
m_pVfs->Read(m_pLightvols, sizeof(lightvol_lump) * m_dwLightvolCount);
return TRUE;
}
//
// Load visdata
//
boolean CQ3BSP::LoadVisdata(direntry* pEntry)
{
// read the lump start
m_pVfs->SeekTo(pEntry->iOffset);
m_pVfs->Read(&m_Visdata, 2 * sizeof(int));
m_dwVisdataCount = m_Visdata.iVectorCount * m_Visdata.iVectorSize;
m_Visdata.pjVecs = new byte[m_dwVisdataCount];
// read the rest of the lump
m_pVfs->Read(m_Visdata.pjVecs, m_dwVisdataCount);
return TRUE;
}
//
// Parse the mapinfo string
//
void CQ3BSP::ParseMapInfo(char *szInfo)
{
#define TOKEN_SIZE 64
#define MAX_CLASSES 20
#define CLASS_LENGTH 128
char* szClasses = new char[MAX_CLASSES * CLASS_LENGTH];
memset(szClasses, 0, MAX_CLASSES * CLASS_LENGTH);
WORD wClassCount = 0;
char c = 0; // current character
DWORD p = 0; // string position
char szToken[TOKEN_SIZE]; // current token
WORD t = 0; // token length
memset(szToken, 0, TOKEN_SIZE); // clear token
//
// Convert the classes into the [MAX_CLASSES][128] format
//
while (szInfo[p])
{
c = szInfo[p];
if (c == '{')
{
// new class
p++;
DWORD dwPos = wClassCount * CLASS_LENGTH;
while (szInfo[p] != '}') szClasses[dwPos++] = szInfo[p++];
wClassCount++;
}
p++;
}
//
// Now scan each class and parses tokens and values
//
for (WORD n=0; n<wClassCount; n++)
{
char* pClass = &szClasses[n * CLASS_LENGTH];
char *pSubClass = NULL;
//
//
// Check for "info_player_start" and "info_player_deathmatch"
//
//
if (STRSTR((const char*)pClass, "info_player_start") || STRSTR((const char*)pClass, "info_player_deathmatch"))
{
// player initial position
pSubClass = STRSTR((const char*)pClass, "origin");
if (pSubClass)
{
while (*pSubClass != ' ') pSubClass++;
while (*pSubClass != '"') pSubClass++;
pSubClass++;
//
// get the origin values
//
// get X
t = 0;
memset(szToken, 0, TOKEN_SIZE);
while (*pSubClass != ' ' && *pSubClass != '"') szToken[t++] = *pSubClass++;
m_Origin[0] = ITOX(ATOI(szToken));
pSubClass++;
// get Y
t = 0;
memset(szToken, 0, TOKEN_SIZE);
while (*pSubClass != ' ' && *pSubClass != '"') szToken[t++] = *pSubClass++;
m_Origin[2] = ITOX(-ATOI(szToken));
pSubClass++;
// get Z
t = 0;
memset(szToken, 0, TOKEN_SIZE);
while (*pSubClass != ' ' && *pSubClass != '"') szToken[t++] = *pSubClass++;
m_Origin[1] = ITOX(ATOI(szToken));
}
// try to get player's initial angle
pSubClass = STRSTR((const char*)pClass, "angle");
if (pSubClass)
{
while (*pSubClass != ' ') pSubClass++;
while (*pSubClass != '"') pSubClass++;
pSubClass++;
t = 0;
memset(szToken, 0, TOKEN_SIZE);
while (*pSubClass != ' ' && *pSubClass != '"') szToken[t++] = *pSubClass++;
m_iAngle = ITOX(ATOI(szToken) + 270);
}
} // end if "info_player_start" || "info_player_deathmatch"
} // end for (wClassCount)
DeletePtrArray(szClasses);
}
//
// Return the info_player_start
//
void CQ3BSP::GetInfoPlayerStart(vec3_t v)
{
VectorCopy(m_Origin, v);
}
//
// return the player initial angle
//
int CQ3BSP::InfoPlayerStartAngle()
{
return m_iAngle;
}
//
// Find leaf where the camera is
//
int CQ3BSP::FindLeaf(CCamera* pCam)
{
node_lump* pNode;
plane_lump* pPlane;
int iIdx;
float fDot;
iIdx = 0;
while (iIdx >= 0) // if idx < 0 we have found a leaf.
{
pNode = &m_pNodes[iIdx];
pPlane = m_pPlanes + pNode->iPlane;
// ### definitely not optimal
vec3f_t v =
{
XTOF(pCam->Position()[0]),
XTOF(-pCam->Position()[2]),
XTOF(pCam->Position()[1])
};
fDot = DotProductf(v, pPlane->vNormal) - pPlane->fDist;
if (fDot >= 0.0f)
iIdx = pNode->iChildren[0]; // front
else
iIdx = pNode->iChildren[1]; // back
}
return ~iIdx;
}
//
// Convert to opengl-es format
//
void CQ3BSP::ConvertToFast(void)
{
DWORD f = 0;
// allocate fast faces for the entire bsp
m_FastBSP.pFaces = new fast_face[m_dwFaceCount];
// allocate vertices for the entire bsp
m_FastBSP.pVertices = new int[m_dwVertexCount * 3];
m_FastBSP.pTexCoords = new dword[m_dwVertexCount * 2];
m_FastBSP.pLitCoords = new dword[m_dwVertexCount * 2];
m_FastBSP.pColValues = new dword[m_dwVertexCount * 4];
// transfer the original faces to the fast faces
for (f=0; f<m_dwFaceCount; f++)
{
// get a pointer to the face
face_lump* pFace = &m_pFaces[f];
// get a pointer to the first meshvert of this face
meshvert_lump* pMeshVert = &m_pMeshVerts[pFace->iMeshVert];
// calculate number of triangles that form this face polygon
WORD wTriCount = pFace->iMeshVertCount / 3;
// allocate triangles for the face polygon
m_FastBSP.pFaces[f].iType = pFace->iType;
m_FastBSP.pFaces[f].wTriCount = wTriCount;
m_FastBSP.pFaces[f].iTextureIndex = pFace->iTexture;
m_FastBSP.pFaces[f].iLightmapIndex = pFace->iLm;
m_FastBSP.pFaces[f].pTris = new word[wTriCount * 3];
m_FastBSP.pFaces[f].dwFrame = 0;
// convert the polygon into triangles
WORD wVert = 0;
WORD wCurTri = 0;
for (WORD t=0; t<wTriCount; t++)
{
m_FastBSP.pFaces[f].pTris[wCurTri + 2] = pFace->iVertex + pMeshVert[wVert++].iOffset;
m_FastBSP.pFaces[f].pTris[wCurTri + 1] = pFace->iVertex + pMeshVert[wVert++].iOffset;
m_FastBSP.pFaces[f].pTris[wCurTri + 0] = pFace->iVertex + pMeshVert[wVert++].iOffset;
wCurTri += 3;
}
}
// transfer the original vertices to the fast vertices
DWORD dwVIndex = 0;
DWORD dwTIndex = 0;
DWORD dwCIndex = 0;
for (f=0; f<m_dwVertexCount; f++)
{
vertex_lump* pVertex = &m_pVertices[f];
// convert vertex
m_FastBSP.pVertices[dwVIndex++] = FTOX(pVertex->fPosition[0]);
m_FastBSP.pVertices[dwVIndex++] = FTOX(pVertex->fPosition[2]);
m_FastBSP.pVertices[dwVIndex++] = -FTOX(pVertex->fPosition[1]);
// convert main texture uv
m_FastBSP.pTexCoords[dwTIndex+0] = FTOX(pVertex->fTexCoord[0][0]);
m_FastBSP.pTexCoords[dwTIndex+1] = FTOX(pVertex->fTexCoord[0][1]);
// convert lightmap uv
m_FastBSP.pLitCoords[dwTIndex+0] = FTOX(pVertex->fTexCoord[1][0]);
m_FastBSP.pLitCoords[dwTIndex+1] = FTOX(pVertex->fTexCoord[1][1]);
// convert RGBA color
m_FastBSP.pColValues[dwCIndex+0] = ITOX(pVertex->jColor[0]);
m_FastBSP.pColValues[dwCIndex+1] = ITOX(pVertex->jColor[1]);
m_FastBSP.pColValues[dwCIndex+2] = ITOX(pVertex->jColor[2]);
m_FastBSP.pColValues[dwCIndex+3] = ITOX(pVertex->jColor[3]);
dwTIndex += 2;
dwCIndex += 4;
}
}
//
//
//
boolean CQ3BSP::IsClusterVisible(int iFromLeaf, int iToLeaf)
{
#if 0
return TRUE;
#else
leaf_lump* pFromLeaf = &m_pLeafs[iFromLeaf];
leaf_lump* pToLeaf = &m_pLeafs[iToLeaf];
if (!m_Visdata.pjVecs || pFromLeaf->iCluster < 0)
return TRUE;
int i = (pFromLeaf->iCluster * m_Visdata.iVectorSize) + (pToLeaf->iCluster >> 3);
byte jVisSet = m_Visdata.pjVecs[i];
return (jVisSet & (1 << (pToLeaf->iCluster & 7))) != 0;
#endif
}
//
//
//
void CQ3BSP::WalkTree(CCamera* pCam, int iNode, int iCamNode)
{
if (iNode >= 0)
{
// node
WalkTree(pCam, m_pNodes[iNode].iChildren[0], iCamNode); // front node
WalkTree(pCam, m_pNodes[iNode].iChildren[1], iCamNode); // back node
}
else
{
// leaf
int iLeaf = ~iNode;
if (IsClusterVisible(iCamNode, iLeaf))
{
leaf_lump* pLeaf = &m_pLeafs[iLeaf];
if (pCam->IsBoxVisible(pLeaf->iMin, pLeaf->iMax))
RenderLeaf(iLeaf);
}
}
}
//
// Render BSP
//
void CQ3BSP::Render(CCamera* pCam)
{
// load camera projection view matrix
glMatrixMode(GL_PROJECTION);
glLoadMatrixx(pCam->ProjectionMatrix().m);
// switch back to model view matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// rotate world in camera space
vec3_t r; VectorCopy(pCam->Rotation(), r);
glRotatex(-r[0], 1,0,0);
glRotatex(-r[1], 0,1,0);
glRotatex(-r[2], 0,0,1);
// translate world in camera space
vec3_t p; VectorCopy(pCam->Position(), p);
glTranslatex(-p[0], -p[1], -p[2]);
//
// change states for rendering
//
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FIXED, 0, m_FastBSP.pVertices);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FIXED, 0, m_FastBSP.pColValues);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//
// render current cluster
//
int iCamLeaf = FindLeaf(pCam);
RenderLeaf(iCamLeaf);
WalkTree(pCam, 0, iCamLeaf);
m_dwFrame++;
}
//
// Render a leaf tree
//
void CQ3BSP::RenderLeaf(int iLeaf)
{
//
// render the specified leaf
//
leaf_lump* pLeaf = &m_pLeafs[iLeaf];
DWORD dwStart = pLeaf->iLeafFace;
DWORD dwEnd = dwStart + pLeaf->iLeafFaceCount;
for (DWORD f=dwStart; f<dwEnd; f++)
{
fast_face* pFace = &m_FastBSP.pFaces[m_pLeafFaces[f].iFace];
if (pFace->dwFrame == m_dwFrame) continue;
pFace->dwFrame = m_dwFrame;
word* pTri = pFace->pTris;
#if 1
//
// render solid triangles
//
// face types: 1==polygon, 2==patch, 3==mesh, 4==billboard
switch (pFace->iType)
{
case 1: // polygon
{
// render polygon triangles
glTexCoordPointer(2, GL_FIXED, 0, m_FastBSP.pTexCoords);
glBindTexture(GL_TEXTURE_2D, m_pSurfaces[pFace->iTextureIndex].TexID());
glDrawElements(GL_TRIANGLES, pFace->wTriCount*3, GL_UNSIGNED_SHORT, pTri);
// render lightmap
glEnable(GL_BLEND);
glBlendFunc(GL_ZERO, GL_SRC_COLOR);
glTexCoordPointer(2, GL_FIXED, 0, m_FastBSP.pLitCoords);
CTexture* pLmTex = &m_pLightmapTextures[pFace->iLightmapIndex];
glBindTexture(GL_TEXTURE_2D, pLmTex->TexID());
glDrawElements(GL_TRIANGLES, pFace->wTriCount*3, GL_UNSIGNED_SHORT, pTri);
glDisable(GL_BLEND);
break;
}
case 3: // mesh
{
// render polygon triangles
glTexCoordPointer(2, GL_FIXED, 0, m_FastBSP.pTexCoords);
glBindTexture(GL_TEXTURE_2D, m_pSurfaces[pFace->iTextureIndex].TexID());
glDrawElements(GL_TRIANGLES, pFace->wTriCount*3, GL_UNSIGNED_SHORT, pTri);
break;
}
}
#else
//
// render wireframe triangles
//
glDisable(GL_TEXTURE_2D);
glDrawElements(GL_LINES, pFace->wTriCount*3, GL_UNSIGNED_SHORT, pTri);
#endif
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -