//
// Copyright 2019 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://openusd.org/license.
//
#ifndef PXR_EXTRAS_USD_EXAMPLES_USD_RECURSIVE_PAYLOADS_EXAMPLE_FILE_FORMAT_H
#define PXR_EXTRAS_USD_EXAMPLES_USD_RECURSIVE_PAYLOADS_EXAMPLE_FILE_FORMAT_H
#include "pxr/pxr.h"
#include "pxr/usd/sdf/fileFormat.h"
#include "pxr/usd/pcp/dynamicFileFormatInterface.h"
#include "pxr/base/tf/staticTokens.h"
#include <string>
PXR_NAMESPACE_OPEN_SCOPE
#define USD_RECURSIVE_PAYLOADS_EXAMPLE_FILE_FORMAT_TOKENS \
((Id, "usdRecursivePayloadsExample")) \
((Version, "1.0")) \
((Target, "usd")) \
((Extension, "usdrecursivepayloadsexample")) \
((Depth, "UsdExample_depth")) \
((Num, "UsdExample_num")) \
((Radius, "UsdExample_radius")) \
((Height, "UsdExample_height")) \
((ArgDict, "UsdExample_argDict")) \
((PayloadId, "UsdExample_payloadId"))
TF_DECLARE_PUBLIC_TOKENS(UsdRecursivePayloadsExampleFileFormatTokens,
USD_RECURSIVE_PAYLOADS_EXAMPLE_FILE_FORMAT_TOKENS);
TF_DECLARE_WEAK_AND_REF_PTRS(UsdRecursivePayloadsExampleFileFormat);
TF_DECLARE_WEAK_AND_REF_PTRS(SdfLayerBase);
/// \class UsdRecursivePayloadsExampleFileFormat
///
/// This is an example of a dynamic file format plugin that demonstrates one
/// method of generating dynamic content from composed metadata fields in scene
/// description by creating scene description with payloads to the same dynamic
/// file but with different parameters.
///
/// This contents of a file of this format are expected to be the same as usda
/// file content. If the file is opened with file format arguments for "num" and
/// "depth" that are greater than 0, then it will generate a ring of Xform prim
/// children that will each have a payload to this file again but with depth-1.
/// It will also adds a "geom" child that references the payload asset file
/// with no parameters, just reading it as an sdf file and referencing the
/// default prim. Thus we end up with a recursively generated set of prims
/// containing the contents of the dynamic file.
///
/// As an example if you have the following prim defined in a usd file:
///
/// def Xform "Root" (
/// UsdExample_num = 2
/// UsdExample_depth = 3
/// UsdExample_radius = 20.0
/// payload = @cone.usdrecursivepayloadsexample@
/// ) {}
///
/// It will generate a prim structure that looks something like this:
///
/// Root (payload = @cone.usdrecursivepayloadsexample@
/// | UsdExample_num = 2
/// | UsdExample_depth = 3
/// | UsdExample_radius = 20.0)
/// |
/// | geom (reference = @cone.usdrecursivepayloadsexample@)
/// |
/// | Xform__2_0 (payload = @cone.usdrecursivepayloadsexample@
/// | | UsdExample_num = 2
/// | | UsdExample_depth = 2
/// | | UsdExample_radius = 10.0)
/// | |
/// | | geom (reference = @cone.usdrecursivepayloadsexample@)
/// | |
/// | | Xform__1_0 (payload = @cone.usdrecursivepayloadsexample@
/// | | | UsdExample_num = 2
/// | | | UsdExample_depth = 1
/// | | | UsdExample_radius = 5.0)
/// | | |
/// | | | geom (reference = @cone.usdrecursivepayloadsexample@)
/// | |
/// | | Xform__1_1 (payload = @cone.usdrecursivepayloadsexample@
/// | | | UsdExample_num = 2
/// | | | UsdExample_depth = 1
/// | | | UsdExample_radius = 5.0)
/// | | |
/// | | | geom (reference = @cone.usdrecursivepayloadsexample@)
/// |
/// | Xform__2_1 (payload = @cone.usdrecursivepayloadsexample@
/// | | UsdExample_num = 2
/// | | UsdExample_depth = 2
/// | | UsdExample_radius = 10.0)
/// | |
/// | | geom (reference = @cone.usdrecursivepayloadsexample@)
/// | |
/// | | Xform__1_0 (payload = @cone.usdrecursivepayloadsexample@
/// | | | UsdExample_num = 2
/// | | | UsdExample_depth = 1
/// | | | UsdExample_radius = 5.0)
/// | | |
/// | | | geom (reference = @cone.usdrecursivepayloadsexample@)
/// | |
/// | | Xform__1_1 (payload = @cone.usdrecursivepayloadsexample@
/// | | | UsdExample_num = 2
/// | | | UsdExample_depth = 1
/// | | | UsdExample_radius = 5.0)
/// | | |
/// | | | geom (reference = @cone.usdrecursivepayloadsexample@)
///
/// Valid metadata field parameters:
/// depth - The number of times to recurse when generating rings of prims
/// num - The number of prims to place in the ring at each level of depth.
/// radius - The radius of the ring around the parent prim which generated
/// prims are placed.
/// height - Vertical distance above the parent where the ring is placed.
/// argDict - A dictionary of values that can specify the above parameters for
/// specifically IDed payloads.
///
class UsdRecursivePayloadsExampleFileFormat : public SdfFileFormat,
public PcpDynamicFileFormatInterface
{
public:
// SdfFileFormat overrides.
bool CanRead(const std::string &file) const override;
bool Read(SdfLayer *layer,
const std::string& resolvedPath,
bool metadataOnly) const override;
// We override Write methods so SdfLayer::ExportToString() etc, work.
// Writing this layer will write out the generated layer contents.
bool WriteToString(const SdfLayer& layer,
std::string* str,
const std::string& comment=std::string()) const override;
bool WriteToStream(const SdfSpecHandle &spec,
std::ostream& out,
size_t indent) const override;
// A required override for generating dynamic arguments that are
// particular to this file format.
void ComposeFieldsForFileFormatArguments(
const std::string& assetPath,
const PcpDynamicFileFormatContext& context,
FileFormatArguments* args,
VtValue *dependencyContextData) const override;
// Another required override for dynamic file arguments to help determine
// which changes may cause prims using this file format to be invalidated.
bool CanFieldChangeAffectFileFormatArguments(
const TfToken& field,
const VtValue& oldValue,
const VtValue& newValue,
const VtValue &dependencyContextData) const override;
protected:
SDF_FILE_FORMAT_FACTORY_ACCESS;
virtual ~UsdRecursivePayloadsExampleFileFormat();
UsdRecursivePayloadsExampleFileFormat();
};
PXR_NAMESPACE_CLOSE_SCOPE
#endif // PXR_EXTRAS_USD_EXAMPLES_USD_RECURSIVE_PAYLOADS_EXAMPLE_FILE_FORMAT_H