Mostly rewrite texture lookup code.
This commit is contained in:
parent
02e5eb684d
commit
d6043151df
|
@ -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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
|
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue