USD IO: use asset resolver to copy textures.
Updated the code to invoke the USD asset resolver for texture import and export. This removes the assumption that assets are specified as file system paths. Added logic to allow importing textures from paths that are not package relative. The new heuristics will attempt to import files that don't exist on the file system, but which can be resolved with the USD asset resolver, to allow importing textures from URIs.
This commit is contained in:
@@ -387,7 +387,17 @@ bool BKE_cachefile_filepath_get(const Main *bmain,
|
||||
char r_filepath[FILE_MAX])
|
||||
{
|
||||
BLI_strncpy(r_filepath, cache_file->filepath, FILE_MAX);
|
||||
|
||||
#ifdef WITH_USD
|
||||
if (BLI_path_extension_check_glob(r_filepath, "*.usd;*.usda;*.usdc;*.usdz")) {
|
||||
USD_path_abs(r_filepath, ID_BLEND_PATH(bmain, &cache_file->id), true /* for import */);
|
||||
}
|
||||
else {
|
||||
BLI_path_abs(r_filepath, ID_BLEND_PATH(bmain, &cache_file->id));
|
||||
}
|
||||
#else
|
||||
BLI_path_abs(r_filepath, ID_BLEND_PATH(bmain, &cache_file->id));
|
||||
#endif
|
||||
|
||||
int fframe;
|
||||
int frame_len;
|
||||
|
@@ -8,6 +8,7 @@
|
||||
#include <pxr/usd/ar/resolver.h>
|
||||
#include <pxr/usd/ar/writableAsset.h>
|
||||
|
||||
#include "BKE_appdir.h"
|
||||
#include "BKE_main.h"
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
@@ -300,4 +301,108 @@ bool is_udim_path(const std::string &path)
|
||||
path.find(UDIM_PATTERN2) != std::string::npos;
|
||||
}
|
||||
|
||||
std::string get_export_textures_dir(const pxr::UsdStageRefPtr stage)
|
||||
{
|
||||
pxr::SdfLayerHandle layer = stage->GetRootLayer();
|
||||
|
||||
if (layer->IsAnonymous()) {
|
||||
WM_reportf(
|
||||
RPT_WARNING, "%s: Can't generate a textures directory path for anonymous stage", __func__);
|
||||
return "";
|
||||
}
|
||||
|
||||
pxr::ArResolvedPath stage_path = layer->GetResolvedPath();
|
||||
|
||||
if (stage_path.empty()) {
|
||||
WM_reportf(
|
||||
RPT_WARNING, "%s: Can't get resolved path for stage", __func__);
|
||||
return "";
|
||||
}
|
||||
|
||||
pxr::ArResolver &ar = pxr::ArGetResolver();
|
||||
|
||||
/* Resolove the './textures' relative path, with the stage path as an anchor. */
|
||||
std::string textures_dir = ar.CreateIdentifierForNewAsset("./textures", stage_path);
|
||||
|
||||
/* If parent of the stage path exists as a file system directory, try to create the
|
||||
* textures directory. */
|
||||
if (parent_dir_exists_on_file_system(stage_path.GetPathString().c_str())) {
|
||||
BLI_dir_create_recursive(textures_dir.c_str());
|
||||
}
|
||||
|
||||
return textures_dir;
|
||||
}
|
||||
|
||||
bool parent_dir_exists_on_file_system(const char *path)
|
||||
{
|
||||
char dir_path[FILE_MAX];
|
||||
BLI_split_dir_part(path, dir_path, FILE_MAX);
|
||||
return BLI_is_dir(dir_path);
|
||||
}
|
||||
|
||||
bool should_import_asset(const std::string &path)
|
||||
{
|
||||
if (BLI_path_is_rel(path.c_str())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pxr::ArIsPackageRelativePath(path)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !BLI_is_file(path.c_str()) && asset_exists(path.c_str());
|
||||
}
|
||||
|
||||
bool paths_equal(const char *p1, const char *p2)
|
||||
{
|
||||
BLI_assert_msg(!BLI_path_is_rel(p1) && !BLI_path_is_rel(p2),
|
||||
"Paths arguments must be absolute");
|
||||
|
||||
pxr::ArResolver &ar = pxr::ArGetResolver();
|
||||
|
||||
std::string resolved_p1 = ar.ResolveForNewAsset(p1).GetPathString();
|
||||
std::string resolved_p2 = ar.ResolveForNewAsset(p2).GetPathString();
|
||||
|
||||
return resolved_p1 == resolved_p2;
|
||||
}
|
||||
|
||||
const char *temp_textures_dir()
|
||||
{
|
||||
static bool inited = false;
|
||||
|
||||
static char temp_dir[FILE_MAXDIR] = {'\0'};
|
||||
|
||||
if (!inited) {
|
||||
BLI_path_join(temp_dir, sizeof(temp_dir), BKE_tempdir_session(), "usd_textures_tmp", SEP_STR);
|
||||
inited = true;
|
||||
}
|
||||
|
||||
return temp_dir;
|
||||
}
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
||||
|
||||
void USD_path_abs(char *path, const char *basepath, bool for_import)
|
||||
{
|
||||
if (!BLI_path_is_rel(path)) {
|
||||
pxr::ArResolvedPath resolved_path = for_import ? pxr::ArGetResolver().Resolve(path) :
|
||||
pxr::ArGetResolver().ResolveForNewAsset(path);
|
||||
|
||||
std::string path_str = resolved_path.GetPathString();
|
||||
|
||||
if (!path_str.empty()) {
|
||||
if (path_str.length() < FILE_MAX) {
|
||||
BLI_strncpy(path, path_str.c_str(), FILE_MAX);
|
||||
return;
|
||||
}
|
||||
WM_reportf(RPT_ERROR,
|
||||
"In %s: resolved path %s exceeds path buffer length.", __func__,
|
||||
path_str.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/* If we got here, the path couldn't be resolved by the ArResolver, so we
|
||||
* fall back on the standard Blender absolute path resolution. */
|
||||
BLI_path_abs(path, basepath);
|
||||
}
|
||||
|
@@ -54,4 +54,64 @@ std::string import_asset(const char *src,
|
||||
*/
|
||||
bool is_udim_path(const std::string &path);
|
||||
|
||||
/**
|
||||
* Invoke the USD asset resolver to return an identifier for a 'textures' directory
|
||||
* which is a sibling of the given stage. The resulting path is created by
|
||||
* resolving the './textures' relative path with the stage's root layer path as
|
||||
* the anchor. If the parent of the stage root layer path resolves to a file
|
||||
* system path, the textures directory will be created, if it doesn't exist.
|
||||
*
|
||||
* \param stage: The stage whose root layer is a sibling of the 'textures'
|
||||
* directory
|
||||
* \return the path to the 'textures' directory
|
||||
*/
|
||||
std::string get_export_textures_dir(const pxr::UsdStageRefPtr stage);
|
||||
|
||||
/**
|
||||
* Returns true if the parent directory of the given path exists on the
|
||||
* file system.
|
||||
*
|
||||
* \param path: input file path
|
||||
* \return true if the parent directory exists
|
||||
*/
|
||||
bool parent_dir_exists_on_file_system(const char *path);
|
||||
|
||||
/**
|
||||
* Return true if the asset at the given path is a candidate for importing
|
||||
* with the USD asset resolver. The following heuristics are currently
|
||||
* applied for this test:
|
||||
* - Returns false if it's a Blender relative path.
|
||||
* - Returns true if the path is package-relative.
|
||||
* - Returns true is the path doesn't exist on the file system but can
|
||||
* nonetheles be resolved by the USD asset resolver.
|
||||
* - Returns false otherwise.
|
||||
*
|
||||
* TODO(makowalski): the test currently requires a file-system stat.
|
||||
* Consider possible ways around this, e.g., by determining if the
|
||||
* path is a supported URI.
|
||||
*
|
||||
* \param path: input file path
|
||||
* \return true if the path should be imported, false otherwise
|
||||
*/
|
||||
bool should_import_asset(const std::string &path);
|
||||
|
||||
/**
|
||||
* Invokes the USD asset resolver to resolve the givn paths and
|
||||
* returns true if the resolved paths are equal.
|
||||
*
|
||||
* \param p1: first path to compare
|
||||
* \param p2: second path to compare
|
||||
* \return true if the resolved input paths are equal, returns
|
||||
* false otherwise.
|
||||
*
|
||||
*/
|
||||
bool paths_equal(const char *p1, const char *p2);
|
||||
|
||||
|
||||
/**
|
||||
* Returns path to temporary folder for saving imported textures prior to packing.
|
||||
* CAUTION: this directory is recursively deleted after material import.
|
||||
*/
|
||||
const char *temp_textures_dir();
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
@@ -2,6 +2,7 @@
|
||||
* Copyright 2019 Blender Foundation. All rights reserved. */
|
||||
|
||||
#include "usd.h"
|
||||
#include "usd_asset_utils.h"
|
||||
#include "usd_common.h"
|
||||
#include "usd_hierarchy_iterator.h"
|
||||
#include "usd_light_convert.h"
|
||||
@@ -342,10 +343,9 @@ static bool perform_usdz_conversion(const ExportJobData *data)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
result = BLI_rename(usdz_temp_dirfile, data->usdz_filepath);
|
||||
if (result != 0) {
|
||||
if (!copy_asset(usdz_temp_dirfile, data->usdz_filepath, USD_TEX_NAME_COLLISION_OVERWRITE)) {
|
||||
WM_reportf(RPT_ERROR,
|
||||
"USD Export: Couldn't move new usdz file from temporary location %s to %s",
|
||||
"USD Export: Couldn't copy new usdz file from temporary location %s to %s",
|
||||
usdz_temp_dirfile,
|
||||
data->usdz_filepath);
|
||||
return false;
|
||||
|
@@ -386,7 +386,7 @@ static void import_startjob(void *customdata, bool *stop, bool *do_update, float
|
||||
data->view_layer, import_collection);
|
||||
}
|
||||
|
||||
BLI_path_abs(data->filepath, BKE_main_blendfile_path_from_global());
|
||||
USD_path_abs(data->filepath, BKE_main_blendfile_path_from_global(), true);
|
||||
|
||||
*data->do_update = true;
|
||||
*data->progress = 0.05f;
|
||||
|
@@ -2,10 +2,17 @@
|
||||
* Copyright 2021 Blender Foundation. All rights reserved. */
|
||||
|
||||
#include "usd_common.h"
|
||||
#include "usd.h"
|
||||
|
||||
#include <pxr/usd/ar/resolver.h>
|
||||
#include <pxr/base/plug/registry.h>
|
||||
|
||||
#include "BKE_appdir.h"
|
||||
#include "BLI_path_util.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
#include "WM_types.h"
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
||||
|
@@ -81,23 +81,6 @@ static const pxr::TfToken UsdPrimvarReader_float2("UsdPrimvarReader_float2",
|
||||
static const pxr::TfToken UsdUVTexture("UsdUVTexture", pxr::TfToken::Immortal);
|
||||
} // namespace usdtokens
|
||||
|
||||
/* Temporary folder for saving imported textures prior to packing.
|
||||
* CAUTION: this directory is recursively deleted after material
|
||||
* import. */
|
||||
static const char *temp_textures_dir()
|
||||
{
|
||||
static bool inited = false;
|
||||
|
||||
static char temp_dir[FILE_MAXDIR] = {'\0'};
|
||||
|
||||
if (!inited) {
|
||||
BLI_path_join(temp_dir, sizeof(temp_dir), BKE_tempdir_session(), "usd_textures_tmp", SEP_STR);
|
||||
inited = true;
|
||||
}
|
||||
|
||||
return temp_dir;
|
||||
}
|
||||
|
||||
/* Add a node of the given type at the given location coordinates. */
|
||||
static bNode *add_node(
|
||||
const bContext *C, bNodeTree *ntree, const int type, const float locx, const float locy)
|
||||
@@ -405,9 +388,14 @@ Material *USDMaterialReader::add_material(const pxr::UsdShadeMaterial &usd_mater
|
||||
}
|
||||
else if (params_.import_shaders_mode == USD_IMPORT_MDL) {
|
||||
bool has_mdl = false;
|
||||
bool mdl_imported = false;
|
||||
#ifdef WITH_PYTHON
|
||||
/* Invoke UMM to convert to MDL. */
|
||||
bool mdl_imported = umm_import_mdl_material(mtl, usd_material, true /* Verbose */, &has_mdl);
|
||||
mdl_imported = umm_import_mdl_material(params_, mtl, usd_material, true /* Verbose */, &has_mdl);
|
||||
if (mdl_imported && params_.import_textures_mode == USD_TEX_IMPORT_PACK) {
|
||||
/* Process the imported material to pack the textures. */
|
||||
pack_imported_textures(mtl);
|
||||
}
|
||||
#endif
|
||||
if (!(has_mdl && mdl_imported) && usd_preview) {
|
||||
/* The material has no MDL shader or we couldn't convert the MDL,
|
||||
@@ -814,7 +802,7 @@ void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader,
|
||||
/* Optionally copy the asset if it's inside a USDZ package. */
|
||||
|
||||
const bool import_textures = params_.import_textures_mode != USD_TEX_IMPORT_NONE &&
|
||||
pxr::ArIsPackageRelativePath(file_path);
|
||||
should_import_asset(file_path);
|
||||
|
||||
if (import_textures) {
|
||||
/* If we are packing the imported textures, we first write them
|
||||
@@ -927,6 +915,39 @@ void USDMaterialReader::convert_usd_primvar_reader_float2(
|
||||
link_nodes(ntree, uv_map, "UV", dest_node, dest_socket_name);
|
||||
}
|
||||
|
||||
void USDMaterialReader::pack_imported_textures(Material *material, bool delete_temp_textures_dir) const
|
||||
{
|
||||
if (!(material && material->use_nodes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (bNode *node = (bNode *)material->nodetree->nodes.first; node; node = node->next) {
|
||||
if (!(ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT))) {
|
||||
continue;
|
||||
}
|
||||
Image *image = reinterpret_cast<Image *>(node->id);
|
||||
if (!image || BKE_image_has_packedfile(image)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (image->filepath[0] == '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
char dir_path[FILE_MAXDIR];
|
||||
BLI_split_dir_part(image->filepath, dir_path, sizeof(dir_path));
|
||||
|
||||
if (BLI_path_cmp_normalized(dir_path, temp_textures_dir()) == 0) {
|
||||
/* Texture was saved to the temporary import directory, so pack it. */
|
||||
BKE_image_packfiles(nullptr, image, ID_BLEND_PATH(bmain_, &image->id));
|
||||
}
|
||||
}
|
||||
|
||||
if (delete_temp_textures_dir && BLI_is_dir(temp_textures_dir())) {
|
||||
BLI_delete(temp_textures_dir(), true, true);
|
||||
}
|
||||
}
|
||||
|
||||
void build_material_map(const Main *bmain, std::map<std::string, Material *> *r_mat_map)
|
||||
{
|
||||
BLI_assert_msg(r_mat_map, "...");
|
||||
|
@@ -127,6 +127,12 @@ class USDMaterialReader {
|
||||
bNodeTree *ntree,
|
||||
int column,
|
||||
NodePlacementContext *r_ctx) const;
|
||||
|
||||
/**
|
||||
* Pack imported textures referenced by this material and optionally delete
|
||||
* the temporary textures import directory when done processing.
|
||||
*/
|
||||
void pack_imported_textures(Material *material, bool delete_temp_textures_dir=true) const;
|
||||
};
|
||||
|
||||
/* Utility functions. */
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
# include "usd_umm.h"
|
||||
# include "usd.h"
|
||||
# include "usd_asset_utils.h"
|
||||
# include "usd_exporter_context.h"
|
||||
# include "usd_writer_material.h"
|
||||
|
||||
@@ -380,7 +381,8 @@ static void test_python()
|
||||
PyGILState_Release(gilstate);
|
||||
}
|
||||
|
||||
static PyObject *get_shader_source_data(const pxr::UsdShadeShader &usd_shader)
|
||||
static PyObject *get_shader_source_data(const USDImportParams ¶ms,
|
||||
const pxr::UsdShadeShader &usd_shader)
|
||||
{
|
||||
if (!usd_shader) {
|
||||
return nullptr;
|
||||
@@ -463,6 +465,24 @@ static PyObject *get_shader_source_data(const pxr::UsdShadeShader &usd_shader)
|
||||
asset_path.GetAssetPath());
|
||||
}
|
||||
|
||||
const bool import_textures = params.import_textures_mode != USD_TEX_IMPORT_NONE &&
|
||||
should_import_asset(resolved_path);
|
||||
|
||||
if (import_textures) {
|
||||
/* If we are packing the imported textures, we first write them
|
||||
* to a temporary directory. */
|
||||
const char *textures_dir = params.import_textures_mode == USD_TEX_IMPORT_PACK ?
|
||||
temp_textures_dir() :
|
||||
params.import_textures_dir;
|
||||
|
||||
const eUSDTexNameCollisionMode name_collision_mode = params.import_textures_mode ==
|
||||
USD_TEX_IMPORT_PACK ?
|
||||
USD_TEX_NAME_COLLISION_OVERWRITE :
|
||||
params.tex_name_collision_mode;
|
||||
|
||||
resolved_path = import_asset(resolved_path.c_str(), textures_dir, name_collision_mode);
|
||||
}
|
||||
|
||||
pxr::TfToken color_space_tok = usd_attr.GetColorSpace();
|
||||
|
||||
if (color_space_tok.IsEmpty() && have_connected_source) {
|
||||
@@ -527,7 +547,8 @@ static PyObject *get_shader_source_data(const pxr::UsdShadeShader &usd_shader)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool import_material(Material *mtl,
|
||||
static bool import_material(const USDImportParams ¶ms,
|
||||
Material *mtl,
|
||||
const pxr::UsdShadeShader &usd_shader,
|
||||
const std::string &source_class)
|
||||
{
|
||||
@@ -558,7 +579,7 @@ static bool import_material(Material *mtl,
|
||||
return false;
|
||||
}
|
||||
|
||||
PyObject *source_data = get_shader_source_data(usd_shader);
|
||||
PyObject *source_data = get_shader_source_data(params, usd_shader);
|
||||
|
||||
if (!source_data) {
|
||||
std::cout << "WARNING: Couldn't get source data for shader " << usd_shader.GetPath()
|
||||
@@ -747,7 +768,8 @@ bool umm_module_loaded()
|
||||
return loaded;
|
||||
}
|
||||
|
||||
bool umm_import_mdl_material(Material *mtl,
|
||||
bool umm_import_mdl_material(const USDImportParams ¶ms,
|
||||
Material *mtl,
|
||||
const pxr::UsdShadeMaterial &usd_material,
|
||||
bool verbose,
|
||||
bool *r_has_mdl)
|
||||
@@ -796,7 +818,7 @@ bool umm_import_mdl_material(Material *mtl,
|
||||
}
|
||||
|
||||
std::string source_class = path + "|" + source_asset_sub_identifier.GetString();
|
||||
return import_material(mtl, surf_shader, source_class);
|
||||
return import_material(params, mtl, surf_shader, source_class);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@@ -24,6 +24,7 @@
|
||||
# include "Python.h"
|
||||
|
||||
struct Material;
|
||||
struct USDImportParams;
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
||||
@@ -31,7 +32,8 @@ struct USDExporterContext;
|
||||
|
||||
bool umm_module_loaded();
|
||||
|
||||
bool umm_import_mdl_material(Material *mtl,
|
||||
bool umm_import_mdl_material(const USDImportParams ¶ms,
|
||||
Material *mtl,
|
||||
const pxr::UsdShadeMaterial &usd_material,
|
||||
bool verbose,
|
||||
bool *r_has_material);
|
||||
|
@@ -238,13 +238,13 @@ pxr::UsdShadeMaterial USDAbstractWriter::ensure_usd_material(const HierarchyCont
|
||||
usd_material,
|
||||
this->usd_export_context_.export_params);
|
||||
if (this->usd_export_context_.export_params.export_textures) {
|
||||
export_textures(material, this->usd_export_context_.stage);
|
||||
export_textures(material, this->usd_export_context_.stage, this->usd_export_context_.export_params.overwrite_textures);
|
||||
}
|
||||
}
|
||||
if (material->use_nodes && this->usd_export_context_.export_params.generate_mdl) {
|
||||
create_mdl_material(this->usd_export_context_, material, usd_material);
|
||||
if (this->usd_export_context_.export_params.export_textures) {
|
||||
export_textures(material, this->usd_export_context_.stage);
|
||||
export_textures(material, this->usd_export_context_.stage, this->usd_export_context_.export_params.overwrite_textures);
|
||||
}
|
||||
}
|
||||
if (material->use_nodes && this->usd_export_context_.export_params.generate_preview_surface) {
|
||||
|
@@ -3,9 +3,11 @@
|
||||
#include "usd_writer_material.h"
|
||||
|
||||
#include "usd.h"
|
||||
#include "usd_asset_utils.h"
|
||||
#include "usd_exporter_context.h"
|
||||
#include "usd_umm.h"
|
||||
|
||||
#include "BKE_appdir.h"
|
||||
#include "BKE_colorband.h"
|
||||
#include "BKE_colortools.h"
|
||||
#include "BKE_curve.h"
|
||||
@@ -458,21 +460,55 @@ static void export_in_memory_texture(Image *ima,
|
||||
|
||||
char export_path[FILE_MAX];
|
||||
BLI_path_join(export_path, FILE_MAX, export_dir.c_str(), file_name);
|
||||
BLI_str_replace_char(export_path, '\\', '/');
|
||||
|
||||
if (!allow_overwrite && BLI_exists(export_path)) {
|
||||
if (!allow_overwrite && asset_exists(export_path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((BLI_path_cmp_normalized(export_path, image_abs_path) == 0) && BLI_exists(image_abs_path)) {
|
||||
if (paths_equal(export_path, image_abs_path) && asset_exists(image_abs_path)) {
|
||||
/* As a precaution, don't overwrite the original path. */
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "Exporting in-memory texture to " << export_path << std::endl;
|
||||
|
||||
if (BKE_imbuf_write_as(imbuf, export_path, &imageFormat, true) == 0) {
|
||||
WM_reportf(RPT_WARNING, "USD export: couldn't export in-memory texture to %s", export_path);
|
||||
if (BLI_is_dir(export_dir.c_str())) {
|
||||
/* We are copying to a file system directory, so we can write the image buffer
|
||||
* directly to the destination. */
|
||||
if (BKE_imbuf_write_as(imbuf, export_path, &imageFormat, true) == 0) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD export: couldn't save in-memory texture to %s", export_path);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we got here, the export directory path is not on the file system, which
|
||||
* would be the case if we the path is a URI. We therefore can't save the image
|
||||
* directly (because BKE_imbuf_write_as() can't resolve URIs) and must save
|
||||
* the image to a temporary location on disk before copyig it to its final
|
||||
* destination. */
|
||||
|
||||
char temp_filepath[FILE_MAX];
|
||||
BLI_path_join(temp_filepath, FILE_MAX, BKE_tempdir_session(), file_name);
|
||||
|
||||
std::cout << "Saving in-memory texture to temporary location " << temp_filepath << std::endl;
|
||||
|
||||
if (BKE_imbuf_write_as(imbuf, temp_filepath, &imageFormat, true) == 0) {
|
||||
WM_reportf(RPT_WARNING, "USD export: couldn't save in-memory texture to temporary location %s", temp_filepath);
|
||||
}
|
||||
|
||||
/* Copy to destination. */
|
||||
if (!copy_asset(temp_filepath,
|
||||
export_path,
|
||||
allow_overwrite ? USD_TEX_NAME_COLLISION_OVERWRITE :
|
||||
USD_TEX_NAME_COLLISION_USE_EXISTING)) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD export: couldn't export in-memory texture to %s",
|
||||
temp_filepath);
|
||||
}
|
||||
|
||||
BLI_delete(temp_filepath, false, false);
|
||||
}
|
||||
|
||||
/* Get the absolute filepath of the given image. Assumes
|
||||
@@ -481,8 +517,7 @@ static void get_absolute_path(Image *ima, char *r_path)
|
||||
{
|
||||
/* Make absolute source path. */
|
||||
BLI_strncpy(r_path, ima->filepath, FILE_MAX);
|
||||
BLI_path_abs(r_path, ID_BLEND_PATH_FROM_GLOBAL(&ima->id));
|
||||
BLI_path_normalize(nullptr, r_path);
|
||||
USD_path_abs(r_path, ID_BLEND_PATH_FROM_GLOBAL(&ima->id), false /* Not for import */);
|
||||
}
|
||||
|
||||
/* ===== Functions copied from inacessible source file
|
||||
@@ -2347,6 +2382,10 @@ static void copy_tiled_textures(Image *ima,
|
||||
return;
|
||||
}
|
||||
|
||||
const eUSDTexNameCollisionMode tex_name_collision_mode = allow_overwrite ?
|
||||
USD_TEX_NAME_COLLISION_OVERWRITE :
|
||||
USD_TEX_NAME_COLLISION_USE_EXISTING;
|
||||
|
||||
/* Copy all tiles. */
|
||||
LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) {
|
||||
char src_tile_path[FILE_MAX];
|
||||
@@ -2358,21 +2397,21 @@ static void copy_tiled_textures(Image *ima,
|
||||
|
||||
char dest_tile_path[FILE_MAX];
|
||||
BLI_path_join(dest_tile_path, FILE_MAX, dest_dir.c_str(), dest_filename);
|
||||
BLI_str_replace_char(dest_tile_path, '\\', '/');
|
||||
|
||||
if (!allow_overwrite && BLI_exists(dest_tile_path)) {
|
||||
if (!allow_overwrite && asset_exists(dest_tile_path)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (BLI_path_cmp_normalized(src_tile_path, dest_tile_path) == 0) {
|
||||
if (paths_equal(src_tile_path, dest_tile_path)) {
|
||||
/* Source and destination paths are the same, don't copy. */
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cout << "Copying texture tile from " << src_tile_path << " to " << dest_tile_path
|
||||
<< std::endl;
|
||||
|
||||
/* Copy the file. */
|
||||
if (BLI_copy(src_tile_path, dest_tile_path) != 0) {
|
||||
if (!copy_asset(src_tile_path,
|
||||
dest_tile_path,
|
||||
tex_name_collision_mode)) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD export: couldn't copy texture tile from %s to %s",
|
||||
src_tile_path,
|
||||
@@ -2393,20 +2432,22 @@ static void copy_single_file(Image *ima, const std::string &dest_dir, const bool
|
||||
|
||||
char dest_path[FILE_MAX];
|
||||
BLI_path_join(dest_path, FILE_MAX, dest_dir.c_str(), file_name);
|
||||
BLI_str_replace_char(dest_path, '\\', '/');
|
||||
|
||||
if (!allow_overwrite && BLI_exists(dest_path)) {
|
||||
if (!allow_overwrite && asset_exists(dest_path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (BLI_path_cmp_normalized(source_path, dest_path) == 0) {
|
||||
if (paths_equal(source_path, dest_path)) {
|
||||
/* Source and destination paths are the same, don't copy. */
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "Copying texture from " << source_path << " to " << dest_path << std::endl;
|
||||
|
||||
/* Copy the file. */
|
||||
if (BLI_copy(source_path, dest_path) != 0) {
|
||||
if (!copy_asset(source_path,
|
||||
dest_path,
|
||||
allow_overwrite ? USD_TEX_NAME_COLLISION_OVERWRITE :
|
||||
USD_TEX_NAME_COLLISION_USE_EXISTING)) {
|
||||
WM_reportf(
|
||||
RPT_WARNING, "USD export: couldn't copy texture from %s to %s", source_path, dest_path);
|
||||
}
|
||||
@@ -2428,22 +2469,13 @@ void export_texture(bNode *node,
|
||||
return;
|
||||
}
|
||||
|
||||
pxr::SdfLayerHandle layer = stage->GetRootLayer();
|
||||
std::string stage_path = layer->GetRealPath();
|
||||
if (stage_path.empty()) {
|
||||
std::string dest_dir = get_export_textures_dir(stage);
|
||||
|
||||
if (dest_dir.empty()) {
|
||||
WM_reportf(RPT_WARNING, "%s: Couldn't determine textures directory path", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
char usd_dir_path[FILE_MAX];
|
||||
BLI_split_dir_part(stage_path.c_str(), usd_dir_path, FILE_MAX);
|
||||
|
||||
char tex_dir_path[FILE_MAX];
|
||||
BLI_path_join(tex_dir_path, FILE_MAX, usd_dir_path, "textures", SEP_STR);
|
||||
|
||||
BLI_dir_create_recursive(tex_dir_path);
|
||||
|
||||
std::string dest_dir(tex_dir_path);
|
||||
|
||||
if (is_in_memory_texture(ima)) {
|
||||
export_in_memory_texture(ima, dest_dir, allow_overwrite);
|
||||
}
|
||||
@@ -2456,7 +2488,7 @@ void export_texture(bNode *node,
|
||||
}
|
||||
|
||||
/* Export the texture of every texture image node in the given material's node tree. */
|
||||
void export_textures(const Material *material, const pxr::UsdStageRefPtr stage)
|
||||
void export_textures(const Material *material, const pxr::UsdStageRefPtr stage, const bool allow_overwrite)
|
||||
{
|
||||
if (!(material && material->use_nodes)) {
|
||||
return;
|
||||
@@ -2467,8 +2499,8 @@ void export_textures(const Material *material, const pxr::UsdStageRefPtr stage)
|
||||
}
|
||||
|
||||
for (bNode *node = (bNode *)material->nodetree->nodes.first; node; node = node->next) {
|
||||
if (node->type == SH_NODE_TEX_IMAGE || SH_NODE_TEX_ENVIRONMENT) {
|
||||
export_texture(node, stage);
|
||||
if (ELEM(node->type, SH_NODE_TEX_IMAGE, SH_NODE_TEX_ENVIRONMENT)) {
|
||||
export_texture(node, stage, allow_overwrite);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -74,7 +74,9 @@ std::string get_tex_image_asset_path(const std::string &asset_path,
|
||||
const pxr::UsdStageRefPtr stage,
|
||||
const USDExportParams &export_params);
|
||||
|
||||
void export_textures(const Material *material, const pxr::UsdStageRefPtr stage);
|
||||
void export_textures(const Material *material,
|
||||
const pxr::UsdStageRefPtr stage,
|
||||
bool allow_overwrite = false);
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
||||
|
@@ -234,6 +234,12 @@ bool USD_umm_module_loaded(void);
|
||||
|
||||
/* USD Import and Mesh Cache interface. */
|
||||
|
||||
/* Similar to BLI_path_abs(), but also invokes the USD asset resolver
|
||||
* to determine the absolute path. This is necessary for resolving
|
||||
* paths with URIs that BLI_path_abs() would otherwise alter when
|
||||
* attempting to normalize the path. */
|
||||
void USD_path_abs(char *path, const char *basepath, bool for_import);
|
||||
|
||||
struct CacheArchiveHandle *USD_create_handle(struct Main *bmain,
|
||||
const char *filepath,
|
||||
struct ListBase *object_paths);
|
||||
|
Reference in New Issue
Block a user