////////////////////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; }
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; }