Пример #1
0
int PackTreeInBSP(bsp_tree_node* root, int offset, char *buffer, std::vector<pcs_polygon> &polygons,
	std::unordered_map<vector3d, int> &norms, std::unordered_map<vector3d, int> &verts, BSP_DefPoints &dpnts, vector3d geo_center, int buffsize, int &error_flags)
{
	// ----------- error detection ---------------
	// abort if error detected
	if (error_flags != BSP_NOERRORS)
		return 0; 

	// we're going to write off the end of the buffer gauranteed (smallest element is EOF - 8 bytes
	if (offset >= buffsize-7)
	{
		error_flags |= BSP_PACK_PREOVERFLOW;
		return 0;
	}
	// either we're written this node already, or it didn't get counted in size calculation.. this is bad, skip
	if (root != NULL && root->used == true)
	{
		error_flags |= BSP_PACK_DOUBLEUSE;
		return 0;
	}

	if (root != NULL && root->counted == false)
	{
		error_flags |= BSP_PACK_UNCOUNTED;
		return 0;
	}

	// ----------- finish error detection ---------------
	int size = 0;
	BSP_BlockHeader EndOfFile;
	EndOfFile.id = 0;
	EndOfFile.size = 0;

	BSP_BoundBox Bounding;
	Bounding.head.id = 5;
	Bounding.head.size = Bounding.MySize();

	BSP_TmapPoly tpoly;
	BSP_FlatPoly fpoly;

	BSP_SortNorm snorm;	
	
	if (root == NULL)
	{
		EndOfFile.Write(buffer+offset);
		return 8;
	}
	switch(root->Type)
	{
		case POLY:
			// write BBOX
			Bounding.max_point = root->bound_max;
			Bounding.min_point = root->bound_min;
			Bounding.Write(buffer+offset+size);
			size += Bounding.MySize();

			if (offset+CalculateTreeSize(root, polygons) > buffsize)
			{
				error_flags |= BSP_PACK_PREPOLYOVERFLOW;
				return 0;
			}
			// Size is BBOX (32 bytes) + Poly (variable on type and count) + EOF ( 8 bytes)
			
			// write POLY
			for(unsigned int i = 0; i<root->poly_num.size(); i++){
				if (polygons[root->poly_num[i]].texture_id == -1)
				{
					MakeFlatPoly(fpoly, polygons[root->poly_num[i]], norms, verts, dpnts);

					fpoly.Write(buffer+offset+size);
					size += fpoly.MySize();
				}
				else 
				{
					MakeTmapPoly(tpoly, polygons[root->poly_num[i]], norms, verts, dpnts);

					tpoly.Write(buffer+offset+size);
					size += tpoly.MySize();
				}
			}
			// write EOF
			EndOfFile.Write(buffer+offset+size);
			size += EndOfFile.MySize();
			root->used = true;

			if (offset+size > buffsize)
			{
				error_flags |= BSP_PACK_POLYOVERFLOW;
			}
			return size;

		default: //SPLIT
			size = 80;
			memset((char*)&snorm, 0, sizeof(BSP_SortNorm));
			snorm.head.id = 4;
			snorm.head.size = snorm.MySize();
			snorm.plane_point = root->point;
			snorm.plane_normal = root->normal;
			snorm.max_bounding_box_point = root->bound_max;
			snorm.min_bounding_box_point = root->bound_min;

			if (offset+CalculateTreeSize(root, polygons) > buffsize)
			{
				error_flags |= BSP_PACK_PRESPLITOVERFLOW;
				return 0;
			}

			snorm.prelist_offset = size;
			size += PackTreeInBSP(NULL, offset+size, buffer, polygons, norms, verts, dpnts, geo_center, buffsize, error_flags);
				
			snorm.postlist_offset = size;
			size += PackTreeInBSP(NULL, offset + size, buffer, polygons, norms, verts, dpnts, geo_center, buffsize, error_flags);
				
			snorm.online_offset = size;
			size += PackTreeInBSP(NULL, offset + size, buffer, polygons, norms, verts, dpnts, geo_center, buffsize, error_flags);
			
			snorm.front_offset = size;
			size += PackTreeInBSP(root->front.get(), offset+size, buffer, polygons, norms, verts, dpnts, geo_center, buffsize, error_flags);

			snorm.back_offset = size;
			size += PackTreeInBSP(root->back.get(), offset+size, buffer, polygons, norms, verts, dpnts, geo_center, buffsize, error_flags);

			snorm.Write(buffer+offset);

			// write a trailing BSP::EOF to make ourselves safe

			//EndOfFile.Write(buffer+offset+size);
			//size += EndOfFile.MySize();
			
			root->used = true;
			if (offset+size > buffsize)
			{
				error_flags |= BSP_PACK_SPLITOVERFLOW;
			}
			return size;
	}
	return 0;
}
Пример #2
0
bool PCS_Model::PMFObj_to_POFObj2(int src_num, OBJ2 &dst, bool &bsp_compiled, float& model_radius)
{

	pcs_sobj &src = subobjects[src_num];

	dst.submodel_parent = src.parent_sobj;
	dst.offset = POFTranslate(src.offset);
	dst.geometric_center = POFTranslate(src.geometric_center);
	dst.submodel_name = APStoString(src.name);
	dst.properties = APStoString(src.properties);

	switch (src.movement_type)
	{
		case ROTATE:
			dst.movement_type = 1;
			break;
		default:
			dst.movement_type = -1;
	}
	switch (src.movement_axis)
	{
		case MV_X:
			dst.movement_axis = 0;
			break;
		case MV_Z:
			dst.movement_axis = 1;
			break;
		case MV_Y:
			dst.movement_axis = 2;
			break;
		default:
			dst.movement_axis = -1;
	}

	dst.reserved = 0;



	if(!can_bsp_cache || bsp_cache[src_num].changed)
	{

		// convert them to POF axis
		std::vector<pcs_polygon> clean_list = src.polygons;
		for (size_t i = 0; i < clean_list.size(); i++)
		{
			clean_list[i].norm = POFTranslate(clean_list[i].norm);
			for (size_t j = 0; j < clean_list[i].verts.size(); j++)
			{
				clean_list[i].verts[j].point = POFTranslate(clean_list[i].verts[j].point);
				clean_list[i].verts[j].norm = POFTranslate(clean_list[i].verts[j].norm);
			}
			clean_list[i].centeroid = PolygonCenter(clean_list[i]);
		}

		// BSP Compilation!
		// assemble points list
		std::vector<bsp_vert> points_list;
		std::vector<vector3d> pnts;
		std::unordered_map<vector3d, int> point_to_index;
		std::unordered_map<vector3d, int> normal_to_index;
		for (size_t i = 0; i < pnts.size(); i++) {
			point_to_index.insert(std::make_pair(pnts[i], i));
		}
		bsp_vert temp;
		points_list.reserve(clean_list.size());
		for (size_t i = 0; i < clean_list.size(); i++)
		{
			for (size_t j = 0; j < clean_list[i].verts.size(); j++)
			{
				auto point = point_to_index.find(clean_list[i].verts[j].point);
				if (point == point_to_index.end()) {
					point_to_index.insert(std::make_pair(clean_list[i].verts[j].point, points_list.size()));
					points_list.emplace_back();
					points_list.back().point = clean_list[i].verts[j].point;
					pnts.push_back(points_list.back().point);
				}
				auto normal = normal_to_index.find(clean_list[i].verts[j].norm);
				if (normal == normal_to_index.end()) {
					points_list[normal_to_index.size() / 128].norms.push_back(clean_list[i].verts[j].norm);
					normal_to_index.insert(std::make_pair(clean_list[i].verts[j].norm, normal_to_index.size()));
				}
			}
		}



		// create our defpoints
		BSP_DefPoints points;
		MakeDefPoints(points, points_list);
		vector3d AvgNormal;

		// create tree
		std::unique_ptr<bsp_tree_node> root = MakeTree(clean_list, dst.bounding_box_max_point, dst.bounding_box_min_point);

		// allocate buffer and write the defpoints
		dst.bsp_data.resize(points.head.size + CalculateTreeSize(root.get(), clean_list));

		if (points.Write(&dst.bsp_data.front()) != points.head.size)
			return false; // calculation error

		//std::ofstream bsp_debug("c:\\bsp.txt");
		//DebugPrintTree(root, bsp_debug);

		// pack the tree
		int error_flags = 0;
		PackTreeInBSP(root.get(), points.head.size, &dst.bsp_data.front(), clean_list, normal_to_index, point_to_index, points, dst.geometric_center, dst.bsp_data.size(), error_flags);
		
		// we got errors!
		if (error_flags != BSP_NOERRORS)
			return false;

		// update the bsp_compiled to be true
		bsp_compiled = true;

		// update the BSP cache with the new result
		if (can_bsp_cache)
		{
			// clear the saved - stale cache
			bsp_cache[src_num].decache();
			bsp_cache[src_num].bsp_data = dst.bsp_data;
			bsp_cache[src_num].changed = false;
		}


	}
	else // Used cached copy!
	{
		dst.bsp_data = bsp_cache[src_num].bsp_data;
	}
	dst.radius = 0.0f;
	dst.bounding_box_max_point = vector3d(FLT_MIN, FLT_MIN, FLT_MIN);
	dst.bounding_box_min_point = vector3d(FLT_MAX, FLT_MAX, FLT_MAX);

	vector3d global_offset(OffsetFromParent(src_num));
	for(unsigned int i = 0; i<src.polygons.size(); i++){
		for(unsigned int j = 0; j<src.polygons[i].verts.size(); j++){
			ExpandBoundingBoxes(dst.bounding_box_max_point, dst.bounding_box_min_point,  src.polygons[i].verts[j].point);
			float norm = Magnitude(src.polygons[i].verts[j].point);
			if (norm > dst.radius) {
				dst.radius = norm;
			}
			float global_norm = Magnitude(src.polygons[i].verts[j].point + global_offset);
			if (global_norm > model_radius) {
				model_radius = global_norm;
			}

		}
	}
	if (dst.radius == 0.0f) {
		dst.bounding_box_max_point = vector3d();
		dst.bounding_box_min_point = vector3d();
	}
	if (src.radius_overridden) {
		dst.radius = src.radius_override;
	}
	if (src.bounding_box_min_point_overridden) {
		dst.bounding_box_min_point = src.bounding_box_min_point_override;
	}
	if (src.bounding_box_max_point_overridden) {
		dst.bounding_box_max_point = src.bounding_box_max_point_override;
	}
	POFTranslateBoundingBoxes(dst.bounding_box_min_point, dst.bounding_box_max_point);
	return true;
}