⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 quake3_bsp.cpp

📁 国外游戏开发者杂志2003年第七期配套代码
💻 CPP
字号:
//////////////////////////////////////////////////////////////////////////////////////////
//	BSP.cpp
//	Functions for bsp file
//	You may use this code as you see fit, provided this header is kept intact.
//	Downloaded from: users.ox.ac.uk/~univ1234
//	Created:	8th August 2002
//////////////////////////////////////////////////////////////////////////////////////////	

/* 
   Decimated, shredded, and otherwise modified by Jonathan Blow
   (jon@number-none.com).
*/

#include "framework.h"
#include "quake3_bsp.h"

bool BSP::load(char * filename, int curveTesselation)
{
	FILE * file;

	file=fopen(filename, "rb");
	if(!file)
	{
		printf("Unable to open %s", filename);
		return false;
	}

	//read in header
	fread(&header, sizeof(BSP_HEADER), 1, file);

	//check header data is correct
	if(	header.string[0]!='I' || header.string[1]!='B' ||
		header.string[2]!='S' || header.string[3]!='P' ||
		header.version  !=0x2E )
	{
		printf("%s is not a version 0x2E .bsp map file", filename);
		return false;
	}


	//Load in vertices
	if(!LoadVertices(file))
		return false;

    if (!LoadTextures(file)) return false;


	//Load in mesh indices
	//Calculate number of indices
	int numMeshIndices=header.directoryEntries[bspMeshIndices].length/sizeof(int);

	//Create space
	meshIndices=new int[numMeshIndices];
	if(!meshIndices)
	{
		printf("Unable to allocate memory for %d mesh indices", numMeshIndices);
		return false;
	}

	//read in the mesh indices
	fseek(file, header.directoryEntries[bspMeshIndices].offset, SEEK_SET);
	fread(meshIndices, header.directoryEntries[bspMeshIndices].length, 1, file);

	

	//Load in faces
	if(!LoadFaces(file, curveTesselation))
		return false;


	//Load BSP Data
	if(!LoadBSPData(file))
		return false;


	//Load in entity string
	entityString=new char[header.directoryEntries[bspEntities].length];
	if(!entityString)
	{
		printf(	"Unable to allocate memory for %d length entity string",
								header.directoryEntries[bspEntities].length);
		return false;
	}

	//Go to entity string in file
	fseek(file, header.directoryEntries[bspEntities].offset, SEEK_SET);
	fread(entityString, 1, header.directoryEntries[bspEntities].length, file);

	//Output the entity string
	//errorLog.OutputSuccess("Entity String: %s", entityString);


	fclose(file);

	printf("%s Loaded successfully", filename);

	return true;
}



///////////////////BSP::LoadVertices////////
////////////////////////////////////////////
bool BSP::LoadVertices(FILE * file)
{
	//calculate number of vertices
	numVertices=header.directoryEntries[bspVertices].length/sizeof(BSP_LOAD_VERTEX);

	//Create space for this many BSP_LOAD_VERTICES
	BSP_LOAD_VERTEX * loadVertices=new BSP_LOAD_VERTEX[numVertices];
	if(!loadVertices)
	{
		printf("Unable to allocate memory for %d BSP_LOAD_VERTEXes", numVertices);
		return false;
	}

	//go to vertices in file
	fseek(file, header.directoryEntries[bspVertices].offset, SEEK_SET);

	//read in the vertices
	fread(loadVertices, header.directoryEntries[bspVertices].length, 1, file);

	//Convert to BSP_VERTEXes
	vertices=new BSP_VERTEX[numVertices];
	if(!vertices)
	{
		printf("Unable to allocate memory for vertices");
		return false;
	}

	for(int i=0; i<numVertices; ++i)
	{
		vertices[i].position =loadVertices[i].position;

		vertices[i].decalS=loadVertices[i].decalS;
		vertices[i].decalT=loadVertices[i].decalT;

		vertices[i].lightmapS=loadVertices[i].lightmapS;
		vertices[i].lightmapT=loadVertices[i].lightmapT;
	}

	if(loadVertices)
		delete [] loadVertices;
	loadVertices=NULL;

	return true;
}

