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& directory,
const std::vector<std::string>& directoryFileList) {
if (FileUtils::FileExists(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);
// Try to find a match with extension.
for (const auto& file : directoryFileList) {
if (StringUtils::CompareNoCase(fileName, file) == 0) {
return std::string(directory) + file;
if (StringUtils::CompareNoCase(fileName, FileUtils::GetFileName(file)) == 0) {
return directory + "/" + file;
}
}
// Get the file name without file extension.
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) {
// If the two extension-less base names match.
if (StringUtils::CompareNoCase(fileBase, FileUtils::GetFileBase(file)) == 0) {
// Return the name with extension of the file in the directory.
return std::string(directory) + file;
return directory + "/" + file;
}
}
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
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(
FbxScene* pScene,
const std::string fbxFileName,
const std::string& fbxFileName,
const std::set<std::string>& extensions,
std::map<const FbxTexture*, FbxString>& textureLocations) {
// Get the folder the FBX file is in.
const std::string folder = FileUtils::getFolder(fbxFileName);
// figure out what folder the FBX file is in,
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.
const std::string fbmFolderName = folder + FileUtils::GetFileBase(fbxFileName) + ".fbm/";
// Search either in the folder with embedded textures or in the same folder as the FBX file.
const std::string searchFolder = FileUtils::FolderExists(fbmFolderName) ? fbmFolderName : folder;
// Get a list with all the texture files from either the folder with embedded textures or the same
// folder as the FBX file.
std::vector<std::string> fileList = FileUtils::ListFolderFiles(searchFolder.c_str(), extensions);
// List the contents of each of these folders (if they exist)
std::vector<std::vector<std::string>> folderContents;
for (const auto& folder : folders) {
if (FileUtils::FolderExists(folder)) {
folderContents.push_back(FileUtils::ListFolderFiles(folder, extensions));
} else {
folderContents.push_back({});
}
}
// Try to match the FBX texture names with the actual files on disk.
for (int i = 0; i < pScene->GetTextureCount(); i++) {
const FbxFileTexture* pFileTexture = FbxCast<FbxFileTexture>(pScene->GetTexture(i));
if (pFileTexture == nullptr) {
continue;
if (pFileTexture != nullptr) {
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 {
std::vector<std::string> ListFolderFiles(
const std::string folder,
std::string folder,
const std::set<std::string>& matchExtensions) {
std::vector<std::string> fileList;
for (const std::filesystem::directory_entry& entry : std::filesystem::directory_iterator(folder)) {
const std::filesystem::path& path = entry.path();
if (matchExtensions.find(path.extension().string()) != matchExtensions.end()) {
fileList.push_back(path.string());
if (folder.empty()) {
folder = ".";
}
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;

View File

@ -34,8 +34,12 @@ bool CopyFile(
const std::string& dstFilename,
bool createPath = false);
inline std::string GetAbsolutePath(const std::string& filePath) {
return std::filesystem::absolute(filePath).string();
}
inline std::string GetCurrentFolder() {
return std::filesystem::current_path().string() + "/";
return std::filesystem::current_path().string();
}
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
#include <algorithm>
#include <cctype>
#include <cstdarg>
#include <cstdio>
#include <cstring>
@ -16,11 +18,15 @@
#if defined(_MSC_VER)
#define strncasecmp _strnicmp
#define strcasecmp _stricmp
#endif
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) {
return strncasecmp(s1.c_str(), s2.c_str(), std::max(s1.length(), s2.length()));
}