Further improvemens to texture resolution. (#16)
* Further improvemens to texture resolution. - Move towards std::string over char * and FbxString where convenient, - Make a clear distinction between textures whose image files have been located and those who haven't; warn early in the latter case. - Extend RawTexture so we always know logical name in FBX, original file name in FBX, and inferred location in local filesystem. - In non-binary mode, simply output the inferred local file basename as the URI; this will be the correct relative path as long as the texture files are located next to the .gltf and .bin files. Primary remaining urge for a follow-up PR: - We should be copying texture image files into the .gltf output folder, but before that we should switch to an off-the-shelf cross-platform file manipulation library like https://github.com/cginternals/cppfs. When we make that transition, all this texture resolution code will undergo another refactoring.
This commit is contained in:
parent
946f12361c
commit
8cf7f446b7
|
@ -106,7 +106,7 @@ class FbxMaterialAccess
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const FbxSurfaceMaterial *fbxMaterial;
|
const FbxSurfaceMaterial *fbxMaterial;
|
||||||
const std::map<const FbxTexture *, FbxString> &textureNames;
|
const std::map<const FbxTexture *, FbxString> &textureLocations;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const FbxString name;
|
const FbxString name;
|
||||||
|
@ -119,7 +119,7 @@ public:
|
||||||
fbxMaterial(fbxMaterial),
|
fbxMaterial(fbxMaterial),
|
||||||
name(fbxMaterial->GetName()),
|
name(fbxMaterial->GetName()),
|
||||||
shadingModel(fbxMaterial->ShadingModel),
|
shadingModel(fbxMaterial->ShadingModel),
|
||||||
textureNames(textureNames),
|
textureLocations(textureNames),
|
||||||
props(extractTextures())
|
props(extractTextures())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ public:
|
||||||
|
|
||||||
FbxDouble val(0);
|
FbxDouble val(0);
|
||||||
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>();
|
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>();
|
||||||
if (tex != nullptr && textureNames.find(tex) == textureNames.end()) {
|
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
|
||||||
tex = nullptr;
|
tex = nullptr;
|
||||||
}
|
}
|
||||||
if (tex == nullptr && prop.IsValid()) {
|
if (tex == nullptr && prop.IsValid()) {
|
||||||
|
@ -195,7 +195,7 @@ public:
|
||||||
|
|
||||||
FbxDouble3 val(1, 1, 1);
|
FbxDouble3 val(1, 1, 1);
|
||||||
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>();
|
FbxFileTexture *tex = prop.GetSrcObject<FbxFileTexture>();
|
||||||
if (tex != nullptr && textureNames.find(tex) == textureNames.end()) {
|
if (tex != nullptr && textureLocations.find(tex) == textureLocations.end()) {
|
||||||
tex = nullptr;
|
tex = nullptr;
|
||||||
}
|
}
|
||||||
if (tex == nullptr && prop.IsValid()) {
|
if (tex == nullptr && prop.IsValid()) {
|
||||||
|
@ -213,14 +213,14 @@ public:
|
||||||
FbxDouble factorVal(1);
|
FbxDouble factorVal(1);
|
||||||
|
|
||||||
FbxFileTexture *colTex = colProp.GetSrcObject<FbxFileTexture>();
|
FbxFileTexture *colTex = colProp.GetSrcObject<FbxFileTexture>();
|
||||||
if (colTex != nullptr && textureNames.find(colTex) == textureNames.end()) {
|
if (colTex != nullptr && textureLocations.find(colTex) == textureLocations.end()) {
|
||||||
colTex = nullptr;
|
colTex = nullptr;
|
||||||
}
|
}
|
||||||
if (colTex == nullptr && colProp.IsValid()) {
|
if (colTex == nullptr && colProp.IsValid()) {
|
||||||
colorVal = colProp.Get<FbxDouble3>();
|
colorVal = colProp.Get<FbxDouble3>();
|
||||||
}
|
}
|
||||||
FbxFileTexture *facTex = facProp.GetSrcObject<FbxFileTexture>();
|
FbxFileTexture *facTex = facProp.GetSrcObject<FbxFileTexture>();
|
||||||
if (facTex != nullptr && textureNames.find(facTex) == textureNames.end()) {
|
if (facTex != nullptr && textureLocations.find(facTex) == textureLocations.end()) {
|
||||||
facTex = nullptr;
|
facTex = nullptr;
|
||||||
}
|
}
|
||||||
if (facTex == nullptr && facProp.IsValid()) {
|
if (facTex == nullptr && facProp.IsValid()) {
|
||||||
|
@ -240,7 +240,7 @@ class FbxMaterialsAccess
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<const FbxTexture *, FbxString> &textureNames) :
|
FbxMaterialsAccess(const FbxMesh *pMesh, const std::map<const FbxTexture *, FbxString> &textureLocations) :
|
||||||
mappingMode(FbxGeometryElement::eNone),
|
mappingMode(FbxGeometryElement::eNone),
|
||||||
mesh(nullptr),
|
mesh(nullptr),
|
||||||
indices(nullptr)
|
indices(nullptr)
|
||||||
|
@ -272,7 +272,7 @@ public:
|
||||||
if (summary == nullptr) {
|
if (summary == nullptr) {
|
||||||
summary = summaries[materialNum] = std::make_shared<FbxMaterialAccess>(
|
summary = summaries[materialNum] = std::make_shared<FbxMaterialAccess>(
|
||||||
mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum),
|
mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(materialNum),
|
||||||
textureNames);
|
textureLocations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -473,7 +473,7 @@ GetMaterialType(const RawModel &raw, const int textures[RAW_TEXTURE_USAGE_MAX],
|
||||||
return skinned ? RAW_MATERIAL_TYPE_SKINNED_OPAQUE : RAW_MATERIAL_TYPE_OPAQUE;
|
return skinned ? RAW_MATERIAL_TYPE_SKINNED_OPAQUE : RAW_MATERIAL_TYPE_OPAQUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std::map<const FbxTexture *, FbxString> &textureNames)
|
static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std::map<const FbxTexture *, FbxString> &textureLocations)
|
||||||
{
|
{
|
||||||
FbxGeometryConverter meshConverter(pScene->GetFbxManager());
|
FbxGeometryConverter meshConverter(pScene->GetFbxManager());
|
||||||
meshConverter.Triangulate(pNode->GetNodeAttribute(), true);
|
meshConverter.Triangulate(pNode->GetNodeAttribute(), true);
|
||||||
|
@ -490,7 +490,7 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std:
|
||||||
const FbxLayerElementAccess<FbxVector2> uvLayer0(pMesh->GetElementUV(0), pMesh->GetElementUVCount());
|
const FbxLayerElementAccess<FbxVector2> uvLayer0(pMesh->GetElementUV(0), pMesh->GetElementUVCount());
|
||||||
const FbxLayerElementAccess<FbxVector2> uvLayer1(pMesh->GetElementUV(1), pMesh->GetElementUVCount());
|
const FbxLayerElementAccess<FbxVector2> uvLayer1(pMesh->GetElementUV(1), pMesh->GetElementUVCount());
|
||||||
const FbxSkinningAccess skinning(pMesh, pScene, pNode);
|
const FbxSkinningAccess skinning(pMesh, pScene, pNode);
|
||||||
const FbxMaterialsAccess materials(pMesh, textureNames);
|
const FbxMaterialsAccess materials(pMesh, textureLocations);
|
||||||
|
|
||||||
if (verboseOutput) {
|
if (verboseOutput) {
|
||||||
fmt::printf(
|
fmt::printf(
|
||||||
|
@ -562,9 +562,9 @@ static void ReadMesh(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std:
|
||||||
|
|
||||||
const auto maybeAddTexture = [&](FbxFileTexture *tex, RawTextureUsage usage) {
|
const auto maybeAddTexture = [&](FbxFileTexture *tex, RawTextureUsage usage) {
|
||||||
if (tex != nullptr) {
|
if (tex != nullptr) {
|
||||||
// dig out the inferred filename from the textureNames map
|
// dig out the inferred filename from the textureLocations map
|
||||||
const char *inferredPath = textureNames.find(tex)->second;
|
FbxString inferredPath = textureLocations.find(tex)->second;
|
||||||
textures[usage] = raw.AddTexture(tex->GetName(), inferredPath, usage);
|
textures[usage] = raw.AddTexture(tex->GetName(), tex->GetFileName(), inferredPath.Buffer(), usage);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -708,7 +708,8 @@ static void ReadCamera(RawModel &raw, FbxScene *pScene, FbxNode *pNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReadNodeAttributes(RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std::map<const FbxTexture *, FbxString> &textureNames)
|
static void ReadNodeAttributes(
|
||||||
|
RawModel &raw, FbxScene *pScene, FbxNode *pNode, const std::map<const FbxTexture *, FbxString> &textureLocations)
|
||||||
{
|
{
|
||||||
if (!pNode->GetVisibility()) {
|
if (!pNode->GetVisibility()) {
|
||||||
return;
|
return;
|
||||||
|
@ -723,7 +724,7 @@ static void ReadNodeAttributes(RawModel &raw, FbxScene *pScene, FbxNode *pNode,
|
||||||
case FbxNodeAttribute::eNurbsSurface:
|
case FbxNodeAttribute::eNurbsSurface:
|
||||||
case FbxNodeAttribute::eTrimNurbsSurface:
|
case FbxNodeAttribute::eTrimNurbsSurface:
|
||||||
case FbxNodeAttribute::ePatch: {
|
case FbxNodeAttribute::ePatch: {
|
||||||
ReadMesh(raw, pScene, pNode, textureNames);
|
ReadMesh(raw, pScene, pNode, textureLocations);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FbxNodeAttribute::eCamera: {
|
case FbxNodeAttribute::eCamera: {
|
||||||
|
@ -752,7 +753,7 @@ static void ReadNodeAttributes(RawModel &raw, FbxScene *pScene, FbxNode *pNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int child = 0; child < pNode->GetChildCount(); child++) {
|
for (int child = 0; child < pNode->GetChildCount(); child++) {
|
||||||
ReadNodeAttributes(raw, pScene, pNode->GetChild(child), textureNames);
|
ReadNodeAttributes(raw, pScene, pNode->GetChild(child), textureLocations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -944,7 +945,7 @@ static void ReadAnimations(RawModel &raw, FbxScene *pScene)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetInferredFileName(const char *fbxFileName, const char *directory, const std::vector<std::string> &directoryFileList)
|
static std::string GetInferredFileName(const std::string &fbxFileName, const std::string &directory, const std::vector<std::string> &directoryFileList)
|
||||||
{
|
{
|
||||||
// Get the file name with file extension.
|
// Get the file name with file extension.
|
||||||
const std::string fileName = Gltf::StringUtils::GetFileNameString(Gltf::StringUtils::GetCleanPathString(fbxFileName));
|
const std::string fileName = Gltf::StringUtils::GetFileNameString(Gltf::StringUtils::GetCleanPathString(fbxFileName));
|
||||||
|
@ -956,25 +957,19 @@ static std::string GetInferredFileName(const char *fbxFileName, const char *dire
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some FBX textures end with "_c.dds" while the source texture is a ".tga".
|
|
||||||
const bool isDDS = fileName.rfind("_c.dds") != std::string::npos;
|
|
||||||
|
|
||||||
// Get the file name without file extension.
|
// Get the file name without file extension.
|
||||||
const std::string fileBase = isDDS ? fileName.substr(0, fileName.length() - 6) : Gltf::StringUtils::GetFileBaseString(fileName);
|
const std::string fileBase = Gltf::StringUtils::GetFileBaseString(fileName);
|
||||||
|
|
||||||
// Try to find a match without file extension.
|
// Try to find a match without file extension.
|
||||||
for (const auto &file : directoryFileList) {
|
for (const auto &file : directoryFileList) {
|
||||||
const std::string listedFileBase = Gltf::StringUtils::GetFileBaseString(file.c_str());
|
|
||||||
|
|
||||||
// If the two extension-less base names match.
|
// If the two extension-less base names match.
|
||||||
if (Gltf::StringUtils::CompareNoCase(fileBase, listedFileBase) == 0) {
|
if (Gltf::StringUtils::CompareNoCase(fileBase, Gltf::StringUtils::GetFileBaseString(file)) == 0) {
|
||||||
// Return the name with extension of the file in the directory.
|
// Return the name with extension of the file in the directory.
|
||||||
return std::string(directory) + file;
|
return std::string(directory) + file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the original file with extension
|
return "";
|
||||||
return fbxFileName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -987,30 +982,34 @@ static std::string GetInferredFileName(const char *fbxFileName, const char *dire
|
||||||
it to a list of existing texture files in the same directory as the FBX file.
|
it to a list of existing texture files in the same directory as the FBX file.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
FindFbxTextures(FbxScene *pScene, const char *fbxFileName, const char *extensions, std::map<const FbxTexture *, FbxString> &textureNames)
|
FindFbxTextures(
|
||||||
|
FbxScene *pScene, const char *fbxFileName, const char *extensions, std::map<const FbxTexture *, FbxString> &textureLocations)
|
||||||
{
|
{
|
||||||
// Get the folder the FBX file is in.
|
// Get the folder the FBX file is in.
|
||||||
const FbxString folder = Gltf::StringUtils::GetFolderString(fbxFileName).c_str();
|
const std::string folder = Gltf::StringUtils::GetFolderString(fbxFileName);
|
||||||
|
|
||||||
// Check if there is a filename.fbm folder to which embedded textures were extracted.
|
// Check if there is a filename.fbm folder to which embedded textures were extracted.
|
||||||
const FbxString fbmFolderName = folder + Gltf::StringUtils::GetFileBaseString(fbxFileName).c_str() + ".fbm/";
|
const std::string fbmFolderName = folder + Gltf::StringUtils::GetFileBaseString(fbxFileName) + ".fbm/";
|
||||||
|
|
||||||
// Search either in the folder with embedded textures or in the same folder as the FBX file.
|
// Search either in the folder with embedded textures or in the same folder as the FBX file.
|
||||||
const FbxString searchFolder = FileUtils::FolderExists(fbmFolderName) ? fbmFolderName : folder;
|
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.
|
// 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;
|
std::vector<std::string> fileList = FileUtils::ListFolderFiles(searchFolder.c_str(), extensions);
|
||||||
FileUtils::ListFolderFiles(fileList, searchFolder, 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 FbxTexture *pTexture = pScene->GetTexture(i);
|
const FbxFileTexture *pFileTexture = FbxCast<FbxFileTexture>(pScene->GetTexture(i));
|
||||||
const FbxFileTexture *pFileTexture = FbxCast<FbxFileTexture>(pTexture);
|
|
||||||
if (pFileTexture == nullptr) {
|
if (pFileTexture == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const FbxString name = GetInferredFileName(pFileTexture->GetFileName(), searchFolder, fileList).c_str();
|
const std::string inferredName = GetInferredFileName(pFileTexture->GetFileName(), searchFolder, fileList);
|
||||||
textureNames.emplace(pTexture, name);
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1041,8 +1040,8 @@ bool LoadFBXFile(RawModel &raw, const char *fbxFileName, const char *textureExte
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<const FbxTexture *, FbxString> textureNames;
|
std::map<const FbxTexture *, FbxString> textureLocations;
|
||||||
FindFbxTextures(pScene, fbxFileName, textureExtensions, textureNames);
|
FindFbxTextures(pScene, fbxFileName, textureExtensions, textureLocations);
|
||||||
|
|
||||||
// Use Y up for glTF
|
// Use Y up for glTF
|
||||||
FbxAxisSystem::MayaYUp.ConvertScene(pScene);
|
FbxAxisSystem::MayaYUp.ConvertScene(pScene);
|
||||||
|
@ -1054,7 +1053,7 @@ bool LoadFBXFile(RawModel &raw, const char *fbxFileName, const char *textureExte
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadNodeHierarchy(raw, pScene, pScene->GetRootNode(), "", "");
|
ReadNodeHierarchy(raw, pScene, pScene->GetRootNode(), "", "");
|
||||||
ReadNodeAttributes(raw, pScene, pScene->GetRootNode(), textureNames);
|
ReadNodeAttributes(raw, pScene, pScene->GetRootNode(), textureLocations);
|
||||||
ReadAnimations(raw, pScene);
|
ReadAnimations(raw, pScene);
|
||||||
|
|
||||||
pScene->Destroy();
|
pScene->Destroy();
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "FBX2glTF.h"
|
#include "FBX2glTF.h"
|
||||||
#include "utils/String_Utils.h"
|
#include "utils/String_Utils.h"
|
||||||
|
#include "utils/Image_Utils.h"
|
||||||
#include "RawModel.h"
|
#include "RawModel.h"
|
||||||
#include "Raw2Gltf.h"
|
#include "Raw2Gltf.h"
|
||||||
|
|
||||||
|
@ -360,27 +361,27 @@ ModelData *Raw2Gltf(
|
||||||
//
|
//
|
||||||
|
|
||||||
for (int textureIndex = 0; textureIndex < raw.GetTextureCount(); textureIndex++) {
|
for (int textureIndex = 0; textureIndex < raw.GetTextureCount(); textureIndex++) {
|
||||||
const RawTexture &texture = raw.GetTexture(textureIndex);
|
const RawTexture &texture = raw.GetTexture(textureIndex);
|
||||||
const std::string textureName = Gltf::StringUtils::GetFileBaseString(texture.name);
|
const std::string textureName = Gltf::StringUtils::GetFileBaseString(texture.name);
|
||||||
const std::string texFilename = texture.fileName;
|
const std::string relativeFilename = Gltf::StringUtils::GetFileNameString(texture.fileLocation);
|
||||||
|
|
||||||
ImageData *source = nullptr;
|
ImageData *source = nullptr;
|
||||||
if (options.outputBinary) {
|
if (options.outputBinary) {
|
||||||
auto bufferView = gltf->AddBufferViewForFile(buffer, texFilename);
|
auto bufferView = gltf->AddBufferViewForFile(buffer, texture.fileLocation);
|
||||||
if (bufferView) {
|
if (bufferView) {
|
||||||
source = new ImageData(textureName, *bufferView, "image/png");
|
std::string suffix = Gltf::StringUtils::GetFileSuffixString(texture.fileLocation);
|
||||||
|
source = new ImageData(relativeFilename, *bufferView, suffixToMimeType(suffix));
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// TODO: don't add .ktx here; try to work out a reasonable relative path.
|
source = new ImageData(relativeFilename, relativeFilename);
|
||||||
source = new ImageData(textureName, textureName + ".ktx");
|
|
||||||
}
|
}
|
||||||
if (!source) {
|
if (!source) {
|
||||||
// fallback is tiny transparent gif
|
// fallback is tiny transparent gif
|
||||||
source = new ImageData(textureName, "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=");
|
source = new ImageData(textureName, "data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=");
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureData &texDat = *gltf->textures.hold(
|
const TextureData &texDat = *gltf->textures.hold(
|
||||||
new TextureData(textureName, defaultSampler, *gltf->images.hold(source)));
|
new TextureData(textureName, defaultSampler, *gltf->images.hold(source)));
|
||||||
assert(texDat.ix == textureIndex);
|
assert(texDat.ix == textureIndex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,9 +84,9 @@ int RawModel::AddTriangle(const int v0, const int v1, const int v2, const int ma
|
||||||
return (int) triangles.size() - 1;
|
return (int) triangles.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RawModel::AddTexture(const char *name, const char *fileName, const RawTextureUsage usage)
|
int RawModel::AddTexture(const std::string &name, const std::string &fileName, const std::string &fileLocation, RawTextureUsage usage)
|
||||||
{
|
{
|
||||||
if (name[0] == '\0') {
|
if (name.empty()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < textures.size(); i++) {
|
for (size_t i = 0; i < textures.size(); i++) {
|
||||||
|
@ -95,17 +95,18 @@ int RawModel::AddTexture(const char *name, const char *fileName, const RawTextur
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ImageProperties properties = GetImageProperties(fileName);
|
const ImageProperties properties = GetImageProperties(!fileLocation.empty() ? fileLocation.c_str() : fileName.c_str());
|
||||||
|
|
||||||
RawTexture texture;
|
RawTexture texture;
|
||||||
texture.name = name;
|
texture.name = name;
|
||||||
texture.width = properties.width;
|
texture.width = properties.width;
|
||||||
texture.height = properties.height;
|
texture.height = properties.height;
|
||||||
texture.mipLevels = (int) ceilf(Log2f(std::max((float) properties.width, (float) properties.height)));
|
texture.mipLevels = (int) ceilf(Log2f(std::max((float) properties.width, (float) properties.height)));
|
||||||
texture.usage = usage;
|
texture.usage = usage;
|
||||||
texture.occlusion = (properties.occlusion == IMAGE_TRANSPARENT) ?
|
texture.occlusion = (properties.occlusion == IMAGE_TRANSPARENT) ?
|
||||||
RAW_TEXTURE_OCCLUSION_TRANSPARENT : RAW_TEXTURE_OCCLUSION_OPAQUE;
|
RAW_TEXTURE_OCCLUSION_TRANSPARENT : RAW_TEXTURE_OCCLUSION_OPAQUE;
|
||||||
texture.fileName = fileName;
|
texture.fileName = fileName;
|
||||||
|
texture.fileLocation = fileLocation;
|
||||||
textures.emplace_back(texture);
|
textures.emplace_back(texture);
|
||||||
return (int) textures.size() - 1;
|
return (int) textures.size() - 1;
|
||||||
}
|
}
|
||||||
|
@ -312,9 +313,9 @@ void RawModel::Condense()
|
||||||
for (auto &material : materials) {
|
for (auto &material : materials) {
|
||||||
for (int j = 0; j < RAW_TEXTURE_USAGE_MAX; j++) {
|
for (int j = 0; j < RAW_TEXTURE_USAGE_MAX; j++) {
|
||||||
if (material.textures[j] >= 0) {
|
if (material.textures[j] >= 0) {
|
||||||
const RawTexture &texture = oldTextures[material.textures[j]];
|
const RawTexture &texture = oldTextures[material.textures[j]];
|
||||||
const int textureIndex = AddTexture(texture.name.c_str(), texture.fileName.c_str(), texture.usage);
|
const int textureIndex = AddTexture(texture.name, texture.fileName, texture.fileLocation, texture.usage);
|
||||||
textures[textureIndex] = texture;
|
textures[textureIndex] = texture;
|
||||||
material.textures[j] = textureIndex;
|
material.textures[j] = textureIndex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,13 +122,14 @@ enum RawTextureOcclusion
|
||||||
|
|
||||||
struct RawTexture
|
struct RawTexture
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name; // logical name in FBX file
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
int mipLevels;
|
int mipLevels;
|
||||||
RawTextureUsage usage;
|
RawTextureUsage usage;
|
||||||
RawTextureOcclusion occlusion;
|
RawTextureOcclusion occlusion;
|
||||||
std::string fileName;
|
std::string fileName; // original filename in FBX file
|
||||||
|
std::string fileLocation; // inferred path in local filesystem, or ""
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RawMaterialType
|
enum RawMaterialType
|
||||||
|
@ -233,7 +234,7 @@ public:
|
||||||
void AddVertexAttribute(const RawVertexAttribute attrib);
|
void AddVertexAttribute(const RawVertexAttribute attrib);
|
||||||
int AddVertex(const RawVertex &vertex);
|
int AddVertex(const RawVertex &vertex);
|
||||||
int AddTriangle(const int v0, const int v1, const int v2, const int materialIndex, const int surfaceIndex);
|
int AddTriangle(const int v0, const int v1, const int v2, const int materialIndex, const int surfaceIndex);
|
||||||
int AddTexture(const char *name, const char *fileName, const RawTextureUsage usage);
|
int AddTexture(const std::string &name, const std::string &fileName, const std::string &fileLocation, RawTextureUsage usage);
|
||||||
int AddMaterial(const RawMaterial &material);
|
int AddMaterial(const RawMaterial &material);
|
||||||
int AddMaterial(
|
int AddMaterial(
|
||||||
const char *name, const char *shadingModel, RawMaterialType materialType,
|
const char *name, const char *shadingModel, RawMaterialType materialType,
|
||||||
|
|
|
@ -31,8 +31,9 @@ ImageData::ImageData(std::string name, const BufferViewData &bufferView, std::st
|
||||||
|
|
||||||
json ImageData::serialize() const
|
json ImageData::serialize() const
|
||||||
{
|
{
|
||||||
if (mimeType.empty()) {
|
if (bufferView < 0) {
|
||||||
return {
|
return {
|
||||||
|
{ "name", name },
|
||||||
{ "uri", uri }
|
{ "uri", uri }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,7 +182,7 @@ Copyright (c) 2016-2017 Oculus VR, LLC.
|
||||||
if (verboseOutput) {
|
if (verboseOutput) {
|
||||||
fmt::printf("Loading FBX File: %s\n", inputPath);
|
fmt::printf("Loading FBX File: %s\n", inputPath);
|
||||||
}
|
}
|
||||||
if (!LoadFBXFile(raw, inputPath.c_str(), "tga;bmp;png;jpg")) {
|
if (!LoadFBXFile(raw, inputPath.c_str(), "png;jpg;jpeg")) {
|
||||||
fmt::fprintf(stderr, "ERROR:: Failed to parse FBX: %s\n", inputPath);
|
fmt::fprintf(stderr, "ERROR:: Failed to parse FBX: %s\n", inputPath);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,17 +54,17 @@ namespace FileUtils {
|
||||||
return std::string(cwd);
|
return std::string(cwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FolderExists(const char *folderPath)
|
bool FolderExists(const std::string &folderPath)
|
||||||
{
|
{
|
||||||
#if defined( __unix__ ) || defined( __APPLE__ )
|
#if defined( __unix__ ) || defined( __APPLE__ )
|
||||||
DIR *dir = opendir(folderPath);
|
DIR *dir = opendir(folderPath.c_str());
|
||||||
if (dir) {
|
if (dir) {
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
const DWORD ftyp = GetFileAttributesA( folderPath );
|
const DWORD ftyp = GetFileAttributesA( folderPath.c_str() );
|
||||||
if ( ftyp == INVALID_FILE_ATTRIBUTES )
|
if ( ftyp == INVALID_FILE_ATTRIBUTES )
|
||||||
{
|
{
|
||||||
return false; // bad path
|
return false; // bad path
|
||||||
|
@ -97,34 +97,34 @@ namespace FileUtils {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ListFolderFiles(std::vector<std::string> &fileList, const char *folder, const char *matchExtensions)
|
std::vector<std::string> ListFolderFiles(const char *folder, const char *matchExtensions)
|
||||||
{
|
{
|
||||||
|
std::vector<std::string> fileList;
|
||||||
#if defined( __unix__ ) || defined( __APPLE__ )
|
#if defined( __unix__ ) || defined( __APPLE__ )
|
||||||
DIR *dir = opendir(folder);
|
DIR *dir = opendir(folder);
|
||||||
if (dir == nullptr) {
|
if (dir != nullptr) {
|
||||||
return;
|
for (;;) {
|
||||||
|
struct dirent *dp = readdir(dir);
|
||||||
|
if (dp == nullptr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dp->d_type == DT_DIR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *fileName = dp->d_name;
|
||||||
|
const char *fileExt = strrchr(fileName, '.');
|
||||||
|
|
||||||
|
if (!fileExt || !MatchExtension(fileExt, matchExtensions)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileList.emplace_back(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
}
|
}
|
||||||
for (;;) {
|
|
||||||
struct dirent *dp = readdir(dir);
|
|
||||||
if (dp == nullptr) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dp->d_type == DT_DIR) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *fileName = dp->d_name;
|
|
||||||
const char *fileExt = strrchr(fileName, '.');
|
|
||||||
|
|
||||||
if (!fileExt || !MatchExtension(fileExt, matchExtensions)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
fileList.emplace_back(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
#else
|
#else
|
||||||
std::string pathStr = folder;
|
std::string pathStr = folder;
|
||||||
pathStr += "*";
|
pathStr += "*";
|
||||||
|
@ -148,6 +148,7 @@ namespace FileUtils {
|
||||||
FindClose( hFind );
|
FindClose( hFind );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
return fileList;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CreatePath(const char *path)
|
bool CreatePath(const char *path)
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
namespace FileUtils {
|
namespace FileUtils {
|
||||||
std::string GetCurrentFolder();
|
std::string GetCurrentFolder();
|
||||||
|
|
||||||
bool FolderExists(const char *folderPath);
|
bool FolderExists(const std::string &folderPath);
|
||||||
|
|
||||||
bool MatchExtension(const char *fileExtension, const char *matchExtensions);
|
bool MatchExtension(const char *fileExtension, const char *matchExtensions);
|
||||||
void ListFolderFiles(std::vector<std::string> &fileList, const char *folder, const char *matchExtensions);
|
std::vector<std::string> ListFolderFiles(const char *folder, const char *matchExtensions);
|
||||||
|
|
||||||
bool CreatePath(const char *path);
|
bool CreatePath(const char *path);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,4 +26,20 @@ struct ImageProperties
|
||||||
|
|
||||||
ImageProperties GetImageProperties(char const *filePath);
|
ImageProperties GetImageProperties(char const *filePath);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Very simple method for mapping filename suffix to mime type. The glTF 2.0 spec only accepts values
|
||||||
|
* "image/jpeg" and "image/png" so we don't need to get too fancy.
|
||||||
|
*/
|
||||||
|
inline std::string suffixToMimeType(std::string suffix) {
|
||||||
|
std::transform(suffix.begin(), suffix.end(), suffix.begin(), ::tolower);
|
||||||
|
|
||||||
|
if (suffix == "jpg" || suffix == "jpeg") {
|
||||||
|
return "image/jpeg";
|
||||||
|
}
|
||||||
|
if (suffix == "png") {
|
||||||
|
return "image/png";
|
||||||
|
}
|
||||||
|
return "image/unknown";
|
||||||
|
}
|
||||||
|
|
||||||
#endif // !__IMAGE_UTILS_H__
|
#endif // !__IMAGE_UTILS_H__
|
||||||
|
|
|
@ -73,6 +73,16 @@ namespace Gltf // TODO replace
|
||||||
return fileName.substr(0, fileName.rfind('.')).c_str();
|
return fileName.substr(0, fileName.rfind('.')).c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline const std::string GetFileSuffixString(const std::string &path)
|
||||||
|
{
|
||||||
|
const std::string fileName = GetFileNameString(path);
|
||||||
|
unsigned long pos = fileName.rfind('.');
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return fileName.substr(++pos);
|
||||||
|
}
|
||||||
|
|
||||||
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(), MAX_PATH_LENGTH);
|
return strncasecmp(s1.c_str(), s2.c_str(), MAX_PATH_LENGTH);
|
||||||
|
|
Loading…
Reference in New Issue