diff options
author | Sybren A. Stüvel <sybren@blender.org> | 2020-03-06 18:19:35 +0300 |
---|---|---|
committer | Sybren A. Stüvel <sybren@blender.org> | 2020-03-06 18:19:45 +0300 |
commit | eb522af4fec58876ac1b0a73ad9bcdae2d82d33f (patch) | |
tree | 485c6a1fb23b5be256757375e2157378d3a5c61b /source/blender/io/usd/intern/usd_capi.cc | |
parent | ff60dd8b18ed00902e5bdfd36882072db7af8735 (diff) |
Cleanup: move Alembic, AVI, Collada, and USD to `source/blender/io`
This moves the `alembic`, `avi`, `collada`, and `usd` modules into a common
`io` directory.
This also cleans up some `#include "../../{somedir}/{somefile}.h"` by
adding `../../io/{somedir}` to `CMakeLists.txt` and then just using
`#include "{somefile}.h"`.
No functional changes.
Diffstat (limited to 'source/blender/io/usd/intern/usd_capi.cc')
-rw-r--r-- | source/blender/io/usd/intern/usd_capi.cc | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/source/blender/io/usd/intern/usd_capi.cc b/source/blender/io/usd/intern/usd_capi.cc new file mode 100644 index 00000000000..83e11cd7bf3 --- /dev/null +++ b/source/blender/io/usd/intern/usd_capi.cc @@ -0,0 +1,233 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2019 Blender Foundation. + * All rights reserved. + */ + +#include "usd.h" +#include "usd_hierarchy_iterator.h" + +#include <pxr/pxr.h> +#include <pxr/usd/usd/stage.h> +#include <pxr/usd/usdGeom/tokens.h> + +#include "MEM_guardedalloc.h" + +extern "C" { +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" + +#include "DNA_scene_types.h" + +#include "BKE_blender_version.h" +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_scene.h" + +#include "BLI_fileops.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "WM_api.h" +#include "WM_types.h" +} + +namespace USD { + +struct ExportJobData { + ViewLayer *view_layer; + Main *bmain; + Depsgraph *depsgraph; + wmWindowManager *wm; + + char filename[FILE_MAX]; + USDExportParams params; + + short *stop; + short *do_update; + float *progress; + + bool was_canceled; + bool export_ok; +}; + +static void export_startjob(void *customdata, short *stop, short *do_update, float *progress) +{ + ExportJobData *data = static_cast<ExportJobData *>(customdata); + + data->stop = stop; + data->do_update = do_update; + data->progress = progress; + data->was_canceled = false; + + G.is_rendering = true; + WM_set_locked_interface(data->wm, true); + G.is_break = false; + + // Construct the depsgraph for exporting. + Scene *scene = DEG_get_input_scene(data->depsgraph); + ViewLayer *view_layer = DEG_get_input_view_layer(data->depsgraph); + DEG_graph_build_from_view_layer(data->depsgraph, data->bmain, scene, view_layer); + BKE_scene_graph_update_tagged(data->depsgraph, data->bmain); + + *progress = 0.0f; + *do_update = true; + + // For restoring the current frame after exporting animation is done. + const int orig_frame = CFRA; + + pxr::UsdStageRefPtr usd_stage = pxr::UsdStage::CreateNew(data->filename); + 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->filename); + data->export_ok = false; + return; + } + + usd_stage->SetMetadata(pxr::UsdGeomTokens->upAxis, pxr::VtValue(pxr::UsdGeomTokens->z)); + usd_stage->SetMetadata(pxr::UsdGeomTokens->metersPerUnit, + pxr::VtValue(scene->unit.scale_length)); + usd_stage->GetRootLayer()->SetDocumentation(std::string("Blender ") + versionstr); + + // Set up the stage for animated data. + if (data->params.export_animation) { + usd_stage->SetTimeCodesPerSecond(FPS); + usd_stage->SetStartTimeCode(scene->r.sfra); + usd_stage->SetEndTimeCode(scene->r.efra); + } + + USDHierarchyIterator iter(data->depsgraph, usd_stage, data->params); + + if (data->params.export_animation) { + // Writing the animated frames is not 100% of the work, but it's our best guess. + float progress_per_frame = 1.0f / std::max(1, (scene->r.efra - scene->r.sfra + 1)); + + for (float frame = scene->r.sfra; frame <= scene->r.efra; frame++) { + if (G.is_break || (stop != nullptr && *stop)) { + break; + } + + // Update the scene for the next frame to render. + scene->r.cfra = static_cast<int>(frame); + scene->r.subframe = frame - scene->r.cfra; + BKE_scene_graph_update_for_newframe(data->depsgraph, data->bmain); + + iter.set_export_frame(frame); + iter.iterate_and_write(); + + *progress += progress_per_frame; + *do_update = true; + } + } + else { + // If we're not animating, a single iteration over all objects is enough. + iter.iterate_and_write(); + } + + iter.release_writers(); + usd_stage->GetRootLayer()->Save(); + + // Finish up by going back to the keyframe that was current before we started. + if (CFRA != orig_frame) { + CFRA = orig_frame; + BKE_scene_graph_update_for_newframe(data->depsgraph, data->bmain); + } + + data->export_ok = !data->was_canceled; + + *progress = 1.0f; + *do_update = true; +} + +static void export_endjob(void *customdata) +{ + ExportJobData *data = static_cast<ExportJobData *>(customdata); + + DEG_graph_free(data->depsgraph); + + if (data->was_canceled && BLI_exists(data->filename)) { + BLI_delete(data->filename, false, false); + } + + G.is_rendering = false; + WM_set_locked_interface(data->wm, false); +} + +} // namespace USD + +bool USD_export(bContext *C, + const char *filepath, + const USDExportParams *params, + bool as_background_job) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + Scene *scene = CTX_data_scene(C); + + USD::ExportJobData *job = static_cast<USD::ExportJobData *>( + MEM_mallocN(sizeof(USD::ExportJobData), "ExportJobData")); + + job->bmain = CTX_data_main(C); + job->wm = CTX_wm_manager(C); + job->export_ok = false; + BLI_strncpy(job->filename, filepath, sizeof(job->filename)); + + job->depsgraph = DEG_graph_new(job->bmain, scene, view_layer, params->evaluation_mode); + job->params = *params; + + bool export_ok = false; + if (as_background_job) { + wmJob *wm_job = WM_jobs_get( + job->wm, CTX_wm_window(C), scene, "USD Export", WM_JOB_PROGRESS, WM_JOB_TYPE_ALEMBIC); + + /* setup job */ + WM_jobs_customdata_set(wm_job, job, MEM_freeN); + WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_FRAME, NC_SCENE | ND_FRAME); + WM_jobs_callbacks(wm_job, USD::export_startjob, NULL, NULL, USD::export_endjob); + + WM_jobs_start(CTX_wm_manager(C), wm_job); + } + else { + /* Fake a job context, so that we don't need NULL pointer checks while exporting. */ + short stop = 0, do_update = 0; + float progress = 0.f; + + USD::export_startjob(job, &stop, &do_update, &progress); + USD::export_endjob(job); + export_ok = job->export_ok; + + MEM_freeN(job); + } + + return export_ok; +} + +int USD_get_version(void) +{ + /* USD 19.11 defines: + * + * #define PXR_MAJOR_VERSION 0 + * #define PXR_MINOR_VERSION 19 + * #define PXR_PATCH_VERSION 11 + * #define PXR_VERSION 1911 + * + * So the major version is implicit/invisible in the public version number. + */ + return PXR_VERSION; +} |