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

📄 bspconv.cpp

📁 3D游戏开发需要用到BSP树来经行场景渲染的管理。本代码包含完整的BSP及文件生成实现
💻 CPP
字号:
#include "portal.h"
#include "buildbsp.h"
#include "bspbrush.h"
#include "bsp.h"

bool _CBSPTree::BuildBSP(CMapLoader* map) {

	if(!map)
		return R_FAIL;

	CBSPBuilder				BSPBuilder;
	CPortalBuilder			PortalBuilder;
	CBSPReachableExtractor	ReachableExtractor;
	CBSPFilter				Filter;

	srcMap = map;

	if(!BSPBuilder.BuildTree(this)) {
		g_CLog.Log(LOG_SYSTEM, "Compilation failed...");
		return R_FAIL;
	}
	
	PortalBuilder.BuildPortals(this);

	Filter.FilterBrushesAndMarkOpaqueNodes(this);

	PortalBuilder.MarkNodeReachability();

	if(!Filter.FilterFacesAndMarkLeaves(this, true)) {
		g_CLog.Log(LOG_SYSTEM, "Map has no reachable surfaces...");
		return R_FAIL;
	}

	if(PortalBuilder.IsMapClosed()) {
		g_CLog.Log(LOG_SYSTEM, "Rebuilding optimized tree...");

		BSPBuilder.RebuildTree();

		PortalBuilder.RebuildPortals();

		Filter.FilterBrushesAndMarkOpaqueNodes(this);

		PortalBuilder.MarkNodeReachability();

		Filter.FilterFacesAndMarkLeaves(this, false);
	} else {
		g_CLog.Log(LOG_SYSTEM, "Map is not closed...");
	}

	PortalBuilder.CalcBounds();

	CString prtFile = *srcMap->GetFilename();
	prtFile.RemoveExtension();
	prtFile.Append(".prt");
	PortalBuilder.SaveToFile(prtFile.GetData());

	return R_OK;


#if 0 /// old non-OOP code
	if(!ExtractMapData()) {
		return;
	}
	
	g_CLog.Log(LOG_SYSTEM, "Building initial tree...", nLeafs);

	BuildTree();
	BuildPortals();
	SplitBrushesAndMarkOpaqueNodes();
	MarkNodeReachability();

	if(!FilterMapBrushesAndClipSides()) {
		ClearUp();
		return;
	} 

	if(IsMapClosed()) {
		g_CLog.Log(LOG_SYSTEM, "Rebuilding optimized tree...");
		BuildTree();
		BuildPortals();
		SplitBrushesAndMarkOpaqueNodes();
		MarkNodeReachability();
		AddFaceRefencesToNodes();

	} else {
		g_CLog.Log(LOG_SYSTEM, "Map is not closed!");

		SplitBrushesAndMarkOpaqueNodes();
	}

	g_CLog.Log(LOG_SYSTEM, "%4d surfaces in final map.", faces.GetNum());

	CalcBounds(1);
#endif	// Which one looks better?
}

_CBSPTree::~_CBSPTree() {
	CBSPTreeDeallocator td;
	td.Deallocate(this);

	for(int i=0; i<brushes.GetNum(); i++)
		delete brushes[i];
}

int	CBSPEmitter::AllocLeafSurface(_CBSPFace *face) {
	int index = faceIndices[face];

	if(index == -1) {
		 index = face->Emit(bsp);
		 faceIndices[face] = index;
	}

	return bsp->leafSurfIndex.Append(index);
}

int CBSPEmitter::AllocLeafBrush(_CBSPBrush *brush) {
	int index = brushIndices[brush];

	if(index == -1) {
		 index = brush->Emit(bsp);
		 brushIndices[brush] = index;
	}

	return bsp->leafBrushIndex.Append(index);
}

void CBSPEmitter::VisitLeaf(_CBSPLeafNode *l) {
	int			li = bsp->leafs.TailAlloc(1);
	sBSPLeaf*	leaf = &bsp->leafs[li];

	bsp->nodes[parent].children[child] = ~li;

	if(l->flags & NODE_OPAQUE) {
		leaf->cluster = -1;
		leaf->area = -1;
	} else {
		leaf->cluster = l->cluster;
		leaf->area = 0;
	}
	
	leaf->mins = l->min;
	leaf->maxs = l->max;

	leaf->firstLeafSurface = bsp->leafSurfIndex.GetNum();
	leaf->numLeafSurfaces = l->faces.GetNum();
	leaf->firstLeafBrush = bsp->leafBrushIndex.GetNum();
	leaf->numLeafBrushes = l->brushes.GetNum();

	for(int i=0; i<l->faces.GetNum(); i++) {
		AllocLeafSurface(l->faces[i]);
	}

	for(int i=0; i<l->brushes.GetNum(); i++) {
		if(l->brushes[i]->IsValid()) {
			AllocLeafBrush(l->brushes[i]);
		} else {
			leaf->numLeafBrushes--;
		}
	}
}
	

void CBSPEmitter::VisitNodeBegin(_CBSPSplitNode *n) {
	int			ni = bsp->nodes.TailAlloc(1);
	sBSPNode*	node = &bsp->nodes[ni];

	if(parent != -1)
		bsp->nodes[parent].children[child] = ni;

	node->planeNum = bsp->planesHash.AddElem(*tree->srcMap->GetPlane(n->plane));
	node->mins = n->min;
	node->maxs = n->max;
	
	for(int i=0; i<2; i++) {
		child = i;
		parent = ni;
		n->children[i]->Visit(this);
	}
}

void CBSPEmitter::EmitWorldEntity(CBSP* b, _CBSPTree* t) {
	bsp = b;
	tree = t;
	parent = -1;

	// Emit Geometry
	tree->tree->Visit(this);

	// Emit Entities
	CVector<CMapEntity> *me = tree->srcMap->GetEntities();

	CMapEntity*	entity = &me->GetElemNoBCheck(0);
	entity->EmitKVPairs(&bsp->entities);

	// Emit World Model
	sBSPModel *model = &bsp->models.TailAlloc();
	model->min = tree->min;
	model->max = tree->max;
	model->firstSurface = 0;
	model->numSurfaces = bsp->surfaces.GetNum();
	model->firstBrush = 0;
	model->numBrushes = bsp->brushes.GetNum();

}

void CBSPEmitter::Finish() {
	// Emit Planes
	bsp->planes.Swap(*bsp->planesHash.GetData());
	bsp->planesHash.Clear();

	// Emit Shaders
	CString textures("textures\\", 9, false);
	bsp->shaders.TailAlloc(bsp->shadersHash.GetNum());
	for(int i=0; i<bsp->shadersHash.GetNum(); i++) {
		sBSPShader *shader = &bsp->shaders[i];
		CMapShader *mapShader = bsp->shadersHash.GetElem(i);
		
		mapShader->name.FixPath();
		mapShader->name.Prepend(textures);
		
		strncpy(shader->shader, mapShader->name.GetData(), BSP_FILENAME_LEN - 1);
		shader->shader[BSP_FILENAME_LEN-1] = 0;
		shader->contentFlags = mapShader->contentFlags;
		shader->surfaceFlags = mapShader->surfaceFlags;
	}
	bsp->shadersHash.Clear();

	// Fix Normals
	for(int i=0; i<bsp->planes.GetNum(); i++) {
		bsp->planes[i].w = -bsp->planes[i].w;
	}
}

void CBSPEmitter::EmitEntity(_CBSPLeafNode* leaf) {
	sBSPModel *model = &bsp->models.TailAlloc();
	model->min = leaf->min;
	model->max = leaf->max;
	model->firstSurface = bsp->surfaces.GetNum();
	model->numSurfaces = leaf->faces.GetNum();
	model->firstBrush = bsp->brushes.GetNum();
	model->numBrushes = leaf->brushes.GetNum();

	for(int i=0; i<leaf->faces.GetNum(); i++) {
		leaf->faces[i]->Emit(bsp);
	}

	for(int i=0; i<leaf->brushes.GetNum(); i++) {
		leaf->brushes[i]->Emit(bsp);
	}
}

bool CompileMap(CBSP *bsp, CMapLoader *map) {
	_CBSPTree	tree;
	CBSPEmitter	emitter;
	int			models = 1;

	g_CLog.Log(LOG_SYSTEM, "Compiling BSP tree...");

	if(!tree.BuildBSP(map))
		return R_FAIL;

	emitter.EmitWorldEntity(bsp, &tree);

	g_CLog.Log(LOG_SYSTEM, "Compiling submodels...");

	for(int i=1; i<map->GetEntities()->GetNum(); i++) {
		CMapEntity*		entity = &map->GetEntities()->GetElemNoBCheck(i);
		_CBSPLeafNode*	leaf = CreateSubmodel(entity);

		if(leaf) {
			CString			model("model", 5, false);
			char			cname[] = {'*', models+'0', 0};
			CString			name(cname, 2, false);	

			entity->keyValPairs.Add(model, name);

			emitter.EmitEntity(leaf);
			for(int i=0; i<leaf->brushes.GetNum(); i++) {
				delete leaf->brushes[i];
			}
			delete leaf;

			models++;
		}

		entity->EmitKVPairs(&bsp->entities);
	}

	emitter.Finish();

	return R_OK;
}

⌨️ 快捷键说明

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