Mostly rewrite texture lookup code.

This commit is contained in:
Par Winzell 2019-04-07 21:58:48 -07:00
parent 02e5eb684d
commit d6043151df
5 changed files with 85 additions and 60 deletions

View File

@ -916,38 +916,61 @@ static void ReadAnimations(RawModel& raw, FbxScene* pScene) {
} }
} }
static std::string GetInferredFileName( static std::string FindFileLoosely(
const std::string& fbxFileName, const std::string& fbxFileName,
const std::string& directory, const std::string& directory,
const std::vector<std::string>& directoryFileList) { const std::vector<std::string>& directoryFileList) {
if (FileUtils::FileExists(fbxFileName)) { if (FileUtils::FileExists(fbxFileName)) {
return fbxFileName; return fbxFileName;
} }
// Get the file name with file extension.
// From e.g. C:/Assets/Texture.jpg, extract 'Texture.jpg'
const std::string fileName = FileUtils::GetFileName(fbxFileName); const std::string fileName = FileUtils::GetFileName(fbxFileName);
// Try to find a match with extension. // Try to find a match with extension.
for (const auto& file : directoryFileList) { for (const auto& file : directoryFileList) {
if (StringUtils::CompareNoCase(fileName, file) == 0) { if (StringUtils::CompareNoCase(fileName, FileUtils::GetFileName(file)) == 0) {
return std::string(directory) + file; return directory + "/" + file;
} }
} }
// Get the file name without file extension. // Get the file name without file extension.
const std::string fileBase = FileUtils::GetFileBase(fileName); const std::string fileBase = FileUtils::GetFileBase(fileName);
// Try to find a match without file extension. // Try to find a match that ignores file extension
for (const auto& file : directoryFileList) { for (const auto& file : directoryFileList) {
// If the two extension-less base names match.
if (StringUtils::CompareNoCase(fileBase, FileUtils::GetFileBase(file)) == 0) { if (StringUtils::CompareNoCase(fileBase, FileUtils::GetFileBase(file)) == 0) {
// Return the name with extension of the file in the directory. return directory + "/" + file;
return std::string(directory) + file;
} }
} }
return ""; return "";
} }
/**
* Try to locate the best match to the given texture filename, as provided in the FBX,
* possibly searching through the provided folders for a reasonable-looking match.
*
* Returns empty string if no match can be found, else the absolute path of the file.
**/
static std::string FindFbxTexture(
const std::string& textureFileName,
const std::vector<std::string>& folders,
const std::vector<std::vector<std::string>>& folderContents) {
// it might exist exactly as-is on the running machine's filesystem
if (FileUtils::FileExists(textureFileName)) {
return textureFileName;
}
// else look in other designated folders
for (int ii = 0; ii < folders.size(); ii++) {
const auto& fileLocation = FindFileLoosely(textureFileName, folders[ii], folderContents[ii]);
if (!fileLocation.empty()) {
return FileUtils::GetAbsolutePath(fileLocation);
}
}
return "";
}
/* /*
The texture file names inside of the FBX often contain some long author-specific The texture file names inside of the FBX often contain some long author-specific
path with the wrong extensions. For instance, all of the art assets may be PSD path with the wrong extensions. For instance, all of the art assets may be PSD
@ -959,39 +982,45 @@ static std::string GetInferredFileName(
*/ */
static void FindFbxTextures( static void FindFbxTextures(
FbxScene* pScene, FbxScene* pScene,
const std::string fbxFileName, const std::string& fbxFileName,
const std::set<std::string>& extensions, const std::set<std::string>& extensions,
std::map<const FbxTexture*, FbxString>& textureLocations) { std::map<const FbxTexture*, FbxString>& textureLocations) {
// Get the folder the FBX file is in. // figure out what folder the FBX file is in,
const std::string folder = FileUtils::getFolder(fbxFileName); const auto& fbxFolder = FileUtils::getFolder(fbxFileName);
std::vector<std::string> folders{
// first search filename.fbm folder which the SDK itself expands embedded textures into,
fbxFolder + "/" + FileUtils::GetFileBase(fbxFileName) + ".fbm", // filename.fbm
// then the FBX folder itself,
fbxFolder,
// then finally our working directory
FileUtils::GetCurrentFolder(),
};
// Check if there is a filename.fbm folder to which embedded textures were extracted. // List the contents of each of these folders (if they exist)
const std::string fbmFolderName = folder + FileUtils::GetFileBase(fbxFileName) + ".fbm/"; std::vector<std::vector<std::string>> folderContents;
for (const auto& folder : folders) {
// Search either in the folder with embedded textures or in the same folder as the FBX file. if (FileUtils::FolderExists(folder)) {
const std::string searchFolder = FileUtils::FolderExists(fbmFolderName) ? fbmFolderName : folder; folderContents.push_back(FileUtils::ListFolderFiles(folder, extensions));
} else {
// Get a list with all the texture files from either the folder with embedded textures or the same folderContents.push_back({});
// folder as the FBX file. }
std::vector<std::string> fileList = FileUtils::ListFolderFiles(searchFolder.c_str(), extensions); }
// Try to match the FBX texture names with the actual files on disk. // Try to match the FBX texture names with the actual files on disk.
for (int i = 0; i < pScene->GetTextureCount(); i++) { for (int i = 0; i < pScene->GetTextureCount(); i++) {
const FbxFileTexture* pFileTexture = FbxCast<FbxFileTexture>(pScene->GetTexture(i)); const FbxFileTexture* pFileTexture = FbxCast<FbxFileTexture>(pScene->GetTexture(i));
if (pFileTexture == nullptr) { if (pFileTexture != nullptr) {
continue; const std::string fileLocation =
FindFbxTexture(pFileTexture->GetFileName(), folders, folderContents);
// always extend the mapping (even for files we didn't find)
textureLocations.emplace(pFileTexture, fileLocation.c_str());
if (fileLocation.empty()) {
fmt::printf(
"Warning: could not find a image file for texture: %s.\n", pFileTexture->GetName());
} else if (verboseOutput) {
fmt::printf("Found texture '%s' at: %s\n", pFileTexture->GetName(), fileLocation);
}
} }
const std::string inferredName =
GetInferredFileName(pFileTexture->GetFileName(), searchFolder, fileList);
if (inferredName.empty()) {
fmt::printf(
"Warning: could not find a local image file for texture: %s.\n"
"Original filename: %s\n",
pFileTexture->GetName(),
pFileTexture->GetFileName());
}
// always extend the mapping, even for files we didn't find
textureLocations.emplace(pFileTexture, inferredName.c_str());
} }
} }

View File

@ -23,13 +23,19 @@
namespace FileUtils { namespace FileUtils {
std::vector<std::string> ListFolderFiles( std::vector<std::string> ListFolderFiles(
const std::string folder, std::string folder,
const std::set<std::string>& matchExtensions) { const std::set<std::string>& matchExtensions) {
std::vector<std::string> fileList; std::vector<std::string> fileList;
for (const std::filesystem::directory_entry& entry : std::filesystem::directory_iterator(folder)) { if (folder.empty()) {
const std::filesystem::path& path = entry.path(); folder = ".";
if (matchExtensions.find(path.extension().string()) != matchExtensions.end()) { }
fileList.push_back(path.string()); for (const auto& entry : std::filesystem::directory_iterator(folder)) {
const auto& suffix = FileUtils::GetFileSuffix(entry.path());
if (suffix.has_value()) {
const auto& suffix_str = StringUtils::ToLower(suffix.value());
if (matchExtensions.find(suffix_str) != matchExtensions.end()) {
fileList.push_back(entry.path().filename().string());
}
} }
} }
return fileList; return fileList;

View File

@ -34,8 +34,12 @@ bool CopyFile(
const std::string& dstFilename, const std::string& dstFilename,
bool createPath = false); bool createPath = false);
inline std::string GetAbsolutePath(const std::string& filePath) {
return std::filesystem::absolute(filePath).string();
}
inline std::string GetCurrentFolder() { inline std::string GetCurrentFolder() {
return std::filesystem::current_path().string() + "/"; return std::filesystem::current_path().string();
} }
inline bool FileExists(const std::string& filePath) { inline bool FileExists(const std::string& filePath) {

View File

@ -1,20 +0,0 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#include "String_Utils.hpp"
#include <algorithm>
namespace StringUtils {
int CompareNoCase(const std::string& s1, const std::string& s2) {
return strncasecmp(s1.c_str(), s2.c_str(), std::max(s1.length(), s2.length()));
}
} // namespace StringUtils

View File

@ -9,6 +9,8 @@
#pragma once #pragma once
#include <algorithm>
#include <cctype>
#include <cstdarg> #include <cstdarg>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
@ -16,11 +18,15 @@
#if defined(_MSC_VER) #if defined(_MSC_VER)
#define strncasecmp _strnicmp #define strncasecmp _strnicmp
#define strcasecmp _stricmp
#endif #endif
namespace StringUtils { namespace StringUtils {
inline std::string ToLower(std::string s) {
std::transform(s.begin(), s.end(), s.begin(), [](uint8_t c) { return std::tolower(c); });
return s;
}
inline int CompareNoCase(const std::string& s1, const std::string& s2) { inline int CompareNoCase(const std::string& s1, const std::string& s2) {
return strncasecmp(s1.c_str(), s2.c_str(), std::max(s1.length(), s2.length())); return strncasecmp(s1.c_str(), s2.c_str(), std::max(s1.length(), s2.length()));
} }