bool BSP::LoadFaces(FILE * file, int curveTesselation)
{
	//calculate number of load faces
	numTotalFaces=header.directoryEntries[bspFaces].length/sizeof(BSP_LOAD_FACE);

	//Create space for this many BSP_LOAD_FACES
	BSP_LOAD_FACE * loadFaces=new BSP_LOAD_FACE[numTotalFaces];
	if(!loadFaces)
	{
		printf("Unable to allocate memory for %d BSP_LOAD_FACEs", numTotalFaces);
		return false;
	}

	//go to faces in file
	fseek(file, header.directoryEntries[bspFaces].offset, SEEK_SET);

	//read in the faces
	fread(loadFaces, header.directoryEntries[bspFaces].length, 1, file);


	//Create space for face directory
	faceDirectory=new BSP_FACE_DIRECTORY_ENTRY[numTotalFaces];
	if(!faceDirectory)
	{
		printf(	"Unable to allocate space for face directory with %d entries",
								numTotalFaces);
		return false;
	}
	
	//Clear the face directory
	memset(faceDirectory, 0, numTotalFaces*sizeof(BSP_FACE_DIRECTORY_ENTRY));


	//Calculate how many of each face type there is
	for(int i=0; i<numTotalFaces; ++i)
	{
		if(loadFaces[i].type==bspPolygonFace)
			++numPolygonFaces;
		if(loadFaces[i].type==bspPatch)
			++numPatches;
		if(loadFaces[i].type==bspMeshFace)
			++numMeshFaces;
	}



	//Create space for BSP_POLYGON_FACEs
	polygonFaces=new BSP_POLYGON_FACE[numPolygonFaces];
	if(!polygonFaces)
	{
		printf("Unable To Allocate memory for BSP_POLYGON_FACEs");
		return false;
	}

	int currentFace=0;
	//convert loadFaces to polygonFaces
	for(i=0; i<numTotalFaces; ++i)
	{
		if(loadFaces[i].type!=bspPolygonFace)		//skip this loadFace if it is not a polygon face
			continue;

		polygonFaces[currentFace].firstVertexIndex=loadFaces[i].firstVertexIndex;
		polygonFaces[currentFace].numVertices=loadFaces[i].numVertices;
		polygonFaces[currentFace].textureIndex=loadFaces[i].texture;
		polygonFaces[currentFace].lightmapIndex=loadFaces[i].lightmapIndex;

		//fill in this entry on the face directory
		faceDirectory[i].faceType=bspPolygonFace;
		faceDirectory[i].typeFaceNumber=currentFace;

		++currentFace;
	}



	//Create space for BSP_MESH_FACEs
	meshFaces=new BSP_MESH_FACE[numMeshFaces];
	if(!meshFaces)
	{
		printf("Unable To Allocate memory for BSP_MESH_FACEs");
		return false;
	}

	int currentMeshFace=0;
	//convert loadFaces to faces
	for(i=0; i<numTotalFaces; ++i)
	{
		if(loadFaces[i].type!=bspMeshFace)		//skip this loadFace if it is not a mesh face
			continue;

		meshFaces[currentMeshFace].firstVertexIndex=loadFaces[i].firstVertexIndex;
		meshFaces[currentMeshFace].numVertices=loadFaces[i].numVertices;
		meshFaces[currentMeshFace].textureIndex=loadFaces[i].texture;
		meshFaces[currentMeshFace].lightmapIndex=loadFaces[i].lightmapIndex;
		meshFaces[currentMeshFace].firstMeshIndex=loadFaces[i].firstMeshIndex;
		meshFaces[currentMeshFace].numMeshIndices=loadFaces[i].numMeshIndices;

		//fill in this entry on the face directory
		faceDirectory[i].faceType=bspMeshFace;
		faceDirectory[i].typeFaceNumber=currentMeshFace;

		++currentMeshFace;
	}
	


	//Create space for BSP_PATCHes
	patches=new BSP_PATCH[numPatches];
	if(!patches)
	{
		printf("Unable To Allocate memory for BSP_PATCHes");
		return false;
	}

	int currentPatch=0;
	//convert loadFaces to patches
	for(i=0; i<numTotalFaces; ++i)
	{
		if(loadFaces[i].type!=bspPatch)		//skip this loadFace if it is not a patch
			continue;

		patches[currentPatch].textureIndex=loadFaces[i].texture;
		patches[currentPatch].lightmapIndex=loadFaces[i].lightmapIndex;
		patches[currentPatch].width=loadFaces[i].patchSize[0];
		patches[currentPatch].height=loadFaces[i].patchSize[1];
		
		//fill in this entry on the face directory
		faceDirectory[i].faceType=bspPatch;
		faceDirectory[i].typeFaceNumber=currentPatch;

		//Create space to hold quadratic patches
		int numPatchesWide=(patches[currentPatch].width-1)/2;
		int numPatchesHigh=(patches[currentPatch].height-1)/2;

		patches[currentPatch].numQuadraticPatches=	numPatchesWide*numPatchesHigh;
		patches[currentPatch].quadraticPatches=new BSP_BIQUADRATIC_PATCH
													[patches[currentPatch].numQuadraticPatches];
		if(!patches[currentPatch].quadraticPatches)
		{
			printf(	"Unable to allocate memory for %d quadratic patches", 
									patches[currentPatch].numQuadraticPatches);
			return false;
		}

		//fill in the quadratic patches
		for(int y=0; y<numPatchesHigh; ++y)
		{
			for(int x=0; x<numPatchesWide; ++x)
			{
				for(int row=0; row<3; ++row)
				{
					for(int point=0; point<3; ++point)
					{
						patches[currentPatch].quadraticPatches[y*numPatchesWide+x].
							controlPoints[row*3+point]=vertices[loadFaces[i].firstVertexIndex+
								(y*2*patches[currentPatch].width+x*2)+
									row*patches[currentPatch].width+point];
					}
				}

				//tesselate the patch
				patches[currentPatch].quadraticPatches[y*numPatchesWide+x].Tesselate(curveTesselation);
			}
		}


		++currentPatch;
	}

	if(loadFaces)
		delete [] loadFaces;
	loadFaces=NULL;

	return true;
}


