Beispiel #1
0
////////////////////BSP::Load///////////////
////////////////////////////////////////////
bool BSP::Load(char * filename, int curveTesselation)
{
	FILE * file;

	file=fopen(filename, "rb");
	if(!file)
	{
		errorLog.OutputError("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 )
	{
		errorLog.OutputError("%s is not a version 0x2E .bsp map file", filename);
		return false;
	}


	//Load in vertices
	if(!LoadVertices(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)
	{
		errorLog.OutputError("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 textures
	if(!LoadTextures(file))
		return false;

		
	//Load Lightmaps
	if(!LoadLightmaps(file))
		return false;


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


	//Load in entity string
	entityString=new char[header.directoryEntries[bspEntities].length];
	if(!entityString)
	{
		errorLog.OutputError(	"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);

	errorLog.OutputSuccess("%s Loaded successfully", filename);

	return true;
}
Beispiel #2
0
int RESGen::MakeRES(std::string &map, int fileindex, size_t filecount, const StringMap &resources, std::vector<std::string> &resourcePaths_)
{
	resourcePaths = resourcePaths_;

	std::string basefolder;
	std::string basefilename;
	splitPath(map, basefolder, basefilename);

	const std::string resName = basefolder + basefilename + ".res";

	if (verbal)
	{
		printf("Creating .res file %s [%d/" SIZE_T_SPECIFIER "].\n", resName.c_str(), fileindex, filecount);
	}


	// Check if resfile doesn't already exist
	const bool fileexists = fileExists(resName);

	if (!overwrite && fileexists)
	{
		// File found, but we don't want to overwrite.
		printf("%s already exists. Skipping file.\n", resName.c_str());
		return 1;
	}

	// Clear the resfile list to be sure (SHOULD be empty)
	resfile.clear();

	// Clear the texture list to be sure (SHOULD be empty)
	texturelist.clear();

	// first, get the enity data
	std::string entdata;

	if(!LoadBSPData(map, entdata, texturelist))
	{
		// error. return
		return 1;
	}


	statcount = STAT_MAX; // make statbar print at once

	EntTokenizer entDataTokenizer(entdata);

	
	try
	{
		const EntTokenizer::KeyValuePair* kv = entDataTokenizer.NextPair();

		// Note that we reparse the mapinfo.
		if(!kv)
		{
			printf("Error parsing \"%s\".\n", map.c_str());
			return 1;
		}

		while (kv && (entDataTokenizer.GetNumBlocksRead() == 0))
		{
			if (!strcmp(kv->first, "wad"))
			{
				std::string value(kv->second);
				if (!value.empty()) // Don't try to parse an empty listing
				{
					// seperate the WAD files and save
					size_t i = 0;
					size_t seppos;

					while ((seppos = value.find(';', i)) != std::string::npos)
					{
						AddWad(value, i, seppos - i); // Add wad to reslist
						i = seppos + 1;
					}

					// There might be a wad file left in the list, check for it
					if (i < value.length())
					{
						// it should be equal, there is a wadfile left!
						AddWad(value, i, value.length() - i);
					}
				}

			}
			else if (!strcmp(kv->first, "skyname"))
			{
				std::string value(kv->second);

				// Add al 6 sky textures here
				AddRes(value, "gfx/env/", "up.tga");
				AddRes(value, "gfx/env/", "dn.tga");
				AddRes(value, "gfx/env/", "lf.tga");
				AddRes(value, "gfx/env/", "rt.tga");
				AddRes(value, "gfx/env/", "ft.tga");
				AddRes(value, "gfx/env/", "bk.tga");
			}

			kv = entDataTokenizer.NextPair();
		}

		while (kv)
		{
			const ptrdiff_t keyLength = entDataTokenizer.GetLatestKeyLength();
			const ptrdiff_t valueLength = entDataTokenizer.GetLatestValueLength();

			// Early out - check if key ends in 'speak'
			if(
				(keyLength >= 5)
			&&	!strcmp(kv->first + keyLength - 5, "speak")
			)
			{
				// Guessing which keys have spoken sentences is too likely to
				// cause false positives - instead use a whitelist of keys
				// known to contain sentences
				// TODO: This can still cause false positives if used on a different entity/mod
				// TODO: Ideally parse FGD corresponding to map
				if(
					!strcmp(kv->first, "AP_speak")
				||	!strcmp(kv->first, "non_owners_team_speak")
				||	!strcmp(kv->first, "non_team_speak")
				||	!strcmp(kv->first, "owners_team_speak")
				||	!strcmp(kv->first, "speak")
				||	!strcmp(kv->first, "team_speak")
				)
				{
					ParseSentence(kv->second);
				}
			}

			const char *token = kv->second;

			// TODO: This is fast, but should be made more robust if possible
			// Need at least 5 chars, assuming filename is:
			// [alpha][.][alpha]{3}
			if(valueLength >= 5)
			{
				if(token[valueLength - 4] == '.')
				{
					const int c1 = ::tolower(token[valueLength - 3]);
					const int c2 = ::tolower(token[valueLength - 2]);
					const int c3 = ::tolower(token[valueLength - 1]);

					if(c1 == 'm' && c2 == 'd' && c3 == 'l')
					{
						// mdl file
						AddRes(token);
					}
					if(c1 == 'w' && c2 == 'a' && c3 == 'v')
					{
						// wave file
						AddRes(token, "sound/");
					}
					if(c1 == 's' && c2 == 'p' && c3 == 'r')
					{
						// sprite file
						AddRes(token);
					}
					if(c1 == 'b' && c2 == 'm' && c3 == 'p')
					{
						// bitmap file
						AddRes(token);
					}
					if(c1 == 't' && c2 == 'g' && c3 == 'a')
					{
						// targa file
						AddRes(token);
					}
				}
			}

			// update statbar
			if (statusline && statcount == STAT_MAX)
			{
				// Reset the statcount
				statcount = 0;

				// Calculate the percentage completed of the current file.
				size_t progress = static_cast<size_t>(token - &entdata[0]);
				size_t percentage = ((progress + 1) * 101) / entdata.length(); // Make the length one too long.
				if (percentage > 100)
				{
					 // Make sure we don;t go over 100%
					percentage = 100;
				}
				printf("\r(" SIZE_T_SPECIFIER "%%) [%d/" SIZE_T_SPECIFIER "]", percentage, fileindex, filecount);
			}
			else
			{
				statcount++;
			}

			kv = entDataTokenizer.NextPair();
		}
	}
	catch(ParseException &parseException)
	{
		if(parseException.GetCharNum() >= 0)
		{
			printf("Failed to parse '%s': %s (char: %d)\n", map.c_str(), parseException.what(), parseException.GetCharNum());
		}
		else
		{
			printf("Failed to parse '%s': %s\n", map.c_str(), parseException.what());
		}
		return 1;
	}

	if (statusline)
	{
		// erase statusline
		printf("\r%-21s\r", ""); // easier to adjust length this way
	}

	entdata.clear();

	// Try to find info txt and overview data
	std::string overviewPath = basefolder + ".." + PATH_SEPARATOR + "overviews" + PATH_SEPARATOR + basefilename;
	if(fileExists(overviewPath + ".txt"))
	{
		// file found, but we need the tga or bmp too
		if(fileExists(overviewPath + ".tga"))
		{
			// txt found too, add both files to res list
			AddRes(basefilename, "overviews/", ".tga");
			AddRes(basefilename, "overviews/", ".txt");
		}
		else if(fileExists(overviewPath + ".bmp"))
		{
			// txt found too, add both files to res list
			AddRes(basefilename, "overviews/", ".bmp");
			AddRes(basefilename, "overviews/", ".txt");
		}
	}

	// Resource list has been made.
	int status = 0; // RES status, 0 means ok, 2 means missing resource

	std::vector<std::string> extraResources;

	// Check for resources on disk
	if (!resourcePaths.empty())
	{
		//printf("\nStarting resource check:\n");
		StringMap::iterator it = resfile.begin();

		while(it != resfile.end())
		{
			bool bErase = false;

			StringMap::const_iterator resourceIt = resources.find(it->first);

			if(resourceIt == resources.end())
			{
				// file not found - maybe it's excluded?
				if(excludelist.find(it->first) != excludelist.end())
				{
					// file found - it's an exclude
					if (contentdisp)
					{
						printf("Resource is excluded: %s\n", it->second.c_str());
					}

				}
				else if (CompareStrEnd(it->first, ".wad"))
				{
					// not a wad file
					if (verbal)
					{
						printf("Resource file not found: %s\n", it->second.c_str());
					}
					status = 2; // res file might not be complete
				}
				else
				{
					// wad file is not critical, so no status change
					if (contentdisp)
					{
						printf("Resource file not found: %s\n", it->second.c_str());
					}
				}

				bErase = true;
			}
			else
			{
				if (matchcase)
				{
					// match case
					it->second = resourceIt->second;
				}

				if (parseresource)
				{
					if (!CompareStrEnd(it->first, ".wad"))
					{
						// Check if wad file is used
						if (!CheckWadUse(resourceIt)) // We MUST have the right file
						{
							// Wad is NOT being used
							if (contentdisp)
							{
								printf("WAD file not used: %s\n", it->second.c_str());
							}

							if(!preservewads)
							{
								bErase = true;
							}
						}
					}
					else if (!CompareStrEnd(it->first, ".mdl"))
					{
						// Check model for external texture
						if (CheckModelExtTexture(resourceIt->second))
						{
							// Uses external texture, add
							std::string extmdltex = it->second.substr(0, it->second.length() - 4); // strip extention
							extmdltex += "T.mdl"; // add T and extention

							if(
								(resfile.find(strToLowerCopy(extmdltex)) == resfile.end())
							&&	(findStringNoCase(extraResources, extmdltex) == extraResources.end())
							)
							{
								extraResources.push_back(extmdltex);

								if (contentdisp)
								{
									printf("MDL texture file added: %s\n", extmdltex.c_str());
								}
							}
						}
					}

				}
			}

			if(bErase)
			{
				it = resfile.erase(it);
			}
			else
			{
				++it;
			}
		}

		for(std::vector<std::string>::const_iterator extraIt = extraResources.begin(); extraIt != extraResources.end(); ++extraIt)
		{
			resfile[strToLowerCopy(*extraIt)] = *extraIt;
		}
	}

	// Check if resource has to be excluded
	if (checkforexcludes)
	{
		//printf("\nStarting exclude check:\n");
		StringMap::iterator it = resfile.begin();
		while(it != resfile.end())
		{
			if(excludelist.find(it->first) != excludelist.end())
			{
				// file found
				if (contentdisp)
				{
					printf("Resource is excluded: %s\n", it->second.c_str());
				}

				it = resfile.erase(it);
			}
			else
			{
				++it;
			}
		}
	}

	// Give a list of missing textures
	if (parseresource && !resourcePaths.empty() && verbal)
	{
		if (!texturelist.empty())
		{
			status = 2; // res file might not be complete
			for(StringMap::const_iterator it = texturelist.begin(); it != texturelist.end(); ++it)
			{
				printf("Texture not found in wad files: %s\n", it->second.c_str());
			}
		}
	}

	if (resfile.empty() && rfastring.empty())
	{
		// no resources!
		if (verbal) { printf("No resources were found for \"%s.res\".", basefilename.c_str()); }

		if (fileexists)
		{
			// File exists, delete it.
			// WHAT? No check for overwrite? No!
			// Think of it, if the file exists we MUST be in overwrite mode to even get to this point!
			remove(resName.c_str());
			if (verbal)
			{
				printf(" Deleting existing res file.\n");
			}
		}
		else
		{
			// File doesn't exist, so we don't have to delete it.
			if (verbal)
			{
				printf(" Skipping file.\n");
			}
		}
		return status;
	}

	// Collecting resfile entries is done, now write the res file.
	if (!WriteRes(basefolder, basefilename))
	{
		return 1;
	}

	// File written successfully. We can safely erase the resfile and texture list
	resfile.clear();
	texturelist.clear();

	return status;
}