Make wmJob worker thread use their own reports list instead of WM one. #113548
|
@ -179,7 +179,7 @@ static int wm_usd_export_exec(bContext *C, wmOperator *op)
|
|||
|
||||
STRNCPY(params.root_prim_path, root_prim_path);
|
||||
|
||||
bool ok = USD_export(C, filepath, ¶ms, as_background_job);
|
||||
bool ok = USD_export(C, filepath, ¶ms, as_background_job, op->reports);
|
||||
|
||||
return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
|
||||
}
|
||||
|
@ -515,7 +515,7 @@ static int wm_usd_import_exec(bContext *C, wmOperator *op)
|
|||
|
||||
STRNCPY(params.import_textures_dir, import_textures_dir);
|
||||
|
||||
const bool ok = USD_import(C, filepath, ¶ms, as_background_job);
|
||||
const bool ok = USD_import(C, filepath, ¶ms, as_background_job, op->reports);
|
||||
|
||||
return as_background_job || ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
|
||||
}
|
||||
|
|
|
@ -9,9 +9,13 @@
|
|||
#include "BLI_string.h"
|
||||
|
||||
#include "BKE_appdir.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "usd.h"
|
||||
#include "usd.hh"
|
||||
|
||||
|
@ -50,6 +54,14 @@ void USDSceneDelegate::populate(Depsgraph *depsgraph)
|
|||
params.export_textures = false; /* Don't copy all textures, is slow. */
|
||||
params.evaluation_mode = DEG_get_mode(depsgraph);
|
||||
|
||||
/* NOTE: Since the reports list will be `nullptr` here, reports generated by export code from
|
||||
* this call will only be printed to console. */
|
||||
wmJobWorkerStatus worker_status = {};
|
||||
ReportList worker_reports = {};
|
||||
BKE_reports_init(&worker_reports, RPT_PRINT | RPT_STORE);
|
||||
worker_status.reports = &worker_reports;
|
||||
params.worker_status = &worker_status;
|
||||
|
||||
/* Create clean directory for export. */
|
||||
BLI_delete(temp_dir_.c_str(), true, true);
|
||||
BLI_dir_create_recursive(temp_dir_.c_str());
|
||||
|
@ -62,6 +74,8 @@ void USDSceneDelegate::populate(Depsgraph *depsgraph)
|
|||
stage_ = io::usd::export_to_stage(params, depsgraph, temp_file_.c_str());
|
||||
delegate_ = std::make_unique<pxr::UsdImagingDelegate>(render_index_, delegate_id_);
|
||||
delegate_->Populate(stage_->GetPseudoRoot());
|
||||
|
||||
WM_reports_add(nullptr, &worker_reports);
|
||||
}
|
||||
|
||||
} // namespace blender::io::hydra
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <pxr/usd/ar/writableAsset.h>
|
||||
|
||||
#include "BKE_main.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_path_util.h"
|
||||
|
@ -52,17 +53,18 @@ static std::pair<std::string, std::string> split_udim_pattern(const std::string
|
|||
|
||||
/* Return the asset file base name, with special handling of
|
||||
* package relative paths. */
|
||||
static std::string get_asset_base_name(const char *src_path)
|
||||
static std::string get_asset_base_name(const char *src_path, ReportList *reports)
|
||||
{
|
||||
char base_name[FILE_MAXFILE];
|
||||
|
||||
if (pxr::ArIsPackageRelativePath(src_path)) {
|
||||
std::pair<std::string, std::string> split = pxr::ArSplitPackageRelativePathInner(src_path);
|
||||
if (split.second.empty()) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Couldn't determine package-relative file name from path %s",
|
||||
__func__,
|
||||
src_path);
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Couldn't determine package-relative file name from path %s",
|
||||
__func__,
|
||||
src_path);
|
||||
return src_path;
|
||||
}
|
||||
BLI_path_split_file_part(split.second.c_str(), base_name, sizeof(base_name));
|
||||
|
@ -77,9 +79,10 @@ static std::string get_asset_base_name(const char *src_path)
|
|||
/* Copy an asset to a destination directory. */
|
||||
static std::string copy_asset_to_directory(const char *src_path,
|
||||
const char *dest_dir_path,
|
||||
eUSDTexNameCollisionMode name_collision_mode)
|
||||
eUSDTexNameCollisionMode name_collision_mode,
|
||||
ReportList *reports)
|
||||
{
|
||||
std::string base_name = get_asset_base_name(src_path);
|
||||
std::string base_name = get_asset_base_name(src_path, reports);
|
||||
|
||||
char dest_file_path[FILE_MAX];
|
||||
BLI_path_join(dest_file_path, sizeof(dest_file_path), dest_dir_path, base_name.c_str());
|
||||
|
@ -89,8 +92,13 @@ static std::string copy_asset_to_directory(const char *src_path,
|
|||
return dest_file_path;
|
||||
}
|
||||
|
||||
if (!copy_asset(src_path, dest_file_path, name_collision_mode)) {
|
||||
WM_reportf(RPT_WARNING, "%s: Couldn't copy file %s to %s", __func__, src_path, dest_file_path);
|
||||
if (!copy_asset(src_path, dest_file_path, name_collision_mode, reports)) {
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Couldn't copy file %s to %s",
|
||||
__func__,
|
||||
src_path,
|
||||
dest_file_path);
|
||||
return src_path;
|
||||
}
|
||||
|
||||
|
@ -99,12 +107,13 @@ static std::string copy_asset_to_directory(const char *src_path,
|
|||
|
||||
static std::string copy_udim_asset_to_directory(const char *src_path,
|
||||
const char *dest_dir_path,
|
||||
eUSDTexNameCollisionMode name_collision_mode)
|
||||
eUSDTexNameCollisionMode name_collision_mode,
|
||||
ReportList *reports)
|
||||
{
|
||||
/* Get prefix and suffix from udim pattern. */
|
||||
std::pair<std::string, std::string> splitPath = split_udim_pattern(src_path);
|
||||
if (splitPath.first.empty() || splitPath.second.empty()) {
|
||||
WM_reportf(RPT_ERROR, "%s: Couldn't split UDIM pattern %s", __func__, src_path);
|
||||
BKE_reportf(reports, RPT_ERROR, "%s: Couldn't split UDIM pattern %s", __func__, src_path);
|
||||
return src_path;
|
||||
}
|
||||
|
||||
|
@ -118,11 +127,11 @@ static std::string copy_udim_asset_to_directory(const char *src_path,
|
|||
for (int i = UDIM_START_TILE; i < UDIM_END_TILE; ++i) {
|
||||
const std::string src_udim = splitPath.first + std::to_string(i) + splitPath.second;
|
||||
if (asset_exists(src_udim.c_str())) {
|
||||
copy_asset_to_directory(src_udim.c_str(), dest_dir_path, name_collision_mode);
|
||||
copy_asset_to_directory(src_udim.c_str(), dest_dir_path, name_collision_mode, reports);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string src_file_name = get_asset_base_name(src_path);
|
||||
const std::string src_file_name = get_asset_base_name(src_path, reports);
|
||||
char ret_udim_path[FILE_MAX];
|
||||
BLI_path_join(ret_udim_path, sizeof(ret_udim_path), dest_dir_path, src_file_name.c_str());
|
||||
|
||||
|
@ -131,14 +140,17 @@ static std::string copy_udim_asset_to_directory(const char *src_path,
|
|||
* path has the former. */
|
||||
splitPath = split_udim_pattern(ret_udim_path);
|
||||
if (splitPath.first.empty() || splitPath.second.empty()) {
|
||||
WM_reportf(RPT_ERROR, "%s: Couldn't split UDIM pattern %s", __func__, ret_udim_path);
|
||||
BKE_reportf(reports, RPT_ERROR, "%s: Couldn't split UDIM pattern %s", __func__, ret_udim_path);
|
||||
return ret_udim_path;
|
||||
}
|
||||
|
||||
return splitPath.first + UDIM_PATTERN + splitPath.second;
|
||||
}
|
||||
|
||||
bool copy_asset(const char *src, const char *dst, eUSDTexNameCollisionMode name_collision_mode)
|
||||
bool copy_asset(const char *src,
|
||||
const char *dst,
|
||||
eUSDTexNameCollisionMode name_collision_mode,
|
||||
ReportList *reports)
|
||||
{
|
||||
if (!(src && dst)) {
|
||||
return false;
|
||||
|
@ -149,7 +161,7 @@ bool copy_asset(const char *src, const char *dst, eUSDTexNameCollisionMode name_
|
|||
if (name_collision_mode != USD_TEX_NAME_COLLISION_OVERWRITE) {
|
||||
if (!ar.Resolve(dst).IsEmpty()) {
|
||||
/* The asset exists, so this is a no-op. */
|
||||
WM_reportf(RPT_INFO, "%s: Will not overwrite existing asset %s", __func__, dst);
|
||||
BKE_reportf(reports, RPT_INFO, "%s: Will not overwrite existing asset %s", __func__, dst);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -157,86 +169,96 @@ bool copy_asset(const char *src, const char *dst, eUSDTexNameCollisionMode name_
|
|||
pxr::ArResolvedPath src_path = ar.Resolve(src);
|
||||
|
||||
if (src_path.IsEmpty()) {
|
||||
WM_reportf(RPT_ERROR, "%s: Can't resolve path %s", __func__, src);
|
||||
BKE_reportf(reports, RPT_ERROR, "%s: Can't resolve path %s", __func__, src);
|
||||
return false;
|
||||
}
|
||||
|
||||
pxr::ArResolvedPath dst_path = ar.ResolveForNewAsset(dst);
|
||||
|
||||
if (dst_path.IsEmpty()) {
|
||||
WM_reportf(RPT_ERROR, "%s: Can't resolve path %s for writing", __func__, dst);
|
||||
BKE_reportf(reports, RPT_ERROR, "%s: Can't resolve path %s for writing", __func__, dst);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (src_path == dst_path) {
|
||||
WM_reportf(RPT_ERROR,
|
||||
"%s: Can't copy %s. The source and destination paths are the same",
|
||||
__func__,
|
||||
src_path.GetPathString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"%s: Can't copy %s. The source and destination paths are the same",
|
||||
__func__,
|
||||
src_path.GetPathString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string why_not;
|
||||
if (!ar.CanWriteAssetToPath(dst_path, &why_not)) {
|
||||
WM_reportf(RPT_ERROR,
|
||||
"%s: Can't write to asset %s: %s",
|
||||
__func__,
|
||||
dst_path.GetPathString().c_str(),
|
||||
why_not.c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"%s: Can't write to asset %s: %s",
|
||||
__func__,
|
||||
dst_path.GetPathString().c_str(),
|
||||
why_not.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<pxr::ArAsset> src_asset = ar.OpenAsset(src_path);
|
||||
if (!src_asset) {
|
||||
WM_reportf(
|
||||
RPT_ERROR, "%s: Can't open source asset %s", __func__, src_path.GetPathString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"%s: Can't open source asset %s",
|
||||
__func__,
|
||||
src_path.GetPathString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t size = src_asset->GetSize();
|
||||
|
||||
if (size == 0) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Will not copy zero size source asset %s",
|
||||
__func__,
|
||||
src_path.GetPathString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Will not copy zero size source asset %s",
|
||||
__func__,
|
||||
src_path.GetPathString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<const char> buf = src_asset->GetBuffer();
|
||||
|
||||
if (!buf) {
|
||||
WM_reportf(RPT_ERROR,
|
||||
"%s: Null buffer for source asset %s",
|
||||
__func__,
|
||||
src_path.GetPathString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"%s: Null buffer for source asset %s",
|
||||
__func__,
|
||||
src_path.GetPathString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<pxr::ArWritableAsset> dst_asset = ar.OpenAssetForWrite(
|
||||
dst_path, pxr::ArResolver::WriteMode::Replace);
|
||||
if (!dst_asset) {
|
||||
WM_reportf(RPT_ERROR,
|
||||
"%s: Can't open destination asset %s for writing",
|
||||
__func__,
|
||||
src_path.GetPathString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"%s: Can't open destination asset %s for writing",
|
||||
__func__,
|
||||
src_path.GetPathString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t bytes_written = dst_asset->Write(src_asset->GetBuffer().get(), src_asset->GetSize(), 0);
|
||||
|
||||
if (bytes_written == 0) {
|
||||
WM_reportf(RPT_ERROR,
|
||||
"%s: Error writing to destination asset %s",
|
||||
__func__,
|
||||
dst_path.GetPathString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"%s: Error writing to destination asset %s",
|
||||
__func__,
|
||||
dst_path.GetPathString().c_str());
|
||||
}
|
||||
|
||||
if (!dst_asset->Close()) {
|
||||
WM_reportf(RPT_ERROR,
|
||||
"%s: Couldn't close destination asset %s",
|
||||
__func__,
|
||||
dst_path.GetPathString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"%s: Couldn't close destination asset %s",
|
||||
__func__,
|
||||
dst_path.GetPathString().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -250,11 +272,15 @@ bool asset_exists(const char *path)
|
|||
|
||||
std::string import_asset(const char *src,
|
||||
const char *import_dir,
|
||||
eUSDTexNameCollisionMode name_collision_mode)
|
||||
eUSDTexNameCollisionMode name_collision_mode,
|
||||
ReportList *reports)
|
||||
{
|
||||
if (import_dir[0] == '\0') {
|
||||
WM_reportf(
|
||||
RPT_ERROR, "%s: Texture import directory path empty, couldn't import %s", __func__, src);
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"%s: Texture import directory path empty, couldn't import %s",
|
||||
__func__,
|
||||
src);
|
||||
return src;
|
||||
}
|
||||
|
||||
|
@ -267,14 +293,15 @@ std::string import_asset(const char *src,
|
|||
basepath = BKE_main_blendfile_path_from_global();
|
||||
|
||||
if (!basepath || basepath[0] == '\0') {
|
||||
WM_reportf(RPT_ERROR,
|
||||
"%s: import directory is relative "
|
||||
"but the blend file path is empty. "
|
||||
"Please save the blend file before importing the USD "
|
||||
"or provide an absolute import directory path. "
|
||||
"Can't import %s",
|
||||
__func__,
|
||||
src);
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"%s: import directory is relative "
|
||||
"but the blend file path is empty. "
|
||||
"Please save the blend file before importing the USD "
|
||||
"or provide an absolute import directory path. "
|
||||
"Can't import %s",
|
||||
__func__,
|
||||
src);
|
||||
return src;
|
||||
}
|
||||
BLI_path_abs(dest_dir_path, basepath);
|
||||
|
@ -283,16 +310,19 @@ std::string import_asset(const char *src,
|
|||
BLI_path_normalize(dest_dir_path);
|
||||
|
||||
if (!BLI_dir_create_recursive(dest_dir_path)) {
|
||||
WM_reportf(
|
||||
RPT_ERROR, "%s: Couldn't create texture import directory %s", __func__, dest_dir_path);
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"%s: Couldn't create texture import directory %s",
|
||||
__func__,
|
||||
dest_dir_path);
|
||||
return src;
|
||||
}
|
||||
|
||||
if (is_udim_path(src)) {
|
||||
return copy_udim_asset_to_directory(src, dest_dir_path, name_collision_mode);
|
||||
return copy_udim_asset_to_directory(src, dest_dir_path, name_collision_mode, reports);
|
||||
}
|
||||
|
||||
return copy_asset_to_directory(src, dest_dir_path, name_collision_mode);
|
||||
return copy_asset_to_directory(src, dest_dir_path, name_collision_mode, reports);
|
||||
}
|
||||
|
||||
bool is_udim_path(const std::string &path)
|
||||
|
|
|
@ -17,9 +17,14 @@ namespace blender::io::usd {
|
|||
* \param src: source path of the asset to copy
|
||||
* \param dst: destination path of the copy
|
||||
* \param name_collision_mode: behavior when `dst` already exists
|
||||
* \param reports: the storage for potential warning or error reports (generated using BKE_report
|
||||
* API).
|
||||
* \return true if the copy succeeded, false otherwise
|
||||
*/
|
||||
bool copy_asset(const char *src, const char *dst, eUSDTexNameCollisionMode name_collision_mode);
|
||||
bool copy_asset(const char *src,
|
||||
const char *dst,
|
||||
eUSDTexNameCollisionMode name_collision_mode,
|
||||
ReportList *reports);
|
||||
|
||||
/**
|
||||
* Invoke the USD asset resolver to determine if the
|
||||
|
@ -41,11 +46,14 @@ bool asset_exists(const char *path);
|
|||
* \param src: source path of the asset to import
|
||||
* \param import_dir: path to the destination directory
|
||||
* \param name_collision_mode: behavior when a file of the same name already exists
|
||||
* \param reports: the storage for potential warning or error reports (generated using BKE_report
|
||||
* API).
|
||||
* \return path to copied file or the original `src` path if there was an error
|
||||
*/
|
||||
std::string import_asset(const char *src,
|
||||
const char *import_dir,
|
||||
eUSDTexNameCollisionMode name_collision_mode);
|
||||
eUSDTexNameCollisionMode name_collision_mode,
|
||||
ReportList *reports);
|
||||
|
||||
/**
|
||||
* Check if the given path contains a UDIM token.
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "BKE_blender_version.h"
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
|
@ -108,6 +109,8 @@ static bool prim_path_valid(const char *path)
|
|||
/**
|
||||
* Perform validation of export parameter settings.
|
||||
* \return true if the parameters are valid; returns false otherwise.
|
||||
*
|
||||
* \warning Do not call from worker thread, only from main thread (i.e. before starting the wmJob).
|
||||
*/
|
||||
static bool export_params_valid(const USDExportParams ¶ms)
|
||||
{
|
||||
|
@ -183,33 +186,36 @@ static bool perform_usdz_conversion(const ExportJobData *data)
|
|||
if (BLI_exists(data->usdz_filepath)) {
|
||||
result = BLI_delete(data->usdz_filepath, false, false);
|
||||
if (result != 0) {
|
||||
WM_reportf(
|
||||
RPT_ERROR, "USD Export: Unable to delete existing usdz file %s", data->usdz_filepath);
|
||||
BKE_reportf(data->params.worker_status->reports,
|
||||
RPT_ERROR,
|
||||
"USD Export: Unable to delete existing usdz file %s",
|
||||
data->usdz_filepath);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
result = BLI_path_move(usdz_temp_full_path, data->usdz_filepath);
|
||||
if (result != 0) {
|
||||
WM_reportf(RPT_ERROR,
|
||||
"USD Export: Couldn't move new usdz file from temporary location %s to %s",
|
||||
usdz_temp_full_path,
|
||||
data->usdz_filepath);
|
||||
BKE_reportf(data->params.worker_status->reports,
|
||||
RPT_ERROR,
|
||||
"USD Export: Couldn't move new usdz file from temporary location %s to %s",
|
||||
usdz_temp_full_path,
|
||||
data->usdz_filepath);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static pxr::UsdStageRefPtr export_to_stage(const USDExportParams ¶ms,
|
||||
Depsgraph *depsgraph,
|
||||
const char *filepath,
|
||||
wmJobWorkerStatus *worker_status)
|
||||
pxr::UsdStageRefPtr export_to_stage(const USDExportParams ¶ms,
|
||||
Depsgraph *depsgraph,
|
||||
const char *filepath)
|
||||
{
|
||||
pxr::UsdStageRefPtr usd_stage = pxr::UsdStage::CreateNew(filepath);
|
||||
if (!usd_stage) {
|
||||
return usd_stage;
|
||||
}
|
||||
|
||||
wmJobWorkerStatus *worker_status = params.worker_status;
|
||||
Scene *scene = DEG_get_input_scene(depsgraph);
|
||||
Main *bmain = DEG_get_bmain(depsgraph);
|
||||
|
||||
|
@ -273,7 +279,7 @@ static pxr::UsdStageRefPtr export_to_stage(const USDExportParams ¶ms,
|
|||
}
|
||||
}
|
||||
|
||||
call_export_hooks(usd_stage, depsgraph);
|
||||
call_export_hooks(usd_stage, depsgraph, params.worker_status->reports);
|
||||
|
||||
/* Finish up by going back to the keyframe that was current before we started. */
|
||||
if (scene->r.cfra != orig_frame) {
|
||||
|
@ -284,14 +290,6 @@ static pxr::UsdStageRefPtr export_to_stage(const USDExportParams ¶ms,
|
|||
return usd_stage;
|
||||
}
|
||||
|
||||
pxr::UsdStageRefPtr export_to_stage(const USDExportParams ¶ms,
|
||||
Depsgraph *depsgraph,
|
||||
const char *filepath)
|
||||
{
|
||||
wmJobWorkerStatus worker_status = {};
|
||||
return export_to_stage(params, depsgraph, filepath, &worker_status);
|
||||
}
|
||||
|
||||
static void export_startjob(void *customdata, wmJobWorkerStatus *worker_status)
|
||||
{
|
||||
ExportJobData *data = static_cast<ExportJobData *>(customdata);
|
||||
|
@ -315,16 +313,18 @@ static void export_startjob(void *customdata, wmJobWorkerStatus *worker_status)
|
|||
|
||||
worker_status->progress = 0.0f;
|
||||
worker_status->do_update = true;
|
||||
data->params.worker_status = worker_status;
|
||||
|
||||
pxr::UsdStageRefPtr usd_stage = export_to_stage(
|
||||
data->params, data->depsgraph, data->unarchived_filepath, worker_status);
|
||||
data->params, data->depsgraph, data->unarchived_filepath);
|
||||
if (!usd_stage) {
|
||||
/* This happens when the USD JSON files cannot be found. When that happens,
|
||||
* the USD library doesn't know it has the functionality to write USDA and
|
||||
* USDC files, and creating a new UsdStage fails. */
|
||||
WM_reportf(RPT_ERROR,
|
||||
"USD Export: unable to find suitable USD plugin to write %s",
|
||||
data->unarchived_filepath);
|
||||
BKE_reportf(worker_status->reports,
|
||||
RPT_ERROR,
|
||||
"USD Export: unable to find suitable USD plugin to write %s",
|
||||
data->unarchived_filepath);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -420,7 +420,8 @@ static void set_job_filepath(blender::io::usd::ExportJobData *job, const char *f
|
|||
bool USD_export(bContext *C,
|
||||
const char *filepath,
|
||||
const USDExportParams *params,
|
||||
bool as_background_job)
|
||||
bool as_background_job,
|
||||
ReportList *reports)
|
||||
{
|
||||
if (!blender::io::usd::export_params_valid(*params)) {
|
||||
return false;
|
||||
|
@ -469,6 +470,9 @@ bool USD_export(bContext *C,
|
|||
}
|
||||
else {
|
||||
wmJobWorkerStatus worker_status = {};
|
||||
/* Use the operator's reports in non-background case. */
|
||||
worker_status.reports = reports;
|
||||
|
||||
blender::io::usd::export_startjob(job, &worker_status);
|
||||
blender::io::usd::export_endjob(job);
|
||||
export_ok = job->export_ok;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "BKE_main.h"
|
||||
#include "BKE_node.hh"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_world.h"
|
||||
|
||||
|
@ -157,6 +158,8 @@ static void import_startjob(void *customdata, wmJobWorkerStatus *worker_status)
|
|||
data->archive = nullptr;
|
||||
data->start_time = timeit::Clock::now();
|
||||
|
||||
data->params.worker_status = worker_status;
|
||||
|
||||
WM_set_locked_interface(data->wm, true);
|
||||
G.is_break = false;
|
||||
|
||||
|
@ -221,7 +224,10 @@ static void import_startjob(void *customdata, wmJobWorkerStatus *worker_status)
|
|||
pxr::UsdStage::OpenMasked(data->filepath, pop_mask);
|
||||
|
||||
if (!stage) {
|
||||
WM_reportf(RPT_ERROR, "USD Import: unable to open stage to read %s", data->filepath);
|
||||
BKE_reportf(worker_status->reports,
|
||||
RPT_ERROR,
|
||||
"USD Import: unable to open stage to read %s",
|
||||
data->filepath);
|
||||
data->import_ok = false;
|
||||
data->error_code = USD_ARCHIVE_FAIL;
|
||||
return;
|
||||
|
@ -392,7 +398,9 @@ static void import_endjob(void *customdata)
|
|||
data->import_ok = !data->was_canceled;
|
||||
break;
|
||||
case USD_ARCHIVE_FAIL:
|
||||
WM_report(RPT_ERROR, "Could not open USD archive for reading, see console for detail");
|
||||
BKE_report(data->params.worker_status->reports,
|
||||
RPT_ERROR,
|
||||
"Could not open USD archive for reading, see console for detail");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -417,7 +425,8 @@ using namespace blender::io::usd;
|
|||
bool USD_import(bContext *C,
|
||||
const char *filepath,
|
||||
const USDImportParams *params,
|
||||
bool as_background_job)
|
||||
bool as_background_job,
|
||||
ReportList *reports)
|
||||
{
|
||||
/* Using new here since `MEM_*` functions do not call constructor to properly initialize data. */
|
||||
ImportJobData *job = new ImportJobData();
|
||||
|
@ -460,6 +469,9 @@ bool USD_import(bContext *C,
|
|||
}
|
||||
else {
|
||||
wmJobWorkerStatus worker_status = {};
|
||||
/* Use the operator's reports in non-background case. */
|
||||
worker_status.reports = reports;
|
||||
|
||||
import_startjob(job, &worker_status);
|
||||
import_endjob(job);
|
||||
import_ok = job->import_ok;
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "RNA_access.hh"
|
||||
#include "RNA_prototypes.h"
|
||||
#include "RNA_types.hh"
|
||||
|
@ -152,7 +154,7 @@ void register_export_hook_converters()
|
|||
}
|
||||
|
||||
/* Retrieve and report the current Python error. */
|
||||
static void handle_python_error(USDHook *hook)
|
||||
static void handle_python_error(USDHook *hook, ReportList *reports)
|
||||
{
|
||||
if (!PyErr_Occurred()) {
|
||||
return;
|
||||
|
@ -160,9 +162,10 @@ static void handle_python_error(USDHook *hook)
|
|||
|
||||
PyErr_Print();
|
||||
|
||||
WM_reportf(RPT_ERROR,
|
||||
"An exception occurred invoking USD hook '%s'. Please see the console for details",
|
||||
hook->name);
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"An exception occurred invoking USD hook '%s'. Please see the console for details",
|
||||
hook->name);
|
||||
}
|
||||
|
||||
/* Abstract base class to facilitate calling a function with a given
|
||||
|
@ -207,10 +210,11 @@ class USDHookInvoker {
|
|||
call_hook(hook_obj);
|
||||
}
|
||||
catch (python::error_already_set const &) {
|
||||
handle_python_error(hook);
|
||||
handle_python_error(hook, reports_);
|
||||
}
|
||||
catch (...) {
|
||||
WM_reportf(RPT_ERROR, "An exception occurred invoking USD hook '%s'", hook->name);
|
||||
BKE_reportf(
|
||||
reports_, RPT_ERROR, "An exception occurred invoking USD hook '%s'", hook->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,6 +229,9 @@ class USDHookInvoker {
|
|||
*
|
||||
* python::call_method<void>(hook_obj, function_name(), arg1, arg2); */
|
||||
virtual void call_hook(PyObject *hook_obj) const = 0;
|
||||
|
||||
/* Reports list provided when constructing the subclass, used by #call() to store reports. */
|
||||
ReportList *reports_;
|
||||
};
|
||||
|
||||
class OnExportInvoker : public USDHookInvoker {
|
||||
|
@ -232,9 +239,10 @@ class OnExportInvoker : public USDHookInvoker {
|
|||
USDSceneExportContext hook_context_;
|
||||
|
||||
public:
|
||||
OnExportInvoker(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph)
|
||||
OnExportInvoker(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph, ReportList *reports)
|
||||
: hook_context_(stage, depsgraph)
|
||||
{
|
||||
reports_ = reports;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -258,10 +266,12 @@ class OnMaterialExportInvoker : public USDHookInvoker {
|
|||
public:
|
||||
OnMaterialExportInvoker(pxr::UsdStageRefPtr stage,
|
||||
Material *material,
|
||||
pxr::UsdShadeMaterial &usd_material)
|
||||
pxr::UsdShadeMaterial &usd_material,
|
||||
ReportList *reports)
|
||||
: hook_context_(stage), usd_material_(usd_material)
|
||||
{
|
||||
material_ptr_ = RNA_pointer_create(nullptr, &RNA_Material, material);
|
||||
reports_ = reports;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -277,25 +287,26 @@ class OnMaterialExportInvoker : public USDHookInvoker {
|
|||
}
|
||||
};
|
||||
|
||||
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph)
|
||||
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph, ReportList *reports)
|
||||
{
|
||||
if (g_usd_hooks.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
OnExportInvoker on_export(stage, depsgraph);
|
||||
OnExportInvoker on_export(stage, depsgraph, reports);
|
||||
on_export.call();
|
||||
}
|
||||
|
||||
void call_material_export_hooks(pxr::UsdStageRefPtr stage,
|
||||
Material *material,
|
||||
pxr::UsdShadeMaterial &usd_material)
|
||||
pxr::UsdShadeMaterial &usd_material,
|
||||
ReportList *reports)
|
||||
{
|
||||
if (g_usd_hooks.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
OnMaterialExportInvoker on_material_export(stage, material, usd_material);
|
||||
OnMaterialExportInvoker on_material_export(stage, material, usd_material, reports);
|
||||
on_material_export.call();
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
struct Depsgraph;
|
||||
struct ExportJobData;
|
||||
struct Material;
|
||||
struct ReportList;
|
||||
struct USDExportParams;
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
@ -19,11 +20,12 @@ namespace blender::io::usd {
|
|||
void register_export_hook_converters();
|
||||
|
||||
/** Call the 'on_export' chaser function defined in the registered USDHook classes. */
|
||||
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph);
|
||||
void call_export_hooks(pxr::UsdStageRefPtr stage, Depsgraph *depsgraph, ReportList *reports);
|
||||
|
||||
/** Call the 'on_material_export' hook functions defined in the registered #USDHook classes. */
|
||||
void call_material_export_hooks(pxr::UsdStageRefPtr stage,
|
||||
Material *material,
|
||||
pxr::UsdShadeMaterial &usd_material);
|
||||
pxr::UsdShadeMaterial &usd_material,
|
||||
ReportList *reports);
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
|
|
@ -760,7 +760,7 @@ void USDMaterialReader::load_tex_image(const pxr::UsdShadeShader &usd_shader,
|
|||
USD_TEX_NAME_COLLISION_OVERWRITE :
|
||||
params_.tex_name_collision_mode;
|
||||
|
||||
file_path = import_asset(file_path.c_str(), textures_dir, name_collision_mode);
|
||||
file_path = import_asset(file_path.c_str(), textures_dir, name_collision_mode, reports());
|
||||
}
|
||||
|
||||
/* If this is a UDIM texture, this will store the
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "usd.h"
|
||||
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "BLI_map.hh"
|
||||
|
||||
#include <pxr/usd/usdShade/material.h>
|
||||
|
@ -86,6 +88,12 @@ class USDMaterialReader {
|
|||
|
||||
Material *add_material(const pxr::UsdShadeMaterial &usd_material) const;
|
||||
|
||||
/** Get the wmJobWorkerStatus-provided `reports` list pointer, to use with the BKE_report API. */
|
||||
ReportList *reports() const
|
||||
{
|
||||
return params_.worker_status->reports;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** Create the Principled BSDF shader node network. */
|
||||
void import_usd_preview(Material *mtl, const pxr::UsdShadeShader &usd_shader) const;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "BKE_material.h"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "BLI_math_color.hh"
|
||||
#include "BLI_math_geom.h"
|
||||
|
@ -165,7 +166,7 @@ USDMeshReader::USDMeshReader(const pxr::UsdPrim &prim,
|
|||
}
|
||||
|
||||
static std::optional<eCustomDataType> convert_usd_type_to_blender(
|
||||
const pxr::SdfValueTypeName usd_type)
|
||||
const pxr::SdfValueTypeName usd_type, ReportList *reports)
|
||||
{
|
||||
static const blender::Map<pxr::SdfValueTypeName, eCustomDataType> type_map = []() {
|
||||
blender::Map<pxr::SdfValueTypeName, eCustomDataType> map;
|
||||
|
@ -194,7 +195,10 @@ static std::optional<eCustomDataType> convert_usd_type_to_blender(
|
|||
|
||||
const eCustomDataType *value = type_map.lookup_ptr(usd_type);
|
||||
if (value == nullptr) {
|
||||
WM_reportf(RPT_WARNING, "Unsupported type %s for mesh data", usd_type.GetAsToken().GetText());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"Unsupported type %s for mesh data",
|
||||
usd_type.GetAsToken().GetText());
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -202,7 +206,7 @@ static std::optional<eCustomDataType> convert_usd_type_to_blender(
|
|||
}
|
||||
|
||||
static const std::optional<eAttrDomain> convert_usd_varying_to_blender(
|
||||
const pxr::TfToken usd_domain)
|
||||
const pxr::TfToken usd_domain, ReportList *reports)
|
||||
{
|
||||
static const blender::Map<pxr::TfToken, eAttrDomain> domain_map = []() {
|
||||
blender::Map<pxr::TfToken, eAttrDomain> map;
|
||||
|
@ -221,7 +225,8 @@ static const std::optional<eAttrDomain> convert_usd_varying_to_blender(
|
|||
const eAttrDomain *value = domain_map.lookup_ptr(usd_domain);
|
||||
|
||||
if (value == nullptr) {
|
||||
WM_reportf(RPT_WARNING, "Unsupported domain for mesh data type %s", usd_domain.GetText());
|
||||
BKE_reportf(
|
||||
reports, RPT_WARNING, "Unsupported domain for mesh data type %s", usd_domain.GetText());
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -271,11 +276,11 @@ void USDMeshReader::read_object_data(Main *bmain, const double motionSampleTime)
|
|||
}
|
||||
|
||||
if (import_params_.import_blendshapes) {
|
||||
import_blendshapes(bmain, object_, prim_);
|
||||
import_blendshapes(bmain, object_, prim_, reports());
|
||||
}
|
||||
|
||||
if (import_params_.import_skeletons) {
|
||||
import_mesh_skel_bindings(bmain, object_, prim_);
|
||||
import_mesh_skel_bindings(bmain, object_, prim_, reports());
|
||||
}
|
||||
|
||||
USDXformReader::read_object_data(bmain, motionSampleTime);
|
||||
|
@ -349,22 +354,26 @@ void USDMeshReader::read_mpolys(Mesh *mesh)
|
|||
|
||||
template<typename T>
|
||||
pxr::VtArray<T> get_prim_attribute_array(const pxr::UsdGeomPrimvar &primvar,
|
||||
const double motionSampleTime)
|
||||
const double motionSampleTime,
|
||||
ReportList *reports)
|
||||
{
|
||||
pxr::VtArray<T> array;
|
||||
|
||||
pxr::VtValue primvar_val;
|
||||
|
||||
if (!primvar.ComputeFlattened(&primvar_val, motionSampleTime)) {
|
||||
WM_reportf(
|
||||
RPT_WARNING, "Unable to get array values for primvar %s", primvar.GetName().GetText());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"Unable to get array values for primvar %s",
|
||||
primvar.GetName().GetText());
|
||||
return array;
|
||||
}
|
||||
|
||||
if (!primvar_val.CanCast<pxr::VtArray<T>>()) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD Import: can't cast attribute '%s' to array",
|
||||
primvar.GetName().GetText());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"USD Import: can't cast attribute '%s' to array",
|
||||
primvar.GetName().GetText());
|
||||
return array;
|
||||
}
|
||||
|
||||
|
@ -380,8 +389,8 @@ void USDMeshReader::read_color_data_primvar(Mesh *mesh,
|
|||
return;
|
||||
}
|
||||
|
||||
pxr::VtArray<pxr::GfVec3f> usd_colors = get_prim_attribute_array<pxr::GfVec3f>(primvar,
|
||||
motionSampleTime);
|
||||
pxr::VtArray<pxr::GfVec3f> usd_colors = get_prim_attribute_array<pxr::GfVec3f>(
|
||||
primvar, motionSampleTime, reports());
|
||||
|
||||
if (usd_colors.empty()) {
|
||||
return;
|
||||
|
@ -395,9 +404,11 @@ void USDMeshReader::read_color_data_primvar(Mesh *mesh,
|
|||
(interp == pxr::UsdGeomTokens->constant && usd_colors.size() != 1) ||
|
||||
(interp == pxr::UsdGeomTokens->uniform && usd_colors.size() != mesh->faces_num))
|
||||
{
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD Import: color attribute value '%s' count inconsistent with interpolation type",
|
||||
primvar.GetName().GetText());
|
||||
BKE_reportf(
|
||||
reports(),
|
||||
RPT_WARNING,
|
||||
"USD Import: color attribute value '%s' count inconsistent with interpolation type",
|
||||
primvar.GetName().GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -418,9 +429,10 @@ void USDMeshReader::read_color_data_primvar(Mesh *mesh,
|
|||
color_data = attributes.lookup_or_add_for_write_only_span<ColorGeometry4f>(primvar_name,
|
||||
color_domain);
|
||||
if (!color_data) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD Import: couldn't add color attribute '%s'",
|
||||
primvar.GetBaseName().GetText());
|
||||
BKE_reportf(reports(),
|
||||
RPT_WARNING,
|
||||
"USD Import: couldn't add color attribute '%s'",
|
||||
primvar.GetBaseName().GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -494,8 +506,8 @@ void USDMeshReader::read_uv_data_primvar(Mesh *mesh,
|
|||
{
|
||||
const StringRef primvar_name(primvar.StripPrimvarsName(primvar.GetName()).GetString());
|
||||
|
||||
pxr::VtArray<pxr::GfVec2f> usd_uvs = get_prim_attribute_array<pxr::GfVec2f>(primvar,
|
||||
motionSampleTime);
|
||||
pxr::VtArray<pxr::GfVec2f> usd_uvs = get_prim_attribute_array<pxr::GfVec2f>(
|
||||
primvar, motionSampleTime, reports());
|
||||
|
||||
if (usd_uvs.empty()) {
|
||||
return;
|
||||
|
@ -511,9 +523,10 @@ void USDMeshReader::read_uv_data_primvar(Mesh *mesh,
|
|||
(varying_type == pxr::UsdGeomTokens->vertex && usd_uvs.size() != mesh->totvert) ||
|
||||
(varying_type == pxr::UsdGeomTokens->varying && usd_uvs.size() != mesh->totloop))
|
||||
{
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD Import: UV attribute value '%s' count inconsistent with interpolation type",
|
||||
primvar.GetName().GetText());
|
||||
BKE_reportf(reports(),
|
||||
RPT_WARNING,
|
||||
"USD Import: UV attribute value '%s' count inconsistent with interpolation type",
|
||||
primvar.GetName().GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -522,9 +535,10 @@ void USDMeshReader::read_uv_data_primvar(Mesh *mesh,
|
|||
primvar_name, ATTR_DOMAIN_CORNER);
|
||||
|
||||
if (!uv_data) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD Import: couldn't add UV attribute '%s'",
|
||||
primvar.GetBaseName().GetText());
|
||||
BKE_reportf(reports(),
|
||||
RPT_WARNING,
|
||||
"USD Import: couldn't add UV attribute '%s'",
|
||||
primvar.GetBaseName().GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -588,10 +602,13 @@ void USDMeshReader::copy_prim_array_to_blender_attribute(const Mesh *mesh,
|
|||
MutableSpan<BlenderT> attribute)
|
||||
{
|
||||
const pxr::TfToken interp = primvar.GetInterpolation();
|
||||
pxr::VtArray<USDT> primvar_array = get_prim_attribute_array<USDT>(primvar, motionSampleTime);
|
||||
pxr::VtArray<USDT> primvar_array = get_prim_attribute_array<USDT>(
|
||||
primvar, motionSampleTime, reports());
|
||||
if (primvar_array.empty()) {
|
||||
WM_reportf(
|
||||
RPT_WARNING, "Unable to get array values for primvar %s", primvar.GetName().GetText());
|
||||
BKE_reportf(reports(),
|
||||
RPT_WARNING,
|
||||
"Unable to get array values for primvar %s",
|
||||
primvar.GetName().GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -642,8 +659,9 @@ void USDMeshReader::read_generic_data_primvar(Mesh *mesh,
|
|||
const pxr::TfToken varying_type = primvar.GetInterpolation();
|
||||
const pxr::TfToken name = pxr::UsdGeomPrimvar::StripPrimvarsName(primvar.GetPrimvarName());
|
||||
|
||||
const std::optional<eAttrDomain> domain = convert_usd_varying_to_blender(varying_type);
|
||||
const std::optional<eCustomDataType> type = convert_usd_type_to_blender(sdf_type);
|
||||
const std::optional<eAttrDomain> domain = convert_usd_varying_to_blender(varying_type,
|
||||
reports());
|
||||
const std::optional<eCustomDataType> type = convert_usd_type_to_blender(sdf_type, reports());
|
||||
|
||||
if (!domain.has_value() || !type.has_value()) {
|
||||
return;
|
||||
|
@ -678,10 +696,11 @@ void USDMeshReader::read_generic_data_primvar(Mesh *mesh,
|
|||
mesh, primvar, motionSampleTime, attribute.span.typed<bool>());
|
||||
break;
|
||||
default:
|
||||
WM_reportf(RPT_ERROR,
|
||||
"Generic primvar %s: invalid type %s",
|
||||
primvar.GetName().GetText(),
|
||||
sdf_type.GetAsToken().GetText());
|
||||
BKE_reportf(reports(),
|
||||
RPT_ERROR,
|
||||
"Generic primvar %s: invalid type %s",
|
||||
primvar.GetName().GetText(),
|
||||
sdf_type.GetAsToken().GetText());
|
||||
break;
|
||||
}
|
||||
attribute.finish();
|
||||
|
@ -878,10 +897,11 @@ void USDMeshReader::read_custom_data(const ImportSettings *settings,
|
|||
/* Convert primvars to custom layer data. */
|
||||
for (pxr::UsdGeomPrimvar &pv : primvars) {
|
||||
if (!pv.HasValue()) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"Skipping primvar %s, mesh %s -- no value",
|
||||
pv.GetName().GetText(),
|
||||
&mesh->id.name[2]);
|
||||
BKE_reportf(reports(),
|
||||
RPT_WARNING,
|
||||
"Skipping primvar %s, mesh %s -- no value",
|
||||
pv.GetName().GetText(),
|
||||
&mesh->id.name[2]);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -898,7 +918,7 @@ void USDMeshReader::read_custom_data(const ImportSettings *settings,
|
|||
}
|
||||
|
||||
/* Read Color primvars. */
|
||||
if (convert_usd_type_to_blender(type) == CD_PROP_COLOR) {
|
||||
if (convert_usd_type_to_blender(type, reports()) == CD_PROP_COLOR) {
|
||||
if ((settings->read_flag & MOD_MESHSEQ_READ_COLOR) != 0) {
|
||||
/* Set the active color name to 'displayColor', if a color primvar
|
||||
* with this name exists. Otherwise, use the name of the first
|
||||
|
@ -916,7 +936,7 @@ void USDMeshReader::read_custom_data(const ImportSettings *settings,
|
|||
pxr::UsdGeomTokens->vertex,
|
||||
pxr::UsdGeomTokens->faceVarying,
|
||||
pxr::UsdGeomTokens->varying) &&
|
||||
convert_usd_type_to_blender(type) == CD_PROP_FLOAT2)
|
||||
convert_usd_type_to_blender(type, reports()) == CD_PROP_FLOAT2)
|
||||
{
|
||||
if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) {
|
||||
/* Set the active uv set name to 'st', if a uv set primvar
|
||||
|
@ -1139,10 +1159,11 @@ std::optional<XformResult> USDMeshReader::get_local_usd_xform(const float time)
|
|||
return XformResult(pxr::GfMatrix4f(bind_xf), true);
|
||||
}
|
||||
else {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Couldn't compute geom bind transform for %s",
|
||||
__func__,
|
||||
prim_.GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports(),
|
||||
RPT_WARNING,
|
||||
"%s: Couldn't compute geom bind transform for %s",
|
||||
__func__,
|
||||
prim_.GetPath().GetAsString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
#include "usd.h"
|
||||
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include <pxr/usd/usd/prim.h>
|
||||
|
||||
#include <map>
|
||||
|
@ -113,6 +115,12 @@ class USDPrimReader {
|
|||
parent_reader_ = parent;
|
||||
}
|
||||
|
||||
/** Get the wmJobWorkerStatus-provided `reports` list pointer, to use with the BKE_report API. */
|
||||
ReportList *reports() const
|
||||
{
|
||||
return import_params_.worker_status->reports;
|
||||
}
|
||||
|
||||
/* Since readers might be referenced through handles
|
||||
* maintained by modifiers and constraints, we provide
|
||||
* a reference count to facilitate managing the object
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "BKE_mesh.hh"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "DNA_cachefile_types.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
|
@ -118,10 +119,11 @@ bool USDShapeReader::read_mesh_values(double motionSampleTime,
|
|||
return true;
|
||||
}
|
||||
|
||||
WM_reportf(RPT_ERROR,
|
||||
"Unhandled Gprim type: %s (%s)",
|
||||
prim_.GetTypeName().GetText(),
|
||||
prim_.GetPath().GetText());
|
||||
BKE_reportf(reports(),
|
||||
RPT_ERROR,
|
||||
"Unhandled Gprim type: %s (%s)",
|
||||
prim_.GetTypeName().GetText(),
|
||||
prim_.GetPath().GetText());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -230,10 +232,11 @@ bool USDShapeReader::is_time_varying()
|
|||
return geom.GetRadiusAttr().ValueMightBeTimeVarying();
|
||||
}
|
||||
|
||||
WM_reportf(RPT_ERROR,
|
||||
"Unhandled Gprim type: %s (%s)",
|
||||
prim_.GetTypeName().GetText(),
|
||||
prim_.GetPath().GetText());
|
||||
BKE_reportf(reports(),
|
||||
RPT_ERROR,
|
||||
"Unhandled Gprim type: %s (%s)",
|
||||
prim_.GetTypeName().GetText(),
|
||||
prim_.GetPath().GetText());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ void USDSkeletonReader::read_object_data(Main *bmain, const double motionSampleT
|
|||
return;
|
||||
}
|
||||
|
||||
import_skeleton(bmain, object_, skel_);
|
||||
import_skeleton(bmain, object_, skel_, reports());
|
||||
|
||||
USDXformReader::read_object_data(bmain, motionSampleTime);
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
|
||||
|
@ -366,10 +367,11 @@ void USDStageReader::process_armature_modifiers() const
|
|||
std::string skel_path = mesh_reader->get_skeleton_path();
|
||||
std::map<std::string, Object *>::const_iterator it = usd_path_to_armature.find(skel_path);
|
||||
if (it == usd_path_to_armature.end()) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Couldn't find armature object corresponding to USD skeleton %s",
|
||||
__func__,
|
||||
skel_path.c_str());
|
||||
BKE_reportf(reports(),
|
||||
RPT_WARNING,
|
||||
"%s: Couldn't find armature object corresponding to USD skeleton %s",
|
||||
__func__,
|
||||
skel_path.c_str());
|
||||
}
|
||||
amd->object = it->second;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
struct Main;
|
||||
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "usd.h"
|
||||
#include "usd_reader_prim.h"
|
||||
|
||||
|
@ -79,6 +81,12 @@ class USDStageReader {
|
|||
return settings_;
|
||||
}
|
||||
|
||||
/** Get the wmJobWorkerStatus-provided `reports` list pointer, to use with the BKE_report API. */
|
||||
ReportList *reports() const
|
||||
{
|
||||
return params_.worker_status->reports;
|
||||
}
|
||||
|
||||
void clear_readers();
|
||||
|
||||
const std::vector<USDPrimReader *> &readers() const
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "BKE_modifier.h"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_object_deform.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_string.h"
|
||||
|
@ -103,11 +104,14 @@ void add_bezt(FCurve *fcu,
|
|||
* \param arm_obj: Armature object to which the action will be added
|
||||
* \param skel_query: The USD skeleton query for reading the animation
|
||||
* \param joint_to_bone_map: Map a USD skeleton joint name to a bone name
|
||||
* \param reports: the storage for potential warning or error reports (generated using BKE_report
|
||||
* API).
|
||||
*/
|
||||
void import_skeleton_curves(Main *bmain,
|
||||
Object *arm_obj,
|
||||
const pxr::UsdSkelSkeletonQuery &skel_query,
|
||||
const std::map<pxr::TfToken, std::string> &joint_to_bone_map)
|
||||
const std::map<pxr::TfToken, std::string> &joint_to_bone_map,
|
||||
ReportList *reports)
|
||||
|
||||
{
|
||||
if (!(bmain && arm_obj && skel_query)) {
|
||||
|
@ -218,18 +222,20 @@ void import_skeleton_curves(Main *bmain,
|
|||
/* Get the world space joint transforms at bind time. */
|
||||
pxr::VtMatrix4dArray bind_xforms;
|
||||
if (!skel_query.GetJointWorldBindTransforms(&bind_xforms)) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Couldn't get world bind transforms for skeleton %s",
|
||||
__func__,
|
||||
skel_query.GetSkeleton().GetPrim().GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Couldn't get world bind transforms for skeleton %s",
|
||||
__func__,
|
||||
skel_query.GetSkeleton().GetPrim().GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (bind_xforms.size() != joint_order.size()) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Number of bind transforms doesn't match the number of joints for skeleton %s",
|
||||
__func__,
|
||||
skel_query.GetSkeleton().GetPrim().GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Number of bind transforms doesn't match the number of joints for skeleton %s",
|
||||
__func__,
|
||||
skel_query.GetSkeleton().GetPrim().GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -334,6 +340,7 @@ namespace blender::io::usd {
|
|||
void import_blendshapes(Main *bmain,
|
||||
Object *mesh_obj,
|
||||
const pxr::UsdPrim &prim,
|
||||
ReportList *reports,
|
||||
const bool import_anim)
|
||||
{
|
||||
if (!(mesh_obj && mesh_obj->data && mesh_obj->type == OB_MESH && prim)) {
|
||||
|
@ -363,10 +370,11 @@ void import_blendshapes(Main *bmain,
|
|||
|
||||
pxr::SdfPathVector targets;
|
||||
if (!skel_api.GetBlendShapeTargetsRel().GetTargets(&targets)) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Couldn't get blendshape targets for prim %s",
|
||||
__func__,
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Couldn't get blendshape targets for prim %s",
|
||||
__func__,
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -390,20 +398,22 @@ void import_blendshapes(Main *bmain,
|
|||
|
||||
/* Sanity check. */
|
||||
if (targets.size() != blendshapes.size()) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Number of blendshapes doesn't match number of blendshape targets for prim %s",
|
||||
__func__,
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Number of blendshapes doesn't match number of blendshape targets for prim %s",
|
||||
__func__,
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
pxr::UsdStageRefPtr stage = prim.GetStage();
|
||||
|
||||
if (!stage) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Couldn't get stage for prim %s",
|
||||
__func__,
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Couldn't get stage for prim %s",
|
||||
__func__,
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -440,16 +450,20 @@ void import_blendshapes(Main *bmain,
|
|||
|
||||
pxr::VtVec3fArray offsets;
|
||||
if (!blendshape.GetOffsetsAttr().Get(&offsets)) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Couldn't get offsets for blend shape %s",
|
||||
__func__,
|
||||
path.GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Couldn't get offsets for blend shape %s",
|
||||
__func__,
|
||||
path.GetAsString().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (offsets.empty()) {
|
||||
WM_reportf(
|
||||
RPT_WARNING, "%s: No offsets for blend shape %s", __func__, path.GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: No offsets for blend shape %s",
|
||||
__func__,
|
||||
path.GetAsString().c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -473,7 +487,8 @@ void import_blendshapes(Main *bmain,
|
|||
* offset to the key block point. */
|
||||
for (int a = 0; a < kb->totelem; ++a, fp += 3) {
|
||||
if (a >= offsets.size()) {
|
||||
WM_reportf(
|
||||
BKE_reportf(
|
||||
reports,
|
||||
RPT_WARNING,
|
||||
"%s: Number of offsets greater than number of mesh vertices for blend shape %s",
|
||||
__func__,
|
||||
|
@ -495,7 +510,8 @@ void import_blendshapes(Main *bmain,
|
|||
continue;
|
||||
}
|
||||
if (a >= offsets.size()) {
|
||||
WM_reportf(
|
||||
BKE_reportf(
|
||||
reports,
|
||||
RPT_WARNING,
|
||||
"%s: Number of offsets greater than number of mesh vertices for blend shape %s",
|
||||
__func__,
|
||||
|
@ -621,6 +637,7 @@ void import_blendshapes(Main *bmain,
|
|||
void import_skeleton(Main *bmain,
|
||||
Object *arm_obj,
|
||||
const pxr::UsdSkelSkeleton &skel,
|
||||
ReportList *reports,
|
||||
const bool import_anim)
|
||||
{
|
||||
if (!(arm_obj && arm_obj->data && arm_obj->type == OB_ARMATURE)) {
|
||||
|
@ -631,10 +648,11 @@ void import_skeleton(Main *bmain,
|
|||
pxr::UsdSkelSkeletonQuery skel_query = skel_cache.GetSkelQuery(skel);
|
||||
|
||||
if (!skel_query.IsValid()) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Couldn't query skeleton %s",
|
||||
__func__,
|
||||
skel.GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Couldn't query skeleton %s",
|
||||
__func__,
|
||||
skel.GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -643,10 +661,11 @@ void import_skeleton(Main *bmain,
|
|||
pxr::VtTokenArray joint_order = skel_query.GetJointOrder();
|
||||
|
||||
if (joint_order.size() != skel_topology.size()) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Topology and joint order size mismatch for skeleton %s",
|
||||
__func__,
|
||||
skel.GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Topology and joint order size mismatch for skeleton %s",
|
||||
__func__,
|
||||
skel.GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -668,8 +687,11 @@ void import_skeleton(Main *bmain,
|
|||
std::string name = pxr::SdfPath(joint).GetName();
|
||||
EditBone *bone = ED_armature_ebone_add(arm, name.c_str());
|
||||
if (!bone) {
|
||||
WM_reportf(
|
||||
RPT_WARNING, "%s: Couldn't add bone for joint %s", __func__, joint.GetString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Couldn't add bone for joint %s",
|
||||
__func__,
|
||||
joint.GetString().c_str());
|
||||
edit_bones.push_back(nullptr);
|
||||
continue;
|
||||
}
|
||||
|
@ -680,28 +702,31 @@ void import_skeleton(Main *bmain,
|
|||
/* Sanity check: we should have created a bone for each joint. */
|
||||
const size_t num_joints = skel_topology.GetNumJoints();
|
||||
if (edit_bones.size() != num_joints) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Mismatch in bone and joint counts for skeleton %s",
|
||||
__func__,
|
||||
skel.GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Mismatch in bone and joint counts for skeleton %s",
|
||||
__func__,
|
||||
skel.GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get the world space joint transforms at bind time. */
|
||||
pxr::VtMatrix4dArray bind_xforms;
|
||||
if (!skel_query.GetJointWorldBindTransforms(&bind_xforms)) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Couldn't get world bind transforms for skeleton %s",
|
||||
__func__,
|
||||
skel.GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Couldn't get world bind transforms for skeleton %s",
|
||||
__func__,
|
||||
skel.GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (bind_xforms.size() != num_joints) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Mismatch in bind xforms and joint counts for skeleton %s",
|
||||
__func__,
|
||||
skel.GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Mismatch in bind xforms and joint counts for skeleton %s",
|
||||
__func__,
|
||||
skel.GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -746,7 +771,8 @@ void import_skeleton(Main *bmain,
|
|||
bool valid_skeleton = true;
|
||||
if (negative_determinant) {
|
||||
valid_skeleton = false;
|
||||
WM_reportf(
|
||||
BKE_reportf(
|
||||
reports,
|
||||
RPT_WARNING,
|
||||
"USD Skeleton Import: bone matrices with negative determinants detected in prim %s. "
|
||||
"Such matrices may indicate negative scales, possibly due to mirroring operations, "
|
||||
|
@ -850,11 +876,14 @@ void import_skeleton(Main *bmain,
|
|||
ED_armature_edit_free(arm);
|
||||
|
||||
if (import_anim && valid_skeleton) {
|
||||
import_skeleton_curves(bmain, arm_obj, skel_query, joint_to_bone_map);
|
||||
import_skeleton_curves(bmain, arm_obj, skel_query, joint_to_bone_map, reports);
|
||||
}
|
||||
}
|
||||
|
||||
void import_mesh_skel_bindings(Main *bmain, Object *mesh_obj, const pxr::UsdPrim &prim)
|
||||
void import_mesh_skel_bindings(Main *bmain,
|
||||
Object *mesh_obj,
|
||||
const pxr::UsdPrim &prim,
|
||||
ReportList *reports)
|
||||
{
|
||||
if (!(bmain && mesh_obj && mesh_obj->type == OB_MESH && prim)) {
|
||||
return;
|
||||
|
@ -912,10 +941,11 @@ void import_mesh_skel_bindings(Main *bmain, Object *mesh_obj, const pxr::UsdPrim
|
|||
|
||||
/* We expect the element counts to match. */
|
||||
if (joint_indices_elem_size != joint_weights_elem_size) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Joint weights and joint indices element size mismatch for prim %s",
|
||||
__func__,
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Joint weights and joint indices element size mismatch for prim %s",
|
||||
__func__,
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -931,10 +961,11 @@ void import_mesh_skel_bindings(Main *bmain, Object *mesh_obj, const pxr::UsdPrim
|
|||
}
|
||||
|
||||
if (joint_indices.size() != joint_weights.size()) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Joint weights and joint indices size mismatch for prim %s",
|
||||
__func__,
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Joint weights and joint indices size mismatch for prim %s",
|
||||
__func__,
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -944,11 +975,12 @@ void import_mesh_skel_bindings(Main *bmain, Object *mesh_obj, const pxr::UsdPrim
|
|||
|
||||
/* Sanity check: we expect only vertex or constant interpolation. */
|
||||
if (!ELEM(interp, pxr::UsdGeomTokens->vertex, pxr::UsdGeomTokens->constant)) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Unexpected joint weights interpolation type %s for prim %s",
|
||||
__func__,
|
||||
interp.GetString().c_str(),
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Unexpected joint weights interpolation type %s for prim %s",
|
||||
__func__,
|
||||
interp.GetString().c_str(),
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -956,18 +988,20 @@ void import_mesh_skel_bindings(Main *bmain, Object *mesh_obj, const pxr::UsdPrim
|
|||
if (interp == pxr::UsdGeomTokens->vertex &&
|
||||
joint_weights.size() != mesh->totvert * joint_weights_elem_size)
|
||||
{
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Joint weights of unexpected size for vertex interpolation for prim %s",
|
||||
__func__,
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Joint weights of unexpected size for vertex interpolation for prim %s",
|
||||
__func__,
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (interp == pxr::UsdGeomTokens->constant && joint_weights.size() != joint_weights_elem_size) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Joint weights of unexpected size for constant interpolation for prim %s",
|
||||
__func__,
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Joint weights of unexpected size for constant interpolation for prim %s",
|
||||
__func__,
|
||||
prim.GetPath().GetAsString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -989,10 +1023,11 @@ void import_mesh_skel_bindings(Main *bmain, Object *mesh_obj, const pxr::UsdPrim
|
|||
}
|
||||
|
||||
if (BKE_object_defgroup_data_create(static_cast<ID *>(mesh_obj->data)) == nullptr) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"%s: Error creating deform group data for mesh %s",
|
||||
__func__,
|
||||
mesh_obj->id.name + 2);
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"%s: Error creating deform group data for mesh %s",
|
||||
__func__,
|
||||
mesh_obj->id.name + 2);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "DNA_windowmanager_types.h"
|
||||
#include <map>
|
||||
#include <pxr/usd/usd/prim.h>
|
||||
#include <pxr/usd/usdSkel/skeletonQuery.h>
|
||||
|
@ -35,12 +36,15 @@ struct ImportSettings;
|
|||
* \param bmain: Main pointer
|
||||
* \param mesh_obj: Mesh object to which imported shape keys will be added
|
||||
* \param prim: The USD primitive from which blend-shapes will be imported
|
||||
* \param reports: the storage for potential warning or error reports (generated using BKE_report
|
||||
* API).
|
||||
* \param import_anim: Whether to import time-sampled weights as shape key
|
||||
* animation curves
|
||||
*/
|
||||
void import_blendshapes(Main *bmain,
|
||||
Object *mesh_obj,
|
||||
const pxr::UsdPrim &prim,
|
||||
ReportList *reports,
|
||||
bool import_anim = true);
|
||||
|
||||
/**
|
||||
|
@ -51,12 +55,15 @@ void import_blendshapes(Main *bmain,
|
|||
* \param bmain: Main pointer
|
||||
* \param arm_obj: Armature object to which the bone hierarchy will be added
|
||||
* \param skel: The USD skeleton from which bones and animation will be imported
|
||||
* \param reports: the storage for potential warning or error reports (generated using BKE_report
|
||||
* API).
|
||||
* \param import_anim: Whether to import time-sampled joint transforms as bone
|
||||
* animation curves
|
||||
*/
|
||||
void import_skeleton(Main *bmain,
|
||||
Object *arm_obj,
|
||||
const pxr::UsdSkelSkeleton &skel,
|
||||
ReportList *reports,
|
||||
bool import_anim = true);
|
||||
/**
|
||||
* Import skinning data from a source USD prim as deform groups and an armature
|
||||
|
@ -66,7 +73,12 @@ void import_skeleton(Main *bmain,
|
|||
* \param bmain: Main pointer
|
||||
* \param obj: Mesh object to which an armature modifier will be added
|
||||
* \param prim: The USD primitive from which skinning data will be imported
|
||||
* \param reports: the storage for potential warning or error reports (generated using BKE_report
|
||||
* API).
|
||||
*/
|
||||
void import_mesh_skel_bindings(Main *bmain, Object *mesh_obj, const pxr::UsdPrim &prim);
|
||||
void import_mesh_skel_bindings(Main *bmain,
|
||||
Object *mesh_obj,
|
||||
const pxr::UsdPrim &prim,
|
||||
ReportList *reports);
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <pxr/usd/usdGeom/bboxCache.h>
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "BLI_assert.h"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
@ -167,9 +169,10 @@ void USDAbstractWriter::author_extent(const pxr::UsdTimeCode timecode, pxr::UsdG
|
|||
pxr::GfBBox3d bounds = bboxCache.ComputeLocalBound(prim.GetPrim());
|
||||
if (pxr::GfBBox3d() == bounds) {
|
||||
/* This will occur, for example, if a mesh does not have any vertices. */
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD Export: no bounds could be computed for %s",
|
||||
prim.GetPrim().GetName().GetText());
|
||||
BKE_reportf(reports(),
|
||||
RPT_WARNING,
|
||||
"USD Export: no bounds could be computed for %s",
|
||||
prim.GetPrim().GetName().GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
|
||||
#include "DEG_depsgraph_query.hh"
|
||||
|
||||
#include "WM_types.hh"
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
#include "DNA_windowmanager_types.h"
|
||||
|
||||
struct Material;
|
||||
|
||||
|
@ -51,6 +54,12 @@ class USDAbstractWriter : public AbstractHierarchyWriter {
|
|||
|
||||
const pxr::SdfPath &usd_path() const;
|
||||
|
||||
/** Get the wmJobWorkerStatus-provided `reports` list pointer, to use with the BKE_report API. */
|
||||
ReportList *reports() const
|
||||
{
|
||||
return usd_export_context_.export_params.worker_status->reports;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void do_write(HierarchyContext &context) = 0;
|
||||
std::string get_export_file_path() const;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "BKE_curves.hh"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLT_translation.h"
|
||||
|
@ -26,7 +27,6 @@
|
|||
#include "RNA_enum_types.hh"
|
||||
|
||||
#include "WM_api.hh"
|
||||
#include "WM_types.hh"
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
||||
|
@ -85,7 +85,8 @@ static void populate_curve_widths(const bke::CurvesGeometry &geometry, pxr::VtAr
|
|||
static pxr::TfToken get_curve_width_interpolation(const pxr::VtArray<float> &widths,
|
||||
const pxr::VtArray<int> &segments,
|
||||
const pxr::VtIntArray &control_point_counts,
|
||||
const bool is_cyclic)
|
||||
const bool is_cyclic,
|
||||
ReportList *reports)
|
||||
{
|
||||
if (widths.empty()) {
|
||||
return pxr::TfToken();
|
||||
|
@ -110,7 +111,7 @@ static pxr::TfToken get_curve_width_interpolation(const pxr::VtArray<float> &wid
|
|||
return pxr::UsdGeomTokens->varying;
|
||||
}
|
||||
|
||||
WM_report(RPT_WARNING, "Curve width size not supported for USD interpolation");
|
||||
BKE_report(reports, RPT_WARNING, "Curve width size not supported for USD interpolation");
|
||||
return pxr::TfToken();
|
||||
}
|
||||
|
||||
|
@ -158,7 +159,8 @@ static void populate_curve_props(const bke::CurvesGeometry &geometry,
|
|||
pxr::VtArray<float> &widths,
|
||||
pxr::TfToken &interpolation,
|
||||
const bool is_cyclic,
|
||||
const bool is_cubic)
|
||||
const bool is_cubic,
|
||||
ReportList *reports)
|
||||
{
|
||||
const int num_curves = geometry.curve_num;
|
||||
const Span<float3> positions = geometry.positions();
|
||||
|
@ -169,7 +171,8 @@ static void populate_curve_props(const bke::CurvesGeometry &geometry,
|
|||
geometry, positions, verts, control_point_counts, segments, is_cyclic, is_cubic);
|
||||
|
||||
populate_curve_widths(geometry, widths);
|
||||
interpolation = get_curve_width_interpolation(widths, segments, control_point_counts, is_cyclic);
|
||||
interpolation = get_curve_width_interpolation(
|
||||
widths, segments, control_point_counts, is_cyclic, reports);
|
||||
}
|
||||
|
||||
static void populate_curve_verts_for_bezier(const bke::CurvesGeometry &geometry,
|
||||
|
@ -246,7 +249,8 @@ static void populate_curve_props_for_bezier(const bke::CurvesGeometry &geometry,
|
|||
pxr::VtIntArray &control_point_counts,
|
||||
pxr::VtArray<float> &widths,
|
||||
pxr::TfToken &interpolation,
|
||||
const bool is_cyclic)
|
||||
const bool is_cyclic,
|
||||
ReportList *reports)
|
||||
{
|
||||
|
||||
const int num_curves = geometry.curve_num;
|
||||
|
@ -262,7 +266,8 @@ static void populate_curve_props_for_bezier(const bke::CurvesGeometry &geometry,
|
|||
geometry, positions, handles_l, handles_r, verts, control_point_counts, segments, is_cyclic);
|
||||
|
||||
populate_curve_widths(geometry, widths);
|
||||
interpolation = get_curve_width_interpolation(widths, segments, control_point_counts, is_cyclic);
|
||||
interpolation = get_curve_width_interpolation(
|
||||
widths, segments, control_point_counts, is_cyclic, reports);
|
||||
}
|
||||
|
||||
static void populate_curve_props_for_nurbs(const bke::CurvesGeometry &geometry,
|
||||
|
@ -397,7 +402,8 @@ void USDCurvesWriter::do_write(HierarchyContext &context)
|
|||
});
|
||||
|
||||
if (number_of_curve_types > 1) {
|
||||
WM_report(RPT_WARNING, "Cannot export mixed curve types in the same Curves object");
|
||||
BKE_report(
|
||||
reports(), RPT_WARNING, "Cannot export mixed curve types in the same Curves object");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -413,8 +419,9 @@ void USDCurvesWriter::do_write(HierarchyContext &context)
|
|||
}
|
||||
|
||||
if (!all_same_cyclic_type) {
|
||||
WM_report(RPT_WARNING,
|
||||
"Cannot export mixed cyclic and non-cyclic curves in the same Curves object");
|
||||
BKE_report(reports(),
|
||||
RPT_WARNING,
|
||||
"Cannot export mixed cyclic and non-cyclic curves in the same Curves object");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -441,12 +448,13 @@ void USDCurvesWriter::do_write(HierarchyContext &context)
|
|||
RNA_enum_name_from_value(
|
||||
rna_enum_curves_type_items, int(curve_type), ¤t_curve_type_name);
|
||||
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD does not support animating curve types. The curve type changes from %s to "
|
||||
"%s on frame %f",
|
||||
IFACE_(first_frame_curve_type_name),
|
||||
IFACE_(current_curve_type_name),
|
||||
timecode.GetValue());
|
||||
BKE_reportf(reports(),
|
||||
RPT_WARNING,
|
||||
"USD does not support animating curve types. The curve type changes from %s to "
|
||||
"%s on frame %f",
|
||||
IFACE_(first_frame_curve_type_name),
|
||||
IFACE_(current_curve_type_name),
|
||||
timecode.GetValue());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -454,22 +462,34 @@ void USDCurvesWriter::do_write(HierarchyContext &context)
|
|||
case CURVE_TYPE_POLY:
|
||||
usd_curves = DefineUsdGeomBasisCurves(pxr::VtValue(), is_cyclic, false);
|
||||
|
||||
populate_curve_props(
|
||||
geometry, verts, control_point_counts, widths, interpolation, is_cyclic, false);
|
||||
populate_curve_props(geometry,
|
||||
verts,
|
||||
control_point_counts,
|
||||
widths,
|
||||
interpolation,
|
||||
is_cyclic,
|
||||
false,
|
||||
reports());
|
||||
break;
|
||||
case CURVE_TYPE_CATMULL_ROM:
|
||||
usd_curves = DefineUsdGeomBasisCurves(
|
||||
pxr::VtValue(pxr::UsdGeomTokens->catmullRom), is_cyclic, true);
|
||||
|
||||
populate_curve_props(
|
||||
geometry, verts, control_point_counts, widths, interpolation, is_cyclic, true);
|
||||
populate_curve_props(geometry,
|
||||
verts,
|
||||
control_point_counts,
|
||||
widths,
|
||||
interpolation,
|
||||
is_cyclic,
|
||||
true,
|
||||
reports());
|
||||
break;
|
||||
case CURVE_TYPE_BEZIER:
|
||||
usd_curves = DefineUsdGeomBasisCurves(
|
||||
pxr::VtValue(pxr::UsdGeomTokens->bezier), is_cyclic, true);
|
||||
|
||||
populate_curve_props_for_bezier(
|
||||
geometry, verts, control_point_counts, widths, interpolation, is_cyclic);
|
||||
geometry, verts, control_point_counts, widths, interpolation, is_cyclic, reports());
|
||||
break;
|
||||
case CURVE_TYPE_NURBS: {
|
||||
pxr::VtArray<double> knots;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "BKE_main.h"
|
||||
#include "BKE_node.hh"
|
||||
#include "BKE_node_runtime.hh"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "IMB_colormanagement.h"
|
||||
|
||||
|
@ -428,7 +429,8 @@ static std::string get_in_memory_texture_filename(Image *ima)
|
|||
|
||||
static void export_in_memory_texture(Image *ima,
|
||||
const std::string &export_dir,
|
||||
const bool allow_overwrite)
|
||||
const bool allow_overwrite,
|
||||
ReportList *reports)
|
||||
{
|
||||
char image_abs_path[FILE_MAX];
|
||||
|
||||
|
@ -472,7 +474,8 @@ static void export_in_memory_texture(Image *ima,
|
|||
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);
|
||||
BKE_reportf(
|
||||
reports, RPT_WARNING, "USD export: couldn't export in-memory texture to %s", export_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -702,7 +705,8 @@ static std::string get_tex_image_asset_filepath(const USDExporterContext &usd_ex
|
|||
* destination directory. */
|
||||
static void copy_tiled_textures(Image *ima,
|
||||
const std::string &dest_dir,
|
||||
const bool allow_overwrite)
|
||||
const bool allow_overwrite,
|
||||
ReportList *reports)
|
||||
{
|
||||
char src_path[FILE_MAX];
|
||||
get_absolute_path(ima, src_path);
|
||||
|
@ -743,17 +747,21 @@ static void copy_tiled_textures(Image *ima,
|
|||
|
||||
/* Copy the file. */
|
||||
if (BLI_copy(src_tile_path, dest_tile_path) != 0) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD export: could not copy texture tile from %s to %s",
|
||||
src_tile_path,
|
||||
dest_tile_path);
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"USD export: could not copy texture tile from %s to %s",
|
||||
src_tile_path,
|
||||
dest_tile_path);
|
||||
}
|
||||
}
|
||||
MEM_SAFE_FREE(udim_pattern);
|
||||
}
|
||||
|
||||
/* Copy the given image to the destination directory. */
|
||||
static void copy_single_file(Image *ima, const std::string &dest_dir, const bool allow_overwrite)
|
||||
static void copy_single_file(Image *ima,
|
||||
const std::string &dest_dir,
|
||||
const bool allow_overwrite,
|
||||
ReportList *reports)
|
||||
{
|
||||
char source_path[FILE_MAX];
|
||||
get_absolute_path(ima, source_path);
|
||||
|
@ -777,8 +785,11 @@ static void copy_single_file(Image *ima, const std::string &dest_dir, const bool
|
|||
|
||||
/* Copy the file. */
|
||||
if (BLI_copy(source_path, dest_path) != 0) {
|
||||
WM_reportf(
|
||||
RPT_WARNING, "USD export: could not copy texture from %s to %s", source_path, dest_path);
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"USD export: could not copy texture from %s to %s",
|
||||
source_path,
|
||||
dest_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -816,13 +827,16 @@ static void export_texture(const USDExporterContext &usd_export_context, bNode *
|
|||
std::string dest_dir(tex_dir_path);
|
||||
|
||||
if (is_generated || is_dirty || is_packed) {
|
||||
export_in_memory_texture(ima, dest_dir, allow_overwrite);
|
||||
export_in_memory_texture(
|
||||
ima, dest_dir, allow_overwrite, usd_export_context.export_params.worker_status->reports);
|
||||
}
|
||||
else if (ima->source == IMA_SRC_TILED) {
|
||||
copy_tiled_textures(ima, dest_dir, allow_overwrite);
|
||||
copy_tiled_textures(
|
||||
ima, dest_dir, allow_overwrite, usd_export_context.export_params.worker_status->reports);
|
||||
}
|
||||
else {
|
||||
copy_single_file(ima, dest_dir, allow_overwrite);
|
||||
copy_single_file(
|
||||
ima, dest_dir, allow_overwrite, usd_export_context.export_params.worker_status->reports);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -853,7 +867,10 @@ pxr::UsdShadeMaterial create_usd_material(const USDExporterContext &usd_export_c
|
|||
create_usd_viewport_material(usd_export_context, material, usd_material);
|
||||
}
|
||||
|
||||
call_material_export_hooks(usd_export_context.stage, material, usd_material);
|
||||
call_material_export_hooks(usd_export_context.stage,
|
||||
material,
|
||||
usd_material,
|
||||
usd_export_context.export_params.worker_status->reports);
|
||||
|
||||
return usd_material;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "BKE_mesh_wrapper.hh"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_object.hh"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "DEG_depsgraph.hh"
|
||||
|
||||
|
@ -128,7 +129,7 @@ void USDGenericMeshWriter::write_custom_data(const Mesh *mesh, pxr::UsdGeomMesh
|
|||
}
|
||||
|
||||
static std::optional<pxr::SdfValueTypeName> convert_blender_type_to_usd(
|
||||
const eCustomDataType blender_type)
|
||||
const eCustomDataType blender_type, ReportList *reports)
|
||||
{
|
||||
switch (blender_type) {
|
||||
case CD_PROP_FLOAT:
|
||||
|
@ -147,13 +148,13 @@ static std::optional<pxr::SdfValueTypeName> convert_blender_type_to_usd(
|
|||
case CD_PROP_QUATERNION:
|
||||
return pxr::SdfValueTypeNames->QuatfArray;
|
||||
default:
|
||||
WM_reportf(RPT_WARNING, "Unsupported type for mesh data");
|
||||
BKE_reportf(reports, RPT_WARNING, "Unsupported type for mesh data");
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
static const std::optional<pxr::TfToken> convert_blender_domain_to_usd(
|
||||
const eAttrDomain blender_domain)
|
||||
const eAttrDomain blender_domain, ReportList *reports)
|
||||
{
|
||||
switch (blender_domain) {
|
||||
case ATTR_DOMAIN_CORNER:
|
||||
|
@ -165,7 +166,7 @@ static const std::optional<pxr::TfToken> convert_blender_domain_to_usd(
|
|||
|
||||
/* Notice: Edge types are not supported in USD! */
|
||||
default:
|
||||
WM_reportf(RPT_WARNING, "Unsupported type for mesh data");
|
||||
BKE_reportf(reports, RPT_WARNING, "Unsupported type for mesh data");
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
@ -231,9 +232,10 @@ void USDGenericMeshWriter::write_generic_data(const Mesh *mesh,
|
|||
const pxr::UsdGeomPrimvarsAPI pvApi = pxr::UsdGeomPrimvarsAPI(usd_mesh);
|
||||
|
||||
/* Varying type depends on original domain. */
|
||||
const std::optional<pxr::TfToken> prim_varying = convert_blender_domain_to_usd(meta_data.domain);
|
||||
const std::optional<pxr::TfToken> prim_varying = convert_blender_domain_to_usd(meta_data.domain,
|
||||
reports());
|
||||
const std::optional<pxr::SdfValueTypeName> prim_attr_type = convert_blender_type_to_usd(
|
||||
meta_data.data_type);
|
||||
meta_data.data_type, reports());
|
||||
|
||||
const GVArraySpan attribute = *mesh->attributes().lookup(
|
||||
attribute_id, meta_data.domain, meta_data.data_type);
|
||||
|
@ -242,10 +244,11 @@ void USDGenericMeshWriter::write_generic_data(const Mesh *mesh,
|
|||
}
|
||||
|
||||
if (!prim_varying || !prim_attr_type) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"Mesh %s, Attribute %s cannot be converted to USD",
|
||||
&mesh->id.name[2],
|
||||
attribute_id.name().data());
|
||||
BKE_reportf(reports(),
|
||||
RPT_WARNING,
|
||||
"Mesh %s, Attribute %s cannot be converted to USD",
|
||||
&mesh->id.name[2],
|
||||
attribute_id.name().data());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "DNA_volume_types.h"
|
||||
#include "DNA_windowmanager_types.h"
|
||||
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_volume.h"
|
||||
|
||||
#include "BLI_fileops.h"
|
||||
|
@ -47,9 +48,10 @@ void USDVolumeWriter::do_write(HierarchyContext &context)
|
|||
|
||||
auto vdb_file_path = resolve_vdb_file(volume);
|
||||
if (!vdb_file_path.has_value()) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD Export: failed to resolve .vdb file for object: %s",
|
||||
volume->id.name + 2);
|
||||
BKE_reportf(reports(),
|
||||
RPT_WARNING,
|
||||
"USD Export: failed to resolve .vdb file for object: %s",
|
||||
volume->id.name + 2);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -58,9 +60,10 @@ void USDVolumeWriter::do_write(HierarchyContext &context)
|
|||
vdb_file_path = relative_vdb_file_path;
|
||||
}
|
||||
else {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD Export: couldn't construct relative file path for .vdb file, absolute path "
|
||||
"will be used instead");
|
||||
BKE_reportf(reports(),
|
||||
RPT_WARNING,
|
||||
"USD Export: couldn't construct relative file path for .vdb file, absolute path "
|
||||
"will be used instead");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ TEST_F(UsdCurvesTest, usd_export_curves)
|
|||
|
||||
USDExportParams params;
|
||||
|
||||
const bool result = USD_export(context, output_filename.c_str(), ¶ms, false);
|
||||
const bool result = USD_export(context, output_filename.c_str(), ¶ms, false, nullptr);
|
||||
EXPECT_TRUE(result) << "USD export should succed.";
|
||||
|
||||
pxr::UsdStageRefPtr stage = pxr::UsdStage::Open(output_filename);
|
||||
|
|
|
@ -214,7 +214,7 @@ TEST_F(UsdExportTest, usd_export_rain_mesh)
|
|||
params.export_uvmaps = false;
|
||||
params.visible_objects_only = true;
|
||||
|
||||
bool result = USD_export(context, output_filename.c_str(), ¶ms, false);
|
||||
bool result = USD_export(context, output_filename.c_str(), ¶ms, false, nullptr);
|
||||
ASSERT_TRUE(result) << "Writing to " << output_filename << " failed!";
|
||||
|
||||
pxr::UsdStageRefPtr stage = pxr::UsdStage::Open(output_filename);
|
||||
|
@ -280,7 +280,7 @@ TEST_F(UsdExportTest, usd_export_material)
|
|||
params.generate_preview_surface = true;
|
||||
params.relative_paths = false;
|
||||
|
||||
const bool result = USD_export(context, output_filename.c_str(), ¶ms, false);
|
||||
const bool result = USD_export(context, output_filename.c_str(), ¶ms, false, nullptr);
|
||||
ASSERT_TRUE(result) << "Unable to export stage to " << output_filename;
|
||||
|
||||
pxr::UsdStageRefPtr stage = pxr::UsdStage::Open(output_filename);
|
||||
|
|
|
@ -98,7 +98,7 @@ TEST_F(UsdUsdzExportTest, usdz_export)
|
|||
params.export_materials = false;
|
||||
params.visible_objects_only = false;
|
||||
|
||||
bool result = USD_export(context, output_filepath, ¶ms, false);
|
||||
bool result = USD_export(context, output_filepath, ¶ms, false, nullptr);
|
||||
ASSERT_TRUE(result) << "usd export to " << output_filepath << " failed.";
|
||||
|
||||
pxr::UsdStageRefPtr stage = pxr::UsdStage::Open(output_filepath);
|
||||
|
|
|
@ -16,6 +16,7 @@ struct CacheArchiveHandle;
|
|||
struct CacheReader;
|
||||
struct Object;
|
||||
struct bContext;
|
||||
struct wmJobWorkerStatus;
|
||||
|
||||
/* Behavior when the name of an imported material
|
||||
* conflicts with an existing material. */
|
||||
|
@ -55,6 +56,10 @@ struct USDExportParams {
|
|||
bool overwrite_textures = true;
|
||||
bool relative_paths = true;
|
||||
char root_prim_path[1024] = ""; /* FILE_MAX */
|
||||
|
||||
/** Communication structure between the wmJob management code and the worker code. Currently used
|
||||
* to generate safely reports from the worker thread. */
|
||||
wmJobWorkerStatus *worker_status;
|
||||
};
|
||||
|
||||
struct USDImportParams {
|
||||
|
@ -91,6 +96,10 @@ struct USDImportParams {
|
|||
char import_textures_dir[768]; /* FILE_MAXDIR */
|
||||
eUSDTexNameCollisionMode tex_name_collision_mode;
|
||||
bool import_all_materials;
|
||||
|
||||
/** Communication structure between the wmJob management code and the worker code. Currently used
|
||||
* to generate safely reports from the worker thread. */
|
||||
wmJobWorkerStatus *worker_status;
|
||||
};
|
||||
|
||||
/* This struct is in place to store the mesh sequence parameters needed when reading a data from a
|
||||
|
@ -115,12 +124,14 @@ USDMeshReadParams create_mesh_read_params(double motion_sample_time, int read_fl
|
|||
bool USD_export(struct bContext *C,
|
||||
const char *filepath,
|
||||
const struct USDExportParams *params,
|
||||
bool as_background_job);
|
||||
bool as_background_job,
|
||||
ReportList *reports);
|
||||
|
||||
bool USD_import(struct bContext *C,
|
||||
const char *filepath,
|
||||
const struct USDImportParams *params,
|
||||
bool as_background_job);
|
||||
bool as_background_job,
|
||||
ReportList *reports);
|
||||
|
||||
int USD_get_version(void);
|
||||
|
||||
|
|
|
@ -591,6 +591,15 @@ void WM_report_banner_show(wmWindowManager *wm, wmWindow *win) ATTR_NONNULL(1);
|
|||
* Hide all currently displayed banners and abort their timer.
|
||||
*/
|
||||
void WM_report_banners_cancel(Main *bmain);
|
||||
/** Add a whole list of reports to the WM ReportList, and show the banner.
|
||||
*
|
||||
* \note In case the given \a reports is a `nullptr`, or has its #RPT_OP_HOLD flag set, this
|
||||
* function does nothing.
|
||||
*
|
||||
* \params reports The #ReportList from which to move reports to the WM one, may be `nullptr`.
|
||||
* \params wm the WindowManager to add given \a reports to. If `nullptr`, the first WM of current
|
||||
* #G_MAIN will be used. */
|
||||
void WM_reports_add(wmWindowManager *wm, ReportList *reports);
|
||||
void WM_report(eReportType type, const char *message);
|
||||
void WM_reportf(eReportType type, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3);
|
||||
|
||||
|
|
|
@ -99,6 +99,7 @@ struct bContext;
|
|||
struct bContextStore;
|
||||
struct GreasePencil;
|
||||
struct GreasePencilLayer;
|
||||
struct ReportList;
|
||||
struct wmDrag;
|
||||
struct wmDropBox;
|
||||
struct wmEvent;
|
||||
|
@ -943,6 +944,10 @@ struct wmJobWorkerStatus {
|
|||
|
||||
/** OUTPUT - Progress as reported by the worker, from `0.0f` to `1.0f`. */
|
||||
float progress;
|
||||
|
||||
/** OUTPUT - Storage of reports generated during this job's run. Contains its own locking for
|
||||
* thread-safety. */
|
||||
ReportList *reports;
|
||||
};
|
||||
|
||||
struct wmOperatorType {
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_timer.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
|
@ -928,27 +929,33 @@ void WM_ndof_deadzone_set(float deadzone)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void wm_add_reports(ReportList *reports)
|
||||
void WM_reports_add(wmWindowManager *wm, ReportList *reports)
|
||||
{
|
||||
/* If the caller owns them, handle this. */
|
||||
if (reports->list.first && (reports->flag & RPT_OP_HOLD) == 0) {
|
||||
wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
|
||||
|
||||
/* Add reports to the global list, otherwise they are not seen. */
|
||||
BKE_reports_move_to_reports(&wm->reports, reports);
|
||||
|
||||
WM_report_banner_show(wm, nullptr);
|
||||
if (!reports || BLI_listbase_is_empty(&reports->list) || (reports->flag & RPT_OP_HOLD) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wm) {
|
||||
wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
|
||||
}
|
||||
|
||||
/* Add reports to the global list, otherwise they are not seen. */
|
||||
BKE_reports_move_to_reports(&wm->reports, reports);
|
||||
|
||||
WM_report_banner_show(wm, nullptr);
|
||||
}
|
||||
|
||||
void WM_report(eReportType type, const char *message)
|
||||
{
|
||||
BLI_assert_msg(BLI_thread_is_main(), "WM_report should only be called from the main thread");
|
||||
|
||||
ReportList reports;
|
||||
BKE_reports_init(&reports, RPT_STORE | RPT_PRINT);
|
||||
BKE_report_print_level_set(&reports, RPT_WARNING);
|
||||
BKE_report(&reports, type, message);
|
||||
|
||||
wm_add_reports(&reports);
|
||||
WM_reports_add(nullptr, &reports);
|
||||
|
||||
BKE_reports_free(&reports);
|
||||
}
|
||||
|
@ -1112,7 +1119,7 @@ static void wm_operator_reports(bContext *C,
|
|||
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO_REPORT, nullptr);
|
||||
}
|
||||
/* If the caller owns them, handle this. */
|
||||
wm_add_reports(op->reports);
|
||||
WM_reports_add(CTX_wm_manager(C), op->reports);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2498,7 +2505,7 @@ static eHandlerActionFlag wm_handler_operator_call(bContext *C,
|
|||
else {
|
||||
/* Not very common, but modal operators may report before finishing. */
|
||||
if (!BLI_listbase_is_empty(&op->reports->list)) {
|
||||
wm_add_reports(op->reports);
|
||||
WM_reports_add(wm, op->reports);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2831,7 +2838,7 @@ static eHandlerActionFlag wm_handler_fileselect_do(bContext *C,
|
|||
BKE_report_print_level_set(handler->op->reports, RPT_WARNING);
|
||||
UI_popup_menu_reports(C, handler->op->reports);
|
||||
|
||||
wm_add_reports(handler->op->reports);
|
||||
WM_reports_add(CTX_wm_manager(C), handler->op->reports);
|
||||
|
||||
CTX_wm_window_set(C, win_prev);
|
||||
CTX_wm_area_set(C, area_prev);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "BKE_context.h"
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_report.h"
|
||||
|
||||
#include "SEQ_prefetch.h"
|
||||
|
||||
|
@ -206,6 +207,10 @@ wmJob *WM_jobs_get(wmWindowManager *wm,
|
|||
|
||||
wm_job->main_thread_mutex = BLI_ticket_mutex_alloc();
|
||||
WM_job_main_thread_lock_acquire(wm_job);
|
||||
|
||||
wm_job->worker_status.reports = MEM_new<ReportList>(__func__);
|
||||
BKE_reports_init(wm_job->worker_status.reports, RPT_STORE | RPT_PRINT);
|
||||
BKE_report_print_level_set(wm_job->worker_status.reports, RPT_WARNING);
|
||||
}
|
||||
/* else: a running job, be careful */
|
||||
|
||||
|
@ -381,6 +386,11 @@ void WM_jobs_callbacks_ex(wmJob *wm_job,
|
|||
wm_job->canceled = canceled;
|
||||
}
|
||||
|
||||
static void wm_jobs_reports_update(wmWindowManager *wm, wmJob *wm_job)
|
||||
{
|
||||
WM_reports_add(wm, wm_job->worker_status.reports);
|
||||
}
|
||||
|
||||
static void *do_job_thread(void *job_v)
|
||||
{
|
||||
wmJob *wm_job = static_cast<wmJob *>(job_v);
|
||||
|
@ -496,7 +506,7 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *wm_job)
|
|||
}
|
||||
}
|
||||
|
||||
static void wm_job_end(wmJob *wm_job)
|
||||
static void wm_job_end(wmWindowManager *wm, wmJob *wm_job)
|
||||
{
|
||||
BLI_assert_msg(BLI_thread_is_main(), "wm_job_end should only be called from the main thread");
|
||||
if (wm_job->endjob) {
|
||||
|
@ -512,6 +522,9 @@ static void wm_job_end(wmJob *wm_job)
|
|||
if (final_callback) {
|
||||
final_callback(wm_job->run_customdata);
|
||||
}
|
||||
|
||||
/* Ensure all reports have been moved to WM. */
|
||||
wm_jobs_reports_update(wm, wm_job);
|
||||
}
|
||||
|
||||
static void wm_job_free(wmWindowManager *wm, wmJob *wm_job)
|
||||
|
@ -519,6 +532,10 @@ static void wm_job_free(wmWindowManager *wm, wmJob *wm_job)
|
|||
BLI_remlink(&wm->jobs, wm_job);
|
||||
WM_job_main_thread_lock_release(wm_job);
|
||||
BLI_ticket_mutex_free(wm_job->main_thread_mutex);
|
||||
|
||||
BLI_assert(BLI_listbase_is_empty(&wm_job->worker_status.reports->list));
|
||||
BKE_reports_free(wm_job->worker_status.reports);
|
||||
MEM_delete(wm_job->worker_status.reports);
|
||||
MEM_freeN(wm_job);
|
||||
}
|
||||
|
||||
|
@ -534,7 +551,7 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *wm_job)
|
|||
WM_job_main_thread_lock_release(wm_job);
|
||||
BLI_threadpool_end(&wm_job->threads);
|
||||
WM_job_main_thread_lock_acquire(wm_job);
|
||||
wm_job_end(wm_job);
|
||||
wm_job_end(wm, wm_job);
|
||||
}
|
||||
|
||||
if (wm_job->wt) {
|
||||
|
@ -644,7 +661,7 @@ void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt)
|
|||
}
|
||||
|
||||
if (wm_job->ready) {
|
||||
wm_job_end(wm_job);
|
||||
wm_job_end(wm, wm_job);
|
||||
|
||||
/* free own data */
|
||||
wm_job->run_free(wm_job->run_customdata);
|
||||
|
@ -689,12 +706,18 @@ void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt)
|
|||
|
||||
/* remove wm_job */
|
||||
wm_job_free(wm, wm_job);
|
||||
wm_job = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (wm_job->suspended) {
|
||||
WM_jobs_start(wm, wm_job);
|
||||
}
|
||||
|
||||
/* Move pending reports generated by the worker thread to the WM main list. */
|
||||
if (wm_job) {
|
||||
wm_jobs_reports_update(wm, wm_job);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update progress bars in windows. */
|
||||
|
|
|
@ -46,8 +46,12 @@ class USDImportTest(AbstractUSDTest):
|
|||
self.assertEqual({'FINISHED'}, res, f"Unable to import USD file {infile}")
|
||||
|
||||
infile = str(self.testdir / "this_file_doesn't_exist.usda")
|
||||
res = bpy.ops.wm.usd_import(filepath=infile)
|
||||
self.assertEqual({'CANCELLED'}, res, "Was somehow able to import a non-existent USD file!")
|
||||
# RPT_ERROR Reports from operators generate `RuntimeError` python exceptions.
|
||||
try:
|
||||
res = bpy.ops.wm.usd_import(filepath=infile)
|
||||
self.assertEqual({'CANCELLED'}, res, "Was somehow able to import a non-existent USD file!")
|
||||
except RuntimeError as e:
|
||||
self.assertTrue(e.args[0].startswith("Error: USD Import: unable to open stage to read"))
|
||||
|
||||
def test_import_prim_hierarchy(self):
|
||||
"""Test importing a simple object hierarchy from a USDA file."""
|
||||
|
|
Loading…
Reference in New Issue