bool BSP::LoadBSPData(FILE * file) {
	//Load leaves
	//Calculate number of leaves
	numLeaves=header.directoryEntries[bspLeaves].length/sizeof(BSP_LOAD_LEAF);

	//Create space for this many BSP_LOAD_LEAFS
	BSP_LOAD_LEAF * loadLeaves=new BSP_LOAD_LEAF[numLeaves];
	if(!loadLeaves)
	{
		printf("Unable to allocate space for %d BSP_LOAD_LEAFs", numLeaves);
		return false;
	}

	//Create space for this many BSP_LEAFs
	leaves=new BSP_LEAF[numLeaves];
	if(!leaves)
	{
		printf("Unable to allocate space for %d BSP_LEAFs", numLeaves);
		return false;
	}

	//Load leaves
	fseek(file, header.directoryEntries[bspLeaves].offset, SEEK_SET);
	fread(loadLeaves, 1, header.directoryEntries[bspLeaves].length, file);

	//Convert the load leaves to leaves
	for(int i=0; i<numLeaves; ++i)
	{
		leaves[i].cluster=loadLeaves[i].cluster;
		leaves[i].firstLeafFace=loadLeaves[i].firstLeafFace;
		leaves[i].numFaces=loadLeaves[i].numFaces;

		//Create the bounding box
		leaves[i].boundingBoxVertices[0].set((float)loadLeaves[i].mins[0], (float)loadLeaves[i].mins[2],-(float)loadLeaves[i].mins[1]);
		leaves[i].boundingBoxVertices[1].set((float)loadLeaves[i].mins[0], (float)loadLeaves[i].mins[2],-(float)loadLeaves[i].maxs[1]);
		leaves[i].boundingBoxVertices[2].set((float)loadLeaves[i].mins[0], (float)loadLeaves[i].maxs[2],-(float)loadLeaves[i].mins[1]);
		leaves[i].boundingBoxVertices[3].set((float)loadLeaves[i].mins[0], (float)loadLeaves[i].maxs[2],-(float)loadLeaves[i].maxs[1]);
		leaves[i].boundingBoxVertices[4].set((float)loadLeaves[i].maxs[0], (float)loadLeaves[i].mins[2],-(float)loadLeaves[i].mins[1]);
		leaves[i].boundingBoxVertices[5].set((float)loadLeaves[i].maxs[0], (float)loadLeaves[i].mins[2],-(float)loadLeaves[i].maxs[1]);
		leaves[i].boundingBoxVertices[6].set((float)loadLeaves[i].maxs[0], (float)loadLeaves[i].maxs[2],-(float)loadLeaves[i].mins[1]);
		leaves[i].boundingBoxVertices[7].set((float)loadLeaves[i].maxs[0], (float)loadLeaves[i].maxs[2],-(float)loadLeaves[i].maxs[1]);

	}

	
	
	//Load leaf faces array
	int numLeafFaces=header.directoryEntries[bspLeafFaces].length/sizeof(int);

	//Create space for this many leaf faces
	leafFaces=new int[numLeafFaces];
	if(!leafFaces)
	{
		printf("Unable to allocate space for %d leaf faces", numLeafFaces);
		return false;
	}

	//Load leaf faces
	fseek(file, header.directoryEntries[bspLeafFaces].offset, SEEK_SET);
	fread(leafFaces, 1, header.directoryEntries[bspLeafFaces].length, file);

	if(loadLeaves)
		delete [] loadLeaves;
	loadLeaves=NULL;

	return true;
}



//Tesselate a biquadratic patch
bool BSP_BIQUADRATIC_PATCH::Tesselate(int newTesselation)
{
	tesselation=newTesselation;

	float px, py;
	BSP_VERTEX temp[3];
	vertices=new BSP_VERTEX[(tesselation+1)*(tesselation+1)];

	for(int v=0; v<=tesselation; ++v)
	{
		px=(float)v/tesselation;

		vertices[v]=controlPoints[0]*((1.0f-px)*(1.0f-px))+
					controlPoints[3]*((1.0f-px)*px*2)+
					controlPoints[6]*(px*px);
	}

	for(int u=1; u<=tesselation; ++u)
	{
		py=(float)u/tesselation;

		temp[0]=controlPoints[0]*((1.0f-py)*(1.0f-py))+
				controlPoints[1]*((1.0f-py)*py*2)+
				controlPoints[2]*(py*py);

		temp[1]=controlPoints[3]*((1.0f-py)*(1.0f-py))+
				controlPoints[4]*((1.0f-py)*py*2)+
				controlPoints[5]*(py*py);

		temp[2]=controlPoints[6]*((1.0f-py)*(1.0f-py))+
				controlPoints[7]*((1.0f-py)*py*2)+
				controlPoints[8]*(py*py);

		for(int v=0; v<=tesselation; ++v)
		{
			px=(float)v/tesselation;

			vertices[u*(tesselation+1)+v]=	temp[0]*((1.0f-px)*(1.0f-px))+
											temp[1]*((1.0f-px)*px*2)+
											temp[2]*(px*px);
		}
	}

	//Create indices
	indices=new int[tesselation*(tesselation+1)*2];
	if(!indices)
	{
		printf("Unable to allocate memory for surface indices");
		return false;
	}

	for(int row=0; row<tesselation; ++row)
	{
		for(int point=0; point<=tesselation; ++point)
		{
			//calculate indices
			//reverse them to reverse winding
			indices[(row*(tesselation+1)+point)*2+1]=row*(tesselation+1)+point;
			indices[(row*(tesselation+1)+point)*2]=(row+1)*(tesselation+1)+point;
		}
	}


	//Fill in the arrays for multi_draw_arrays
	trianglesPerRow=new int[tesselation];
	rowIndexPointers=new unsigned int *[tesselation];
	if(!trianglesPerRow || !rowIndexPointers)
	{
		printf("Unable to allocate memory for indices for multi_draw_arrays");
		return false;
	}

	for(row=0; row<tesselation; ++row)
	{
		trianglesPerRow[row]=2*(tesselation+1);
		rowIndexPointers[row]=(unsigned int *)&indices[row*2*(tesselation+1)];
	}

	return true;
}



bool BSP::LoadTextures(FILE * file)
{
	//Calculate number of textures
	numTextures=header.directoryEntries[bspTextures].length/sizeof(BSP_LOAD_TEXTURE);

	//Create space for this many BSP_LOAD_TEXTUREs
	loadTextures=new BSP_LOAD_TEXTURE[numTextures];
	if(!loadTextures)
	{
		printf("Unable to allocate space for %d BSP_LOAD_TEXTUREs", numTextures);
		return false;
	}

	//Load textures
	fseek(file, header.directoryEntries[bspTextures].offset, SEEK_SET);
	fread(loadTextures, 1, header.directoryEntries[bspTextures].length, file);

	return true;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -