Merge branch 'master' into fix_malformed_irr_files
commit
ca7f6de671
|
@ -730,7 +730,7 @@ bool glTF2Exporter::GetMatSpecGloss(const aiMaterial &mat, glTF2::PbrSpecularGlo
|
||||||
|
|
||||||
bool glTF2Exporter::GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular) {
|
bool glTF2Exporter::GetMatSpecular(const aiMaterial &mat, glTF2::MaterialSpecular &specular) {
|
||||||
// Specular requires either/or, default factors of zero disables specular, so do not export
|
// Specular requires either/or, default factors of zero disables specular, so do not export
|
||||||
if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) != AI_SUCCESS || mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) != AI_SUCCESS) {
|
if (GetMatColor(mat, specular.specularColorFactor, AI_MATKEY_COLOR_SPECULAR) != AI_SUCCESS && mat.Get(AI_MATKEY_SPECULAR_FACTOR, specular.specularFactor) != AI_SUCCESS) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// The spec states that the default is 1.0 and [1.0, 1.0, 1.0]. We if both are 0, which should disable specular. Otherwise, if one is 0, set to 1.0
|
// The spec states that the default is 1.0 and [1.0, 1.0, 1.0]. We if both are 0, which should disable specular. Otherwise, if one is 0, set to 1.0
|
||||||
|
|
|
@ -59,6 +59,31 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Checks whether the passed string is a gcs version.
|
||||||
|
bool IsGcsVersion(const std::string &s) {
|
||||||
|
if (s.empty()) return false;
|
||||||
|
return std::all_of(s.cbegin(), s.cend(), [](const char c) {
|
||||||
|
// gcs only permits numeric characters.
|
||||||
|
return std::isdigit(static_cast<int>(c));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removes a possible version hash from a filename, as found for example in
|
||||||
|
// gcs uris (e.g. `gs://bucket/model.glb#1234`), see also
|
||||||
|
// https://github.com/GoogleCloudPlatform/gsutil/blob/c80f329bc3c4011236c78ce8910988773b2606cb/gslib/storage_url.py#L39.
|
||||||
|
std::string StripVersionHash(const std::string &filename) {
|
||||||
|
const std::string::size_type pos = filename.find_last_of('#');
|
||||||
|
// Only strip if the hash is behind a possible file extension and the part
|
||||||
|
// behind the hash is a version string.
|
||||||
|
if (pos != std::string::npos && pos > filename.find_last_of('.') &&
|
||||||
|
IsGcsVersion(filename.substr(pos + 1))) {
|
||||||
|
return filename.substr(0, pos);
|
||||||
|
}
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -241,6 +266,7 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Check for file extension
|
// Check for file extension
|
||||||
/*static*/ bool BaseImporter::HasExtension(const std::string &pFile, const std::set<std::string> &extensions) {
|
/*static*/ bool BaseImporter::HasExtension(const std::string &pFile, const std::set<std::string> &extensions) {
|
||||||
|
const std::string file = StripVersionHash(pFile);
|
||||||
// CAUTION: Do not just search for the extension!
|
// CAUTION: Do not just search for the extension!
|
||||||
// GetExtension() returns the part after the *last* dot, but some extensions
|
// GetExtension() returns the part after the *last* dot, but some extensions
|
||||||
// have dots inside them, e.g. ogre.mesh.xml. Compare the entire end of the
|
// have dots inside them, e.g. ogre.mesh.xml. Compare the entire end of the
|
||||||
|
@ -248,9 +274,9 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
|
||||||
for (const std::string& ext : extensions) {
|
for (const std::string& ext : extensions) {
|
||||||
// Yay for C++<20 not having std::string::ends_with()
|
// Yay for C++<20 not having std::string::ends_with()
|
||||||
const std::string dotExt = "." + ext;
|
const std::string dotExt = "." + ext;
|
||||||
if (dotExt.length() > pFile.length()) continue;
|
if (dotExt.length() > file.length()) continue;
|
||||||
// Possible optimization: Fetch the lowercase filename!
|
// Possible optimization: Fetch the lowercase filename!
|
||||||
if (0 == ASSIMP_stricmp(pFile.c_str() + pFile.length() - dotExt.length(), dotExt.c_str())) {
|
if (0 == ASSIMP_stricmp(file.c_str() + file.length() - dotExt.length(), dotExt.c_str())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,7 +285,8 @@ void BaseImporter::GetExtensionList(std::set<std::string> &extensions) {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Get file extension from path
|
// Get file extension from path
|
||||||
std::string BaseImporter::GetExtension(const std::string &file) {
|
std::string BaseImporter::GetExtension(const std::string &pFile) {
|
||||||
|
const std::string file = StripVersionHash(pFile);
|
||||||
std::string::size_type pos = file.find_last_of('.');
|
std::string::size_type pos = file.find_last_of('.');
|
||||||
|
|
||||||
// no file extension at all
|
// no file extension at all
|
||||||
|
|
|
@ -361,3 +361,37 @@ TEST_F(ImporterTest, unexpectedException) {
|
||||||
EXPECT_TRUE(false);
|
EXPECT_TRUE(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct ExtensionTestCase {
|
||||||
|
std::string testName;
|
||||||
|
std::string filename;
|
||||||
|
std::string getExtensionResult;
|
||||||
|
std::string hasExtension;
|
||||||
|
bool hasExtensionResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ExtensionTest = ::testing::TestWithParam<ExtensionTestCase>;
|
||||||
|
|
||||||
|
TEST_P(ExtensionTest, testGetAndHasExtension) {
|
||||||
|
const ExtensionTestCase& testCase = GetParam();
|
||||||
|
EXPECT_EQ(testCase.getExtensionResult, BaseImporter::GetExtension(testCase.filename));
|
||||||
|
EXPECT_EQ(testCase.hasExtensionResult, BaseImporter::HasExtension(testCase.filename, {testCase.hasExtension}));
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
|
ExtensionTests, ExtensionTest,
|
||||||
|
::testing::ValuesIn<ExtensionTestCase>({
|
||||||
|
{"NoExtension", "name", "", "glb", false},
|
||||||
|
{"NoExtensionAndEmptyVersion", "name#", "", "glb", false},
|
||||||
|
{"WithExtensionAndEmptyVersion", "name.glb#", "glb#", "glb", false},
|
||||||
|
{"WithExtensionAndVersion", "name.glb#1234", "glb", "glb", true},
|
||||||
|
{"WithExtensionAndHashInStem", "name#1234.glb", "glb", "glb", true},
|
||||||
|
{"WithExtensionAndInvalidVersion", "name.glb#_", "glb#_", "glb", false},
|
||||||
|
{"WithExtensionAndDotAndHashInStem", "name.glb#.abc", "abc", "glb", false},
|
||||||
|
{"WithTwoExtensions", "name.abc.def", "def", "abc.def", true},
|
||||||
|
}),
|
||||||
|
[](const ::testing::TestParamInfo<ExtensionTest::ParamType>& info) {
|
||||||
|
return info.param.testName;
|
||||||
|
});
|
||||||
|
|
|
@ -60,7 +60,7 @@ using namespace Assimp;
|
||||||
|
|
||||||
class utglTF2ImportExport : public AbstractImportExportBase {
|
class utglTF2ImportExport : public AbstractImportExportBase {
|
||||||
public:
|
public:
|
||||||
virtual bool importerMatTest(const char *file, bool spec_gloss, std::array<aiTextureMapMode, 2> exp_modes = { aiTextureMapMode_Wrap, aiTextureMapMode_Wrap }) {
|
virtual bool importerMatTest(const char *file, bool spec, bool gloss, std::array<aiTextureMapMode, 2> exp_modes = { aiTextureMapMode_Wrap, aiTextureMapMode_Wrap }) {
|
||||||
Assimp::Importer importer;
|
Assimp::Importer importer;
|
||||||
const aiScene *scene = importer.ReadFile(file, aiProcess_ValidateDataStructure);
|
const aiScene *scene = importer.ReadFile(file, aiProcess_ValidateDataStructure);
|
||||||
EXPECT_NE(scene, nullptr);
|
EXPECT_NE(scene, nullptr);
|
||||||
|
@ -105,16 +105,19 @@ public:
|
||||||
|
|
||||||
aiColor3D spec_color = { 0, 0, 0 };
|
aiColor3D spec_color = { 0, 0, 0 };
|
||||||
ai_real glossiness = ai_real(0.5);
|
ai_real glossiness = ai_real(0.5);
|
||||||
if (spec_gloss) {
|
if (spec) {
|
||||||
EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_COLOR_SPECULAR, spec_color));
|
EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_COLOR_SPECULAR, spec_color));
|
||||||
constexpr ai_real spec_val(0.20000000298023225); // From the file
|
constexpr ai_real spec_val(0.20000000298023225); // From the file
|
||||||
EXPECT_EQ(spec_val, spec_color.r);
|
EXPECT_EQ(spec_val, spec_color.r);
|
||||||
EXPECT_EQ(spec_val, spec_color.g);
|
EXPECT_EQ(spec_val, spec_color.g);
|
||||||
EXPECT_EQ(spec_val, spec_color.b);
|
EXPECT_EQ(spec_val, spec_color.b);
|
||||||
|
} else {
|
||||||
|
EXPECT_EQ(aiReturn_FAILURE, material->Get(AI_MATKEY_COLOR_SPECULAR, spec_color));
|
||||||
|
}
|
||||||
|
if (gloss) {
|
||||||
EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_GLOSSINESS_FACTOR, glossiness));
|
EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_GLOSSINESS_FACTOR, glossiness));
|
||||||
EXPECT_EQ(ai_real(1.0), glossiness);
|
EXPECT_EQ(ai_real(1.0), glossiness);
|
||||||
} else {
|
} else {
|
||||||
EXPECT_EQ(aiReturn_FAILURE, material->Get(AI_MATKEY_COLOR_SPECULAR, spec_color));
|
|
||||||
EXPECT_EQ(aiReturn_FAILURE, material->Get(AI_MATKEY_GLOSSINESS_FACTOR, glossiness));
|
EXPECT_EQ(aiReturn_FAILURE, material->Get(AI_MATKEY_GLOSSINESS_FACTOR, glossiness));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +146,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(utglTF2ImportExport, importglTF2FromFileTest) {
|
TEST_F(utglTF2ImportExport, importglTF2FromFileTest) {
|
||||||
EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", false, {aiTextureMapMode_Mirror, aiTextureMapMode_Clamp}));
|
EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", false, false, {aiTextureMapMode_Mirror, aiTextureMapMode_Clamp}));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(utglTF2ImportExport, importBinaryglTF2FromFileTest) {
|
TEST_F(utglTF2ImportExport, importBinaryglTF2FromFileTest) {
|
||||||
|
@ -151,7 +154,7 @@ TEST_F(utglTF2ImportExport, importBinaryglTF2FromFileTest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(utglTF2ImportExport, importglTF2_KHR_materials_pbrSpecularGlossiness) {
|
TEST_F(utglTF2ImportExport, importglTF2_KHR_materials_pbrSpecularGlossiness) {
|
||||||
EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf", true));
|
EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf", true, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerifyClearCoatScene(const aiScene *scene) {
|
void VerifyClearCoatScene(const aiScene *scene) {
|
||||||
|
@ -223,13 +226,16 @@ TEST_F(utglTF2ImportExport, importglTF2AndExport_KHR_materials_pbrSpecularGlossi
|
||||||
// Export with specular glossiness disabled
|
// Export with specular glossiness disabled
|
||||||
EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb"));
|
EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb"));
|
||||||
|
|
||||||
|
// And re-import
|
||||||
|
EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", true, false));
|
||||||
|
|
||||||
// Export with specular glossiness enabled
|
// Export with specular glossiness enabled
|
||||||
ExportProperties props;
|
ExportProperties props;
|
||||||
props.SetPropertyBool(AI_CONFIG_USE_GLTF_PBR_SPECULAR_GLOSSINESS, true);
|
props.SetPropertyBool(AI_CONFIG_USE_GLTF_PBR_SPECULAR_GLOSSINESS, true);
|
||||||
EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", 0, &props));
|
EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", 0, &props));
|
||||||
|
|
||||||
// And re-import
|
// And re-import
|
||||||
EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", true));
|
EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", true, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(utglTF2ImportExport, importglTF2AndExportToOBJ) {
|
TEST_F(utglTF2ImportExport, importglTF2AndExportToOBJ) {
|
||||||
|
|
Loading…
Reference in New Issue