diff --git a/include/vsgXchange/models.h b/include/vsgXchange/models.h index 5c0d032..1a060ad 100644 --- a/include/vsgXchange/models.h +++ b/include/vsgXchange/models.h @@ -54,6 +54,8 @@ namespace vsgXchange static constexpr const char* crease_angle = "crease_angle"; /// float static constexpr const char* two_sided = "two_sided"; /// bool static constexpr const char* discard_empty_nodes = "discard_empty_nodes"; /// bool + static constexpr const char* external_textures = "external_textures"; /// bool + static constexpr const char* external_texture_format = "external_texture_format"; /// TextureFormat enum bool readOptions(vsg::Options& options, vsg::CommandLine& arguments) const override; diff --git a/src/assimp/assimp.cpp b/src/assimp/assimp.cpp index 25887af..0ab7163 100644 --- a/src/assimp/assimp.cpp +++ b/src/assimp/assimp.cpp @@ -16,6 +16,31 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include +enum class TextureFormat +{ + native, + vsgt, + vsgb +}; + +// this needs to be defined before 'vsg/commandline.h' has been included +std::istream& operator>> (std::istream& is, TextureFormat& textureFormat) +{ + std::string value; + is >> value; + + if (value == "native") + textureFormat = TextureFormat::native; + else if (value == "vsgb") + textureFormat = TextureFormat::vsgb; + else if ((value == "vsgt")||(value == "vsga")) + textureFormat = TextureFormat::vsgt; + else + textureFormat = TextureFormat::native; + + return is; +} + #include #include @@ -117,6 +142,8 @@ bool assimp::getFeatures(Features& features) const features.optionNameTypeMap[assimp::crease_angle] = vsg::type_name(); features.optionNameTypeMap[assimp::two_sided] = vsg::type_name(); features.optionNameTypeMap[assimp::discard_empty_nodes] = vsg::type_name(); + features.optionNameTypeMap[assimp::external_textures] = vsg::type_name(); + features.optionNameTypeMap[assimp::external_texture_format] = vsg::type_name(); return true; } @@ -128,6 +155,9 @@ bool assimp::readOptions(vsg::Options& options, vsg::CommandLine& arguments) con result = arguments.readAndAssign(assimp::crease_angle, &options) || result; result = arguments.readAndAssign(assimp::two_sided, &options) || result; result = arguments.readAndAssign(assimp::discard_empty_nodes, &options) || result; + result = arguments.readAndAssign(assimp::external_textures, &options) || result; + result = arguments.readAndAssign(assimp::external_texture_format, &options) || result; + return result; } @@ -149,11 +179,14 @@ struct SceneConverter bool useViewDependentState = true; bool discardEmptyNodes = true; + bool externalTextures = false; + TextureFormat externalTextureFormat = TextureFormat::native; // TODO flatShadedShaderSet? vsg::ref_ptr pbrShaderSet; vsg::ref_ptr phongShaderSet; vsg::ref_ptr sharedObjects; + vsg::ref_ptr externalObjects; std::vector> convertedMaterials; std::vector> convertedMeshes; @@ -250,6 +283,7 @@ SamplerData SceneConverter::convertTexture(const aiMaterial& material, aiTexture if (material.GetTexture(type, 0, &texPath, nullptr, nullptr, nullptr, nullptr, wrapMode) == AI_SUCCESS) { SamplerData samplerImage; + vsg::Path externalTextureFilename; if (auto texture = scene->GetEmbeddedTexture(texPath.C_Str())) { @@ -288,10 +322,10 @@ SamplerData SceneConverter::convertTexture(const aiMaterial& material, aiTexture } else { - auto textureFilename = vsg::findFile(texPath.C_Str(), options); - if (samplerImage.data = vsg::read_cast(textureFilename, options); !samplerImage.data.valid()) + externalTextureFilename = vsg::findFile(texPath.C_Str(), options); + if (samplerImage.data = vsg::read_cast(externalTextureFilename, options); !samplerImage.data.valid()) { - vsg::warn("Failed to load texture: ", textureFilename, " texPath = ", texPath.C_Str()); + vsg::warn("Failed to load texture: ", externalTextureFilename, " texPath = ", texPath.C_Str()); return {}; } } @@ -317,6 +351,40 @@ SamplerData SceneConverter::convertTexture(const aiMaterial& material, aiTexture sharedObjects->share(samplerImage.sampler); } + if (externalTextures && externalObjects) + { + // calculate the texture filename + switch (externalTextureFormat) + { + case TextureFormat::native: + break; // nothing to do + case TextureFormat::vsgt: + externalTextureFilename = vsg::removeExtension(externalTextureFilename).concat(".vsgt"); + break; + case TextureFormat::vsgb: + externalTextureFilename = vsg::removeExtension(externalTextureFilename).concat(".vsgb"); + break; + } + + // actually write out the texture.. this need only be done once per texture! + if (externalObjects->entries.count(externalTextureFilename) == 0) + { + switch (externalTextureFormat) + { + case TextureFormat::native: + break; // nothing to do + case TextureFormat::vsgt: + vsg::write(samplerImage.data, externalTextureFilename, options); + break; + case TextureFormat::vsgb: + vsg::write(samplerImage.data, externalTextureFilename, options); + break; + } + + externalObjects->add(externalTextureFilename, samplerImage.data); + } + } + return samplerImage; } else @@ -717,11 +785,14 @@ vsg::ref_ptr SceneConverter::visit(const aiScene* in_scene, vsg::ref_ scene = in_scene; options = in_options; discardEmptyNodes = vsg::value(true, assimp::discard_empty_nodes, options); + externalTextures = vsg::value(false, assimp::external_textures, options); + externalTextureFormat = vsg::value(TextureFormat::native, assimp::external_texture_format, options); std::string name = scene->mName.C_Str(); if (options) sharedObjects = options->sharedObjects; if (!sharedObjects) sharedObjects = vsg::SharedObjects::create(); + if (externalTextures && !externalObjects) externalObjects = vsg::External::create(); processCameras(); processLights(); @@ -1023,7 +1094,15 @@ vsg::ref_ptr assimp::Implementation::read(const vsg::Path& filename SceneConverter converter; converter.filename = filename; - return converter.visit(scene, opt, ext); + + auto root = converter.visit(scene, opt, ext); + if (root) + { + if (converter.externalTextures && converter.externalObjects && !converter.externalObjects->entries.empty()) + root->setObject("external", converter.externalObjects); + } + + return root; } else { @@ -1038,7 +1117,7 @@ vsg::ref_ptr assimp::Implementation::read(const vsg::Path& filename opt->paths.push_back(vsg::filePath(filename)); opt->extensionHint = vsg::lowerCaseFileExtension(filename); - return read(file, opt); + return vsg::read(file, opt); #endif return {};