Doc tweaks.

This commit is contained in:
Par Winzell 2017-10-20 18:37:08 -07:00
commit 23ae8d3ec9
11 changed files with 134 additions and 102 deletions

View File

@ -92,11 +92,11 @@ and [fmt](https://github.com/fmtlib/fmt);
all of which are automatically downloaded, configured and built. all of which are automatically downloaded, configured and built.
You must manually download and install the You must manually download and install the
[Autodesk FBX SDK](https://www.autodesk.com/products/fbx/overview) 2018.1.1 and [Autodesk FBX SDK](https://www.autodesk.com/products/fbx/overview) and
accept its license agreement. Once installed, the build system will attempt to accept its license agreement.
find the SDK in its default location for each system.
Once that's all done... **At present, only version 2018.1.1 of the FBX SDK is supported**. The
build system will not successfully locate any other version.
### Linux and MacOS X ### Linux and MacOS X
Compilation on Unix machines should be as simple as: Compilation on Unix machines should be as simple as:
@ -113,9 +113,11 @@ If all goes well, you will end up with a statically linked executable.
Windows users may [download](https://cmake.org/download) CMake for Windows, Windows users may [download](https://cmake.org/download) CMake for Windows,
install it and [run it](https://cmake.org/runningcmake/) on the FBX2glTF install it and [run it](https://cmake.org/runningcmake/) on the FBX2glTF
checkout (choose a build directory distinct from the source). As part of this checkout (choose a build directory distinct from the source).
process, you will be asked to choose which generator to use; the code is only
known to compile on ***Visual Studio 2017***. As part of this process, you will be asked to choose which generator
to use. **At present, only Visual Studio 2017 is supported.** Older
versions of the IDE are unlikely to successfully build the cool.
*(MinGW support may be plausible. Contributions welcome.)* *(MinGW support may be plausible. Contributions welcome.)*

View File

@ -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();

View File

@ -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);
} }

View File

@ -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;
} }
} }

View File

@ -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,

View File

@ -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 }
}; };
} }

View File

@ -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;
} }

View File

@ -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)

View File

@ -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);
} }

View File

@ -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__

View File

@ -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);