📄 quake3bsp.cpp
字号:
#include "Main.h"
#include "Camera.h"
#include "Quake3Bsp.h"
#include "Frustum.h"
// This is our maximum height that the user can climb over
const float kMaxStepHeight = 10.0f;
// We use the camera in our TryToStep() function so we extern the global camera
extern CCamera g_Camera;
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
// This is our global frustum class, which is used to cull BSP leafs
extern CFrustum g_Frustum;
// This will store how many faces are drawn and are seen by the camera
extern int g_VisibleFaces;
// This tells us if we want to render the lightmaps
extern bool g_bLightmaps;
// This holds the gamma value that was stored in the config file
extern float g_Gamma;
// This tells us if we want to render the textures
extern bool g_bTextures;
//////////////////////////// CQUAKE3BSP \\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
///// This is our object's constructor to initial all it's data members
/////
//////////////////////////// CQUAKE3BSP \\\\\\\\\\\\\\\\\\\\\\\\\\\*
CQuake3BSP::CQuake3BSP()
{
// Here we simply initialize our member variables to 0
m_numOfVerts = 0;
m_numOfFaces = 0;
m_numOfIndices = 0;
m_numOfTextures = 0;
m_numOfLightmaps = 0;
m_numOfNodes = 0;
m_numOfLeafs = 0;
m_numOfLeafFaces = 0;
m_numOfPlanes = 0;
m_numOfBrushes = 0;
m_numOfBrushSides = 0;
m_numOfLeafBrushes = 0;
m_traceRatio = 0;
m_traceType = 0;
m_traceRadius = 0;
bool m_bCollided = false;
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
// Initialize our variables to start off
bool m_bGrounded = false;
bool m_bTryStep = false;
/////// * /////////// * /////////// * NEW * /////// * /////////// * /////////// *
// We need to initialize our Min and Max and Extent variables
m_vTraceMins = CVector3(0, 0, 0);
m_vTraceMaxs = CVector3(0, 0, 0);
m_vExtents = CVector3(0, 0, 0);
// This will store the normal of the plane we collided with
m_vCollisionNormal = CVector3(0, 0, 0);
// Initialize all the dynamic BSP data pointers to NULL
m_pVerts = NULL;
m_pFaces = NULL;
m_pIndices = NULL;
m_pNodes = NULL;
m_pLeafs = NULL;
m_pPlanes = NULL;
m_pLeafFaces = NULL;
memset(&m_clusters, 0, sizeof(tBSPVisData));
// Here we initialize our dynamic arrays of data for the brush information of the BSP
m_pBrushes = NULL;
m_pBrushSides = NULL;
m_pTextures = NULL;
m_pLeafBrushes = NULL;
}
//////////////////////////// CHANGE GAMMA \\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
///// This manually changes the gamma of an image
/////
//////////////////////////// CHANGE GAMMA \\\\\\\\\\\\\\\\\\\\\\\\\\\*
void CQuake3BSP::ChangeGamma(byte *pImage, int size, float factor)
{
// Go through every pixel in the lightmap
for(int i = 0; i < size / 3; i++, pImage += 3)
{
float scale = 1.0f, temp = 0.0f;
float r = 0, g = 0, b = 0;
// extract the current RGB values
r = (float)pImage[0];
g = (float)pImage[1];
b = (float)pImage[2];
// Multiply the factor by the RGB values, while keeping it to a 255 ratio
r = r * factor / 255.0f;
g = g * factor / 255.0f;
b = b * factor / 255.0f;
// Check if the the values went past the highest value
if(r > 1.0f && (temp = (1.0f/r)) < scale) scale=temp;
if(g > 1.0f && (temp = (1.0f/g)) < scale) scale=temp;
if(b > 1.0f && (temp = (1.0f/b)) < scale) scale=temp;
// Get the scale for this pixel and multiply it by our pixel values
scale*=255.0f;
r*=scale; g*=scale; b*=scale;
// Assign the new gamma'nized RGB values to our image
pImage[0] = (byte)r;
pImage[1] = (byte)g;
pImage[2] = (byte)b;
}
}
////////////////////////////// CREATE LIGHTMAP TEXTURE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
///// This creates a texture map from the light map image bits
/////
////////////////////////////// CREATE LIGHTMAP TEXTURE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
void CQuake3BSP::CreateLightmapTexture(UINT &texture, byte *pImageBits, int width, int height)
{
// Generate a texture with the associative texture ID stored in the array
glGenTextures(1, &texture);
// This sets the alignment requirements for the start of each pixel row in memory.
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
// Bind the texture to the texture arrays index and init the texture
glBindTexture(GL_TEXTURE_2D, texture);
// Change the lightmap gamma values by our desired gamma
ChangeGamma(pImageBits, width*height*3, g_Gamma);
// Build Mipmaps (builds different versions of the picture for distances - looks better)
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB, GL_UNSIGNED_BYTE, pImageBits);
//Assign the mip map levels
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
//////////////////////////// FIND TEXTURE EXTENSION \\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
///// This attaches the image extension to the texture name, if found
/////
//////////////////////////// FIND TEXTURE EXTENSION \\\\\\\\\\\\\\\\\\\\\\\\\\\*
void CQuake3BSP::FindTextureExtension(char *strFileName)
{
char strJPGPath[MAX_PATH] = {0};
char strTGAPath[MAX_PATH] = {0};
FILE *fp = NULL;
// Get the current path we are in
GetCurrentDirectory(MAX_PATH, strJPGPath);
// Add on a '\' and the file name to the end of the current path.
// We create 2 seperate strings to test each image extension.
strcat(strJPGPath, "\\");
strcat(strJPGPath, strFileName);
strcpy(strTGAPath, strJPGPath);
// Add the extensions on to the file name and path
strcat(strJPGPath, ".jpg");
strcat(strTGAPath, ".tga");
// Check if there is a jpeg file with the texture name
if((fp = fopen(strJPGPath, "rb")) != NULL)
{
// If so, then let's add ".jpg" onto the file name and return
strcat(strFileName, ".jpg");
return;
}
// Check if there is a targa file with the texture name
if((fp = fopen(strTGAPath, "rb")) != NULL)
{
// If so, then let's add a ".tga" onto the file name and return
strcat(strFileName, ".tga");
return;
}
}
//////////////////////////// LOAD BSP \\\\\\\\\\\\\\\\\\\\\\\\\\\*
/////
///// This loads in all of the .bsp data for the level
/////
//////////////////////////// LOAD BSP \\\\\\\\\\\\\\\\\\\\\\\\\\\*
bool CQuake3BSP::LoadBSP(const char *strFileName)
{
FILE *fp = NULL;
int i = 0;
// Check if the .bsp file could be opened
if((fp = fopen(strFileName, "rb")) == NULL)
{
// Display an error message and quit if the file can't be found.
MessageBox(g_hWnd, "Could not find BSP file!", "Error", 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);
// Now we know all the information about our file. We can
// then allocate the needed memory for our member variables.
// Allocate the 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 the index memory
m_numOfIndices = lumps[kIndices].length / sizeof(int);
m_pIndices = new int [m_numOfIndices];
// Allocate memory to read in the texture information.
m_numOfTextures = lumps[kTextures].length / sizeof(tBSPTexture);
m_pTextures = new tBSPTexture [m_numOfTextures];
// Allocate memory to read in the lightmap data.
m_numOfLightmaps = lumps[kLightmaps].length / sizeof(tBSPLightmap);
tBSPLightmap *pLightmaps = new tBSPLightmap [m_numOfLightmaps ];
// Seek to the position in the file that stores the vertex information
fseek(fp, lumps[kVertices].offset, SEEK_SET);
// Go through all of the vertices that need to be read and swap axis's
for(i = 0; i < m_numOfVerts; i++)
{
// Read in the current vertex
fread(&m_pVerts[i], 1, sizeof(tBSPVertex), fp);
// Swap the y and z values, and negate the new z so Y is up.
float temp = m_pVerts[i].vPosition.y;
m_pVerts[i].vPosition.y = m_pVerts[i].vPosition.z;
m_pVerts[i].vPosition.z = -temp;
}
// Seek to the position in the file that stores the index information
fseek(fp, lumps[kIndices].offset, SEEK_SET);
// Read in all the index information
fread(m_pIndices, m_numOfIndices, sizeof(int), fp);
// Seek to the position in the file that stores the face information
fseek(fp, lumps[kFaces].offset, SEEK_SET);
// Read in all the face information
fread(m_pFaces, m_numOfFaces, sizeof(tBSPFace), fp);
// Seek to the position in the file that stores the texture information
fseek(fp, lumps[kTextures].offset, SEEK_SET);
// Read in all the texture information
fread(m_pTextures, m_numOfTextures, sizeof(tBSPTexture), fp);
// Go through all of the textures
for(i = 0; i < m_numOfTextures; i++)
{
// Find the extension if any and append it to the file name
FindTextureExtension(m_pTextures[i].strName);
// Create a texture from the image
CreateTexture(m_textures[i], m_pTextures[i].strName);
}
// Seek to the position in the file that stores the lightmap information
fseek(fp, lumps[kLightmaps].offset, SEEK_SET);
// Go through all of the lightmaps and read them in
for(i = 0; i < m_numOfLightmaps ; i++)
{
// Read in the RGB data for each lightmap
fread(&pLightmaps[i], 1, sizeof(tBSPLightmap), fp);
// Create a texture map for each lightmap that is read in. The lightmaps
// are always 128 by 128.
CreateLightmapTexture(m_lightmaps[i],
(unsigned char *)pLightmaps[i].imageBits, 128, 128);
}
// Delete the image bits because we are already done with them
delete [] pLightmaps;
// Store the number of nodes and allocate the memory to hold them
m_numOfNodes = lumps[kNodes].length / sizeof(tBSPNode);
m_pNodes = new tBSPNode [m_numOfNodes];
// Seek to the position in the file that hold the nodes and store them in m_pNodes
fseek(fp, lumps[kNodes].offset, SEEK_SET);
fread(m_pNodes, m_numOfNodes, sizeof(tBSPNode), fp);
// Store the number of leafs and allocate the memory to hold them
m_numOfLeafs = lumps[kLeafs].length / sizeof(tBSPLeaf);
m_pLeafs = new tBSPLeaf [m_numOfLeafs];
// Seek to the position in the file that holds the leafs and store them in m_pLeafs
fseek(fp, lumps[kLeafs].offset, SEEK_SET);
fread(m_pLeafs, m_numOfLeafs, sizeof(tBSPLeaf), fp);
// Now we need to go through and convert all the leaf bounding boxes
// to the normal OpenGL Y up axis.
for(i = 0; i < m_numOfLeafs; i++)
{
// Swap the min y and z values, then negate the new Z
int temp = m_pLeafs[i].min.y;
m_pLeafs[i].min.y = m_pLeafs[i].min.z;
m_pLeafs[i].min.z = -temp;
// Swap the max y and z values, then negate the new Z
temp = m_pLeafs[i].max.y;
m_pLeafs[i].max.y = m_pLeafs[i].max.z;
m_pLeafs[i].max.z = -temp;
}
// Store the number of leaf faces and allocate the memory for them
m_numOfLeafFaces = lumps[kLeafFaces].length / sizeof(int);
m_pLeafFaces = new int [m_numOfLeafFaces];
// Seek to the leaf faces lump, then read it's data
fseek(fp, lumps[kLeafFaces].offset, SEEK_SET);
fread(m_pLeafFaces, m_numOfLeafFaces, sizeof(int), fp);
// Store the number of planes, then allocate memory to hold them
m_numOfPlanes = lumps[kPlanes].length / sizeof(tBSPPlane);
m_pPlanes = new tBSPPlane [m_numOfPlanes];
// Seek to the planes lump in the file, then read them into m_pPlanes
fseek(fp, lumps[kPlanes].offset, SEEK_SET);
fread(m_pPlanes, m_numOfPlanes, sizeof(tBSPPlane), fp);
// Go through every plane and convert it's normal to the Y-axis being up
for(i = 0; i < m_numOfPlanes; i++)
{
float temp = m_pPlanes[i].vNormal.y;
m_pPlanes[i].vNormal.y = m_pPlanes[i].vNormal.z;
m_pPlanes[i].vNormal.z = -temp;
}
// Seek to the position in the file that holds the visibility lump
fseek(fp, lumps[kVisData].offset, SEEK_SET);
// Check if there is any visibility information first
if(lumps[kVisData].length)
{
// Read in the number of vectors and each vector's size
fread(&(m_clusters.numOfClusters), 1, sizeof(int), fp);
fread(&(m_clusters.bytesPerCluster), 1, sizeof(int), fp);
// Allocate the memory for the cluster bitsets
int size = m_clusters.numOfClusters * m_clusters.bytesPerCluster;
m_clusters.pBitsets = new byte [size];
// Read in the all the visibility bitsets for each cluster
fread(m_clusters.pBitsets, 1, sizeof(byte) * size, fp);
}
// Otherwise, we don't have any visibility data (prevents a crash)
else
m_clusters.pBitsets = NULL;
// Like we do for other data, we read get the size of brushes and allocate memory
m_numOfBrushes = lumps[kBrushes].length / sizeof(int);
m_pBrushes = new tBSPBrush [m_numOfBrushes];
// Here we read in the brush information from the BSP file
fseek(fp, lumps[kBrushes].offset, SEEK_SET);
fread(m_pBrushes, m_numOfBrushes, sizeof(tBSPBrush), fp);
// Get the size of brush sides, then allocate memory for it
m_numOfBrushSides = lumps[kBrushSides].length / sizeof(int);
m_pBrushSides = new tBSPBrushSide [m_numOfBrushSides];
// Read in the brush sides data
fseek(fp, lumps[kBrushSides].offset, SEEK_SET);
fread(m_pBrushSides, m_numOfBrushSides, sizeof(tBSPBrushSide), fp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -