// // TextureEntryManager.cpp // // Handles all texture identification functions. Texture matching // is the primary method by which a rendered object is identified. // Written by Matthew Fisher // #include "Main.h" // // Textures use long string literals to represent characters that cannot be used in Windows file system. // This converts a single string literal into the appropriate character. // String TextureEntryManager::FontUpdateStringName(const String &ID) { if(ID == "Space") { return " "; } else if(ID == "Apostrophe") { return "'"; } else if(ID == "OpenBrace") { return "["; } else if(ID == "CloseBrace") { return "]"; } else if(ID == "Colon") { return ":"; } else if(ID == "Slash") { return "/"; } else if(ID == "OpenParens") { return "("; } else if(ID == "CloseParens") { return ")"; } else if(ID == "Colon") { return ":"; } else if(ID == "Comma") { return ","; } else if(ID == "Dash") { return "-"; } else if(ID == "Plus") { return "+"; } else if(ID == "Period") { return "."; } else if(ID == "Exclimation") { return "!"; } else if(ID == "Question") { return "?"; } else if(ID == "Quotation") { return "\""; } else if(ID == "LessThan") { return "<"; } else if(ID == "GreaterThan") { return ">"; } else if(ID == "Star") { return "*"; } return ID; } // // Saves the currently loaded texture map to MapSaveString // void TextureEntryManager::SaveMap(const TextureEntryMap &Map, const String &Filename) { ofstream File(Filename.CString()); for(TextureEntryMap::const_iterator Iterator = Map.begin(); Iterator != Map.end(); Iterator++) { File << UINT(Iterator->second->Type) << '\t' << Iterator->second->ID << '\t' << Iterator->second->Filename << '\t' << Iterator->first << endl; } } // // Loads the texture map from MapSaveString // void TextureEntryManager::LoadMap(TextureEntryMap &Map, set &Set, const String &Filename) { ifstream File(Filename.CString()); Vector Lines; Utility::GetFileLines(File, Lines); for(UINT i = 0; i < Lines.Length(); i++) { if(Lines[i].Length() > 3) { Vector Parameters; Lines[i].Partition('\t', Parameters); Assert(Parameters.Length() == 4, "Output.Length() != 4"); RenderType Type = RenderType(Parameters[0].ConvertToInteger()); String ID = Parameters[1]; String Filename = Parameters[2]; UINT HashValue = Parameters[3].ConvertToUnsignedInteger(); if(Utility::FileExists(g_Context->Parameters.TextureLoadDirectory + Filename + String(".png"))) { Assert(Map.find(HashValue) == Map.end(), "Hash collision in TextureEntryManager::LoadMap"); Map[HashValue] = new TextureEntry(Filename, ID, Type); Set.insert(Filename.Hash32()); } else { g_Context->Files.Events << "Texture removed: " << Filename << endl; } } } } // // Adds the bitmap at Directory + Filename to the texture hash // void TextureEntryManager::AddBitmapFromFile(const String &Directory, const String &Filename, RenderType Type, TextureEntryMap &Map, set &Set) { String TruncatedFilename = Filename; TruncatedFilename.ReSize(TruncatedFilename.Length() - 4); const String LocalDirectory = Directory.RemovePrefix(g_Context->Parameters.TextureLoadDirectory); const String FinalFilename = LocalDirectory + TruncatedFilename; UINT FilenameHash = FinalFilename.Hash32(); if(Set.count(FilenameHash) > 0) { return; } Set.insert(FilenameHash); g_Context->Files.Events << "Adding texture: " << FinalFilename << endl; String ID = TruncatedFilename; String FullFilename = Directory + Filename; Bitmap Bmp; Bmp.LoadPNG(FullFilename); Bmp.FlipBlueAndRed(); bool Exit = false; for(int i = ID.Length() - 1; !Exit && i >= 0; i--) { if(ID[i] >= '0' && ID[i] <= '9' && ID.Length() > 1) { ID.PopEnd(); } else { Exit = true; } } ID = FontUpdateStringName(ID); InsertBitmapIntoMap(Bmp, FinalFilename, ID, Type, Map); } void TextureEntryManager::InsertBitmapIntoMap(const Bitmap &Bmp, const String &Filename, const String &ID, RenderType Type, TextureEntryMap &Map) { UINT Hash = Bmp.Hash32(); if(Map.find(Hash) == Map.end()) { Map[Hash] = new TextureEntry(Filename, ID, Type); } else { if(Map[Hash]->ID == ID) { //g_Context->Files.Assert << "Harmless hash collision, " << ID << ' ' << FullFilename << endl; } else { g_Context->Files.Assert << "Add hash collision. Source: " << Map[Hash]->Filename << " New: " << Filename << endl; } } } // // Adds all bitmaps in the given directory to the texture hash // void TextureEntryManager::AddDirectory(const String &Folder, RenderType Type, TextureEntryMap &Map, set &Set) { String DirectoryName = g_Context->Parameters.TextureLoadDirectory + Folder + String("\\"); Directory Dir(DirectoryName); for(UINT FileIndex = 0; FileIndex < Dir.Files().Length(); FileIndex++) { const String &Filename = Dir.Files()[FileIndex]; if(Filename.EndsWith(".png")) { AddBitmapFromFile(DirectoryName, Filename, Type, Map, Set); } } for(UINT DirectoryIndex = 0; DirectoryIndex < Dir.Directories().Length(); DirectoryIndex++) { AddDirectory(Folder + String("\\") + Dir.Directories()[DirectoryIndex], Type, Map, Set); } } // // Loads all directories into the texture hash, or loads the texture hash from the texture map file // void TextureEntryManager::Init() { if(g_Context->Parameters.VideoCaptureMode) { return; } String TextureMapFilename(g_Context->Parameters.DatabaseLoadDirectory + String("TextureMap.txt")); String FontMapFilename(g_Context->Parameters.DatabaseLoadDirectory + String("FontMap.txt")); LoadMap(_TextureMap, _TextureMapFilenameHashSet, TextureMapFilename); LoadMap(_FontMap, _FontMapFilenameHashSet, FontMapFilename); UINT StartSize = _TextureMap.size() + _FontMap.size(); g_Context->Files.Events << String(StartSize) << " textures loaded from map file\n"; if(g_Context->Parameters.LoadDataFromDirectories) { AddDirectory("Decoration", RenderDecoration, _TextureMap, _TextureMapFilenameHashSet); AddDirectory("Minimap", RenderMinimap, _TextureMap, _TextureMapFilenameHashSet); AddDirectory("Icon", RenderIcon, _TextureMap, _TextureMapFilenameHashSet); AddDirectory("PortraitLarge", RenderPortraitLarge, _TextureMap, _TextureMapFilenameHashSet); AddDirectory("Portrait", RenderPortrait, _TextureMap, _TextureMapFilenameHashSet); AddDirectory("Unit", RenderUnit, _TextureMap, _TextureMapFilenameHashSet); AddDirectory("Special", RenderSpecial, _TextureMap, _TextureMapFilenameHashSet); AddDirectory("Unclassified", RenderUnclassified, _TextureMap, _TextureMapFilenameHashSet); AddDirectory("Font", RenderFont, _FontMap, _FontMapFilenameHashSet); g_Context->Files.Events << String(_TextureMap.size() + _FontMap.size() - StartSize) << " new textures loaded from disk\n"; SaveMap(_TextureMap, TextureMapFilename); SaveMap(_FontMap, FontMapFilename); } else { } } const TextureEntry* TextureEntryManager::FindTextureMatch(const Bitmap &Bmp) { return FindMapMatch(Bmp, _TextureMap); } const TextureEntry* TextureEntryManager::FindFontMatch(const Bitmap &Bmp) { const TextureEntry* Result = FindMapMatch(Bmp, _FontMap); if(Result == NULL) { InsertBitmapIntoMap(Bmp, "*", "*", RenderNoMatchFound, _FontMap); } return Result; } // // Searches the texture map for a texture with hash equal to the given bitmap, returning its ID and Type. // const TextureEntry* TextureEntryManager::FindMapMatch(const Bitmap &Bmp, const TextureEntryMap &Map) { UINT Hash = Bmp.Hash32(); TextureEntryMap::const_iterator Iterator = Map.find(Hash); if(Iterator == Map.end()) { //g_Context->Files.Events << "Hash not found: " << Hash << endl; return NULL; } else { //g_Context->Files.Events << "Hash found: " << Hash << endl; return Iterator->second; } }