Implementing Preset Assets

Implement a custom preset asset type wrapping a custom data type to be exposed by the Asset Browser.

Overview

A preset asset type allows users to read and write a custom data type exposed by a plugin into an asset database. Usually such preset asset type implementation is not just bound to a custom data type, but also to a custom GUI which is used to display the custom data in the Attribute Manger of Cinema 4D. Unlike a normal asset type, a preset asset type usually does not implement the method which is invoked when a user double clicks an asset in the Asset Browser. Instead, preset assets rely on drag and drop operations and dedicated GUIs elements being added to their data type GUI for loading and saving a preset asset.

Fig I: Preset assets can be saved and loaded with the buttons in the custom GUI that complements their data type and preset assets of matching type can be dragged into the GUI to load them into it. Preset assets can also generate preview thumbnails that reflect their stored data in the Asset Browser.

Technical Overview

The general logic to implement a preset asset type, is to provide a two layer implementation where the layers communicate with a dedicated data exchange type, the preset arguments PresetLoadArgs and PresetSaveArgs:

  • An external layer which defines a custom data type and GUI, and
  • an asset layer which implements a preset asset type for that data type and its GUI.

The common pattern to implement the external layer, is to implement a iCustomDataType to store the custom data and an iCustomGui to display this data as a parameter in the Attribute Manger. The iCustomGui sends and receives data from the Asset API with the preset arguments PresetLoadArgs and PresetSaveArgs, usually attaching itself or the wrapped data to these arguments, so that the asset type layer can load and store data. The pattern to implement the GUI is to add two buttons for the preset handling: One for loading a preset into the GUI and one for saving a preset. Via iCustomGui::Command these buttons then invoke the Asset API to load or store an asset. Asset drag and drop operations are handled with the DndAsset alias, a tuple containing among other data the dragged AssetDescriptionInterface reference. The drag and drop is handled as any other classic API drag and drop operation in iCustomGui::Message, where an array of DndAsset, the dragged asset(s), is then part of the message data.

The preset asset type implementation must implement a component for the BasePresetAssetInterface interface and one for the BasePresetAssetTypeInterface interface. The first component implements the functionalities that are applicable to singular asset: Creating a new instance with PresetSaveArgs, generating preview images and serializing the asset data into an asset database. The component for the BasePresetAssetTypeInterface interface implements the functionalities that are applicable to all instances of this asset type. Most importantly creating a new preset asset instance, loading, i.e., deserializing, a previously serialized asset from an asset database and handling incoming PresetLoadArgs requests from the Asset API to load an preset into passed the PresetLoadArgs.

Fig II: A simplified overview of implementing a preset asset type. Shown in green is the external layer and in blue the preset asset logic layer. It is the custom GUI implementation which actively sends data to the Asset API when the user wants to save or load a custom data type as an asset.

Related Topics

Articles Asset API Provide content as reusable assets served with the Cinema 4D Asset Browser.
Entity Creation Explains the managed memory environment of the maxon API with interfaces and references.
Published Objects Explains the concept of published objects.
Component Bases

Explains the component system of maxon API classes.

Important API Entities iCustomDataType Provides the base class for a custom data type implementation.
iCustomGui Provides the base class a custom GUI implementation which can be used to display a custom datatype.
CustomDataTypeClass Provides the plugin class for custom data type implementations.
CustomGuiData Provides the plugin class for custom GUI implementations.
AssetTypes Contains the declarations of asset types.
AssetDescriptionInterface Represents an asset over its metadata in an asset repository.
BasePresetAssetInterface Provides the base implementation for the functionalities of a singular preset asset.
BasePresetAssetTypeInterface Provides the base implementation for the functionalities applicable to all preset assets of a specific type.
PresetLoadArgs Provides a helper data structure that is used to exchange incoming preset asset data with the Asset API for preset asset implementations.
PresetSaveArgs Provides a helper data structure that is used to exchange outgoing preset asset data with the Asset API for preset asset implementations.
DndAsset

Provides a helper data structure that is used in asset drag and drop operations.

SDK Plugins Dots Preset Asset Implementation

Showcases the implementation of a custom preset asset type in conjunction with a custom datatype and GUI.

Examples Implement a Preset Asset Type Implement a preset asset and asset type.
Implement a Data Type for a Preset Asset Type Implement a data type wrapped by a preset asset.
Load Assets into a GUI Provides an example pattern for loading preset assets into a iCustomGui.
Save Assets from a GUI Provides an example pattern for creating preset assets from the data attached to a iCustomGui.
Instantiate a Preset Instantiate an implemented preset asset type from its custom data type.
Invoke Asset Implementation Showcases how to access the implementation of an asset type from an asset description.

Examples

Implement a Preset Asset Type

Implements the Dots preset asset type that is targeted by the dots data type and GUI.

The preset asset type implementation must implement a component for the BasePresetAssetInterface interface and one for the BasePresetAssetTypeInterface interface. The first component implements the functionalities that are applicable to singular asset: Creating a new instance with PresetSaveArgs, generating preview images and serializing the asset data into an asset database. The component for the BasePresetAssetTypeInterface interface implements the functionalities that are applicable to all instances of this asset type. Most importantly creating a new preset asset instance, loading, i.e., deserializing a previously serialized asset from an asset database and handling incoming PresetLoadArgs requests from the Asset API to load a preset into the passed PresetLoadArgs.

#ifndef SDK_PRESET_ASSET_TYPE_H__
#define SDK_PRESET_ASSET_TYPE_H__
#include "maxon/apibase.h"
#include "maxon/assets.h"
#include "dots_datatype.h"
// A published object is an object that is globally accessible within a Cinema 4D instance. Search
// for "Published Objects" in the C++ SDK documentation for details on the subject of publishing
// objects.
// The maxon API requires published objects to be declared for the implemented preset asset. They
// primarily act as symbols for the preset asset type and class. A good pattern for the ids is:
//
// "com.mycompany.assettype.myasset"
// "com.mycompany.class.myasset"
// Declare the published object for dots asset type. It is mandatory to publish the objects in
// these exact namespaces so that the Asset API can find them at runtime.
{
MAXON_DECLARATION(BasePresetAssetType, DotsPresetAsset, "net.maxonexample.assettype.dotpreset");
};
// Declare a published object for dots asset type class.
{
Class<BasePresetAsset>, DotsPresetAssetClass, "net.maxonexample.class.dotpreset");
};
// Declare a custom metadata attribute to describe the dot scale of dot asset thumbnails. Defining
// custom metadata attributes is optional. The source-processor will generate the files
// dots_preset_asset1.hxx and dots_preset_asset2.hxx which must be included for this attribute to
// be correctly exposed.
#include "dots_preset_asset1.hxx"
namespace maxon::ASSETMETADATA::DOTSPRESET
{
MAXON_ATTRIBUTE(maxon::Float32, DOT_SCALE, "net.maxonexample.asset.dotpreset.dotscele");
};
#include "dots_preset_asset2.hxx"
// Renders a preview of the passed dots data.
//
// @param[out] canvas The canvas to draw into.
// @param[in] data The dots data to draw.
// @param[in] size The size in pixels of the requested preview thumbnail.
// @param[in] dotScale The size of a dot in relation to the preview size. E.g., 0.1 will mean
// that for a preview size of 100 each dot will be 10 pixels large.
maxon::Result<void> RenderPreview(
GeClipMap* canvas, const DotsData* data, const maxon::Int32 size, const maxon::Float32 dotScale);
// Provides the dots preset asset implementation.
//
// The preset asset implementation handles a single asset. This implementation is only functional
// in cooperation with the corresponding asset type implementation which is declared below as
// DotsPresetAssetTypeImpl. Its key methods are the two Init() methods to instantiate an asset
// in memory from DotsData and from serialized data on disk, the Serialize() method to serialize
// an asset in memory to an asset database, and the GeneratePreview() method to provide
// preview thumbnails for the Asset Browser.
//
// @warning It is important to implement all members for BasePresetAssetInterface, even the ones
// which seemingly serve no purpose as for example DotsPresetAssetImpl::Apply(). If
// these empty implementations are skipped, the solution will compile, but the
// construction of the BasePresetAssetInterface for a DotsPresetAsset will fail at
// runtime, as this component will then not adhere to the BasePresetAssetInterface
// interface signature.
class DotsPresetAssetImpl:
public maxon::Component<DotsPresetAssetImpl, maxon::BasePresetAssetInterface>
{
// This is a BasePresetAssetInterface component which is final. It is always going to be the last
// component in the component list of a BasePresetAssetInterface instance, and therefore its
// methods cannot be overridden by other components.
MAXON_COMPONENT(FINAL, maxon::BasePresetAssetClass);
public:
// Called when the user invokes the asset in the Asset Browser.
//
// Usually not implemented for preset assets as applying them is handled with drag and drop
// operations or the "Load Preset ..." button in the GUI of the data type.
// Convert an asset from the old Content Browser format into an Asset Browser asset.
//
// Not implemented in this example.
MAXON_METHOD maxon::Result<void> ConvertFromLegacyBrowser(
Int32 pluginId, const maxon::Block<const Char>& memBlock, const BaseContainer& settings,
const String& name, maxon::DataDictionary& metaProperties, maxon::AddAssetMetaData& addMetaData,
maxon::AddAssetDepencendyStruct& addDependencyStruct,
// Initializes an asset instance from preset data.
//
// This form of intilization is invoked when the user presses the "Save Preset ..." button in
// the custom gui. It will invoke AssetCreationInterface::SaveBrowserPreset() which then will
// invoke CreateInit() for the implemented asset interface, causing this method to be called.
//
// @param[in] sourceData The data to be wrapped, a pointer to an instance of DotsData.
maxon::Result<void> Init(const maxon::PresetSaveArgs& sourceData);
// Initializes an asset instance from serialized data.
//
// This form of intilization is invoked when a repository must deserialize data that previously
// has been serialized with DotsPresetAssetImpl::Serialize(). The structure of the data found
// at #presetUrl depends on what is being carried out in Serialize().
//
// @param[in] asset The asset description of the asset to deserialize the data for.
// @param[in] presetUrl The location of the data to deserialize.
maxon::Result<void> Init(const maxon::AssetDescription& asset, const maxon::Url& presetUrl);
// Generates a preview image for the asset instance.
//
// Called by the Asset Browser to populate its asset preview tiles.
//
// @param[in] previewSize The size of a tile in the Asset Browser to render for.
// @param[in] progressRef An interface to communicate progress.
// @param[in] progressIndex The progress index.
//
// @return The url of the generated preview image.
MAXON_METHOD maxon::Result<maxon::Url> GeneratePreview(maxon::Int previewSize,
const maxon::ProgressRef& progressRef, maxon::Int progressIndex) const;
// Returns the asset type for this asset instance.
//
// Returns maxon::AssetTypes::DotsPresetAsset() as published at the top of this file.
MAXON_METHOD const maxon::AssetType& GetType() const;
// Called to serialize the asset instance to an output stream.
//
// Called by an asset repository when an asset must be serialized to a database. Serialized must
// only be the custom data type data, not the asset metadata stored in the AssetDescription and
// AssetMetadata which are handled by the Asset API.
//
// @param[out] outputStream The stream to write the serialized data to.
MAXON_METHOD maxon::Result<void> Serialize(const maxon::OutputStreamRef& outputStream) const;
// Accesses the internal DotsData attached to the asset instance.
//
// This is a member of the specific pattern shown in this example and not a member of
// BasePresetAssetInterface.
const DotsData* GetCustomData() const;
private:
// The custom data attached to the preset asset instance, in this case an instance of DotsData.
// Neither the naming of the field nor its existence is formally required, but the implementation
// pattern shown here does store the primary data attached to an asset instance in this way.
AutoAlloc<DotsData> _customData;
};
// Provides the dots preset asset type implementation.
//
// The preset asset type implementation handles operations applicable to all assets of this type.
// This implementation is only functional in cooperation with the corresponding singular asset
// implementation which is declared above as DotsPresetAssetImpl.
//
// Its most important methods are CreateNewPresetSettings() to create a new dots preset asset
// instance and the Load() method to handle incoming calls to the asset API to unpack preset asset
// data into an external entity; a DotsGui in this case.
//
// @warning Just as for DotsPresetAssetImpl it is important to implement all members for
// BasePresetAssetTypeInterface.
//
// @warning It is important to return the asset type id returned by GetId() in exactly the manner
// which is shown here with a maxon::Id reference attched to the DotsPresetAssetTypeImpl
// instance.
class DotsPresetAssetTypeImpl:
public maxon::Component<DotsPresetAssetTypeImpl, maxon::BasePresetAssetTypeInterface>
{
// This is a component for a BasePresetAssetTypeInterface.
MAXON_COMPONENT(NORMAL, maxon::AssetTypeBasePresetClass);
public:
// The type identifier for the implemented asset type.
const maxon::Id _typeId = maxon::AssetTypes::DotsPresetAsset.GetId();
// Creates a new asset instance from the raw data which are wrapped by the asset.
//
// The passed arguments contain an PresetSaveArgs instance and this implementation then calls
// the DotsPresetAssetImpl::Init() overload which accepts PresetSaveArgs to create an asset
// instance.
//
// @param[in] args The raw data to create a new asset instance for.
MAXON_METHOD maxon::Result<void> CreateNewPresetSettings(
// Returns the the asset type this implementation is representing.
MAXON_METHOD const maxon::DataType& GetAssetDataType() const;
// Returns the identifier of the asset type.
//
// As explained in the class description, it is important to follow the exact pattern shown here,
// as otherwise the asset type will fail when assets must be saved and loaded.
MAXON_METHOD const maxon::Id& GetId() const;
// Returns the asset type alias as shown in the Asset Browser.
MAXON_METHOD maxon::String GetName() const;
// Used to deserialize an asset from an asset database.
//
// This implementation ignores most of its input arguments and wraps around the
// DotsPresetAssetImpl::Init() method which accepts an asset description and url to instantiate
// an asset.
//
// @param[in] repo The repository which is requesting the loading.
// @param[in] assetDescription The asset description for the to be loaded asset.
// @param[in] url The location of the primary data of the asset to deserialize.
// @param[in] updateLinks Private.
const maxon::AssetRepositoryRef& repo, const maxon::AssetDescription& assetDescription,
const maxon::Url& url, maxon::Bool* updateLinks) const;
// Handles incoming requests from the outside of the Asset API to load an preset asset into
// a target passed with the PresetLoadArgs.
//
// @param[in] preset The data to load, a DotsPresetAsset in this case.
// @param[in, out] target The entity to load into, a DotsGui in this case.
const maxon::BasePresetAsset& preset, const maxon::PresetLoadArgs& target) const;
};
#endif // SDK_PRESET_ASSET_TYPE_H__
@ Load
Definition: Python-ast.h:20
PyObject * args
Definition: abstract.h:159
const char const char * name
Definition: abstract.h:195
Definition: ge_autoptr.h:37
Definition: c4d_basecontainer.h:47
Definition: lib_clipmap.h:148
Definition: c4d_string.h:39
Helper class to pass additional data into asset creation functions.
Definition: base_preset_asset.h:101
Definition: block.h:423
Definition: objectbase.h:2651
Helper class to create a new preset asset.
Definition: base_preset_asset.h:447
Definition: datatypebase.h:772
Definition: apibaseid.h:253
Helper class to pass arguments for loading presets into asset/preset implementations....
Definition: base_preset_asset.h:155
Helper class to pass arguments for saving presets into asset/preset implementations....
Definition: base_preset_asset.h:197
Helper structure to store resolved asset dependencies.
Definition: base_preset_asset.h:54
Definition: string.h:1235
Definition: url.h:952
Py_ssize_t size
Definition: bytesobject.h:86
maxon::Int32 Int32
Definition: ge_sys_math.h:60
Int64 Int
signed 32/64 bit int, size depends on the platform
Definition: apibase.h:188
bool Bool
boolean type, possible values are only false/true, 8 bit
Definition: apibase.h:181
int32_t Int32
32 bit signed integer datatype.
Definition: apibase.h:176
float Float32
32 bit floating point value (float)
Definition: apibase.h:182
@ NORMAL
Samples the surface as the user moves over it the SculptObject and returns a new hit point and normal...
#define MAXON_COMPONENT(KIND,...)
Definition: objectbase.h:2212
#define MAXON_METHOD
Definition: interfacebase.h:1001
MAXON_ATTRIBUTE(AssetCommandQueryStateDelegate, CommandQueryState, "net.maxon.asset.command.metadata.querystate")
Definition: asset_command.h:246
MAXON_DECLARATION(AssetType, Command, "net.maxon.assettype.command")
AssetTypes::Command allows to store commands within in a repository.
Definition: base_preset_asset.h:406
MAXON_DECLARATION(Class< BasePresetAsset >, CameraSensorPresetClass, "net.maxon.class.asset.preset.camerasensor")

Implement a Data Type for a Preset Asset Type

Implements a custom datatype with a custom GUI that accommodates a matching preset asset type.

The core elements of this implementation are DotsData and DotsGui. DotsData implements the custom data type and DotsGui a dialog that is used to render that data type as a parameter in the Attribute Manger.

DotsGui is a iCustomGui which inherits from GeDialog and attaches three gadgets to itself.

  1. A DotsUserArea instance, which renders a preview of the DotsData attached to the DotsGui.
  2. A "Load Preset ..." button to load a preset asset of type DotsPresetAsset with the help of a popup dialog.
  3. A "Save Preset ..." button to save the DotsData shown in the DotsGui as a DotsPresetAsset which is exposed by the Asset Browser.

Both the DotsData and DotsGui implementation are exposed as plugin interfaces to the classic API, handling the data type and its GUI. For DotsData it is DotsDataClass and for DotsGui it is DotsGuiData. These types are then used to register the data type and its GUI as plugins with Cinema 4D.

The example also showcases the bindings of a custom GUI and datatype to the Asset API, so that users can save and load preset assets from within the GUI of the data type. This is primarily realized with the two buttons in the custom GUI, the "Load Preset..." and "Save Preset..." buttons. In DotsGui::Command() the click messages for these buttons are then handled and DotsData is being sent to or retrieved from the Asset API DotsPresetAsset type implementation. Asset drag and drop events are being handled in a similar fashion in DotsGui::Message().

#ifndef CUSTOMDATA_CUSTOMGUI_H__
#define CUSTOMDATA_CUSTOMGUI_H__
#include "c4d_baselist.h"
#include "c4d_gui.h"
#include "c4d_symbols.h"
#include "maxon/assets.h"
// The size of a DotsUserArea drawing canvas.
const maxon::Int32 g_dots_canvas_size = 200;
// Forward declaration for the DotsData friend access modifier.
class DotsDataClass;
// Provides a data structure to store an array of points on a fixed size canvas.
class DotsData : public iCustomDataType<DotsData>
{
friend class DotsDataClass;
public:
DotsData() {}
~DotsData() {}
maxon::Int32 canvasSize = g_dots_canvas_size;
// Copies the data from this instance to #dest.
//
// @param[in] dest The target to copy to.
//
// @return The number of points copied.
maxon::Result<maxon::Int32> CopyTo(DotsData& dest);
};
// Represents a gadget which can be added to dialogs that renders an instance of DotsData.
//
// Used by DotsGui and does not contain any Asset API relevant code.
class DotsUserArea : public GeUserArea
{
public:
DotsUserArea();
virtual ~DotsUserArea();
virtual Bool Init();
virtual Bool InitValues();
virtual Bool GetMinSize(Int32& w, Int32& h);
virtual void DrawMsg(Int32 x1, Int32 y1, Int32 x2, Int32 y2, const BaseContainer& msg);
virtual Bool InputEvent(const BaseContainer& msg);
DotsData* _data;
};
// Represents the custom GUI interface that handles a DotsData parameter in the Attribute Manager.
//
// This contains all the code handling the Asset API dots preset asset type implementation from the
// classic API side, this custom GUI. The methods containing code relevant for the Asset API are
// DotsGui::Command(), DotsGui::Message(), DotsGui::LoadAsset(), and DotsGui::SaveAsset().
class DotsGui : public iCustomGui
{
private:
Bool _tristate;
DotsData _data;
DotsUserArea _dotsUserArea;
public:
DotsGui(const BaseContainer &settings, CUSTOMGUIPLUGIN *plugin);
virtual Bool CreateLayout();
virtual Bool InitValues();
virtual Bool SetData(const TriState<GeData>& tristate);
// Receives dialog gadget events for the custom GUI.
//
// Used in this example to handle the "Load Asset ..." and "Save Asset ..." buttons. Sends and
// receives data with the Asset API by sending itself as SavePresetArgs and LoadPresetArgs,
// to the DotsPresetAsset type implementation to load or save DotsData into this DotsGui
// instance.
//
// @param[in] id The dialog gadget which received a user interaction.
// @param[in] msg The event data.
//
// @return If the event was consumed or not.
virtual Bool Command(Int32 id, const BaseContainer &msg);
// Receives messages sent to the iCustomGui dialog.
//
// Used in this example to handle asset drag and drop events onto the custom GUI. Receives data
// from the Asset API in form of DndAsset tuples and then sends data to the Asset API to load
// unpack the DotsData wrapped by the dragged asset into this DotsGui instance.
//
// @param[in] msg The message event and event data.
// @param[in, out] result The message data.
//
// @return Depends on the type of message.
// Handles loading assets into the GUI.
//
// Both asset drag and drop events and "Load Asset..." button clicks will use this method. This
// method is not an overload of iCustomGui and things must not be implemented in this way, but it
// is the approach chosen here to abstract the process of asset loading.
//
// @param[in] assetDescription The asset to load into the GUI.
maxon::Result<void> LoadAsset(const maxon::AssetDescription& assetDescription);
// Handles saving assets from the current state of the GUI. This method is not an overload of
//
// Saved will be _data of the GUI instance. This method is not an overload of iCustomGui and
// things must not be implemented in this way, but it is the approach chosen here to abstract
// the process of asset saving.
maxon::Result<void> SaveAsset();
};
static Int32 g_stringtable[] = { PID_CUSTOMDATATYPE_DOTS };
// Provides the plugin interface for the custom GUI.
//
// This does not contain any code relevant for the Asset API.
class DotsGuiData : public CustomGuiData
{
public:
virtual Int32 GetId();
virtual CDialog* Alloc(const BaseContainer& settings);
virtual void Free(CDialog* dlg, void* userdata);
virtual const Char* GetResourceSym();
};
// Provides the plugin interface for the custom datatype.
//
// This does not contain any code relevant for the Asset API.
class DotsDataClass : public CustomDataTypeClass
{
public:
virtual Int32 GetId();
virtual void FreeData(CustomDataType* data);
virtual Bool CopyData(const CustomDataType* src, CustomDataType* dst, AliasTrans* aliastrans);
virtual Int32 Compare(const CustomDataType* d1, const CustomDataType* d2);
virtual Bool WriteData(const CustomDataType* t_d, HyperFile* hf);
virtual const Char* GetResourceSym();
virtual void GetDefaultProperties(BaseContainer& data);
};
// Registers the dots datatype and GUI
Bool RegisterDotsDataAndGui();
#endif // CUSTOMDATA_CUSTOMGUI_H__
#define INSTANCEOF(X, Y)
Definition: c4d_baselist.h:38
Definition: c4d_baselist.h:3067
Definition: c4d_customdatatype.h:91
virtual void FreeData(CustomDataType *data)=0
virtual Bool CopyData(const CustomDataType *src, CustomDataType *dest, AliasTrans *aliastrans)=0
virtual void GetDefaultProperties(BaseContainer &data)
virtual Bool WriteData(const CustomDataType *d, HyperFile *hf)=0
virtual const Char * GetResourceSym()=0
virtual Int32 GetId()=0
virtual Int32 Compare(const CustomDataType *d1, const CustomDataType *d2)=0
virtual CustomDataType * AllocData()=0
virtual Bool ReadData(CustomDataType *d, HyperFile *hf, Int32 level)=0
Definition: c4d_customguidata.h:139
virtual const Char * GetResourceSym()=0
virtual Int32 GetId()=0
virtual CustomProperty * GetProperties()
virtual void Free(CDialog *dlg, void *userdata)=0
virtual CDialog * Alloc(const BaseContainer &settings)=0
virtual Int32 GetResourceDataType(Int32 *&table)
virtual Bool InitValues()
virtual Bool Command(Int32 id, const BaseContainer &msg)
virtual Bool CreateLayout()
Definition: c4d_gui.h:171
virtual Bool InitValues()
virtual Bool Init()
virtual void DrawMsg(Int32 x1, Int32 y1, Int32 x2, Int32 y2, const BaseContainer &msg)
virtual Bool InputEvent(const BaseContainer &msg)
virtual Bool GetMinSize(Int32 &w, Int32 &h)
Definition: c4d_gui.h:3006
virtual Int32 Message(const BaseContainer &msg, BaseContainer &result)
virtual TriState< GeData > GetData()
virtual Bool SetData(const TriState< GeData > &tristate)
Definition: basearray.h:412
PyObject PyObject * result
Definition: abstract.h:43
PyObject * src
Definition: abstract.h:305
Py_ssize_t PyObject * table
Definition: unicodeobject.h:944
maxon::Char Char
Definition: ge_sys_math.h:56
maxon::Bool Bool
Definition: ge_sys_math.h:55
PyObject PyObject PyObject int level
Definition: import.h:58
const char const char * msg
Definition: object.h:438
Base class for custom data types.
Definition: c4d_customdatatype.h:51
Definition: c4d_customguidata.h:114
Definition: c4d_customdatatype.h:70

Load Assets into a GUI

Provides an example pattern for loading preset assets into a iCustomGui.

maxon::Result<void> DotsGui::LoadAsset(const maxon::AssetDescription& assetDescription)
{
// Sort out any asset descriptions that are not of type DotsPresetAsset.
if (!assetDescription)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Invalid asset description."_s);
if (assetDescription.GetTypeId() != maxon::AssetTypes::DotsPresetAsset().GetId())
return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION, "Received unexpected asset type."_s);
// Load the asset and attempt to cast it to a BasePresetAsset.
maxon::Asset asset = assetDescription.Load() iferr_return;
maxon::BasePresetAsset preset = maxon::Cast<maxon::BasePresetAsset>(asset);
if (!preset)
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Failed to cast asset to preset asset."_s);
// Prepare the PresetLoadArgs to send to the DotsPresetAssetImpl to load the data. The arguments
// will point to #this GUI, so that the DotsPresetAssetImpl can load the asset into it.
maxon::PresetLoadArgs dataContainer;
dataContainer.SetPointer(this) iferr_return;
// Call the dots asset type implementation to load #preset into #this GUI.
if (!maxon::AssetTypes::DotsPresetAsset().LoadPreset(preset, dataContainer))
return maxon::UnexpectedError(MAXON_SOURCE_LOCATION, "Could not load asset."_s);
return maxon::OK;
}

Save Assets from a GUI

Provides an example pattern for creating preset assets from the data attached to a iCustomGui.

maxon::Result<void> DotsGui::SaveAsset()
{
// Create an instance PresetSaveArgs and point to _data, the instance of DotsData attached to this
// GUI, in it.
maxon::PresetSaveArgs data(&_data, 0);
// The strings for the asset type name and asset name. #SaveBrowserPreset will allow the user to
// modify the asset name.
const maxon::String typeName = maxon::AssetTypes::DotsPresetAsset().GetName();
const maxon::String assetName("Dots Preset");
// Call #AssetCreationInterface::SaveBrowserPreset for the type #DotsPresetAsset and the prepared
// PresetSaveArgs. It will cause the DotsPresetAssetTypeImpl to be called to save the asset with
// the given PresetSaveArgs #data wrapping the instance of DotsData of this GUI.
maxon::AssetCreationInterface::SaveBrowserPreset(maxon::AssetTypes::DotsPresetAsset(),
data, typeName, assetName, false, false, false) iferr_return;
return maxon::OK;
}

Instantiate a Preset

Demonstrates how to instantiate a preset asset with its data type.

How a preset asset can be instantiated from their targeted data type depends on the implementation of the preset asset. The pattern shown here applies to the dots preset asset example and some native preset asset types of Cinema 4D, but there is no guarantee that all preset asset types directly wrap their data type in the PresetSaveArgs.

maxon::Result<maxon::AssetDescription> InstantiateDotsPresetAsset()
{
// Allocate the data.
DotsData dotsData = DotsData();
// Init a pseudo random generator and add ten random points to the DotsData.
random.Init(static_cast<maxon::Int32>(maxon::UniversalDateTime::GetNow().GetUnixTimestamp()));
for (maxon::Int32 i = 0; i < 10; i++)
{
const maxon::Float32 x = random.Get01() * maxon::Float32(dotsData.canvasSize);
const maxon::Float32 y = random.Get01() * maxon::Float32(dotsData.canvasSize);
dotsData.points.Append(maxon::Vector(x, y, 0)) iferr_return;
}
// Pack the DotsData into a PresetSaveArgs. The type of data that must be packed depends on the
// Preset Asset type implementation.
maxon::PresetSaveArgs data(&dotsData, 0);
const maxon::String typeName = maxon::AssetTypes::DotsPresetAsset().GetName();
const maxon::String name ("Manually Instantiated Dots Preset");
// Save the data as a preset asset.
maxon::AssetDescription asset = maxon::AssetCreationInterface::SaveBrowserPreset(
maxon::AssetTypes::DotsPresetAsset(), data, typeName, name, false, false, false) iferr_return;
return std::move(asset);
}
Definition: lib_math.h:19
FLOAT Get01()
Returns the next random value in the range of [0..1].
static UniversalDateTime GetNow()
PyObject * x
Definition: bytesobject.h:38
Definition: apibase.h:541

Invoke Asset Implementation

Showcases how to access the implementation of an asset type from an asset description.

An asset thumbnail can be updated with AddPreviewRenderAsset in a more convenient fashion. This example demonstrates how to load the asset interface from an asset description and then invoke one of the implementations of its components. It is an example case for what has been lined out in Asset Types as the rare case of having to invoke methods of an maxon::AssetInterface instance for an asset directly.

The The Dots Preset Asset Type makes its preview thumbnails dependent on a custom meta data attribute called DOTS_SCALE. The example showcases how to write that attribute and how to manually update the preview image by calling the dots preset asset implementation.

maxon::Result<void> UpdatePreviewThumbnail(
maxon::AssetDescription& assetDescription, maxon::Float32 difference)
{
// Bail when an asset description has been passed that is not for a dots preset asset.
if (assetDescription.GetTypeId() != maxon::AssetTypes::DotsPresetAsset().GetId())
return maxon::IllegalArgumentError(
MAXON_SOURCE_LOCATION, "Passed asset is not of type 'DotsPresetAsset'"_s);
// Get the asset metadata and the existing or default entry of 0.025F for the dot scale. This
// custom metadata attribute has been defined in the dots preset asset implementation and will
// only be carried by that asset type.
maxon::AssetMetaData metadata = assetDescription.GetMetaData();
maxon::Float32 oldValue = metadata.Get(
maxon::ASSETMETADATA::DOTSPRESET::DOT_SCALE, 0.025F) iferr_return;
// The new value clamped to the interval [0.025, 0.1].
maxon::Float32 newValue = maxon::ClampValue(oldValue + difference, 0.025F, 0.1F);
// Write the new value as a persistent value, i.e., a value that will be serialized.
assetDescription.StoreMetaData(maxon::ASSETMETADATA::DOTSPRESET::DOT_SCALE, newValue,
// Get the asset interface for the asset description and cast it to a BasePresetAsset.
maxon::Asset asset = assetDescription.Load() iferr_return;
maxon::BasePresetAsset presetAsset = maxon::Cast<maxon::BasePresetAsset>(asset);
if (!presetAsset)
return maxon::UnexpectedError(
MAXON_SOURCE_LOCATION, "Could not access asset implementation."_s);
// Get Asset Browser preferences and the thumbnail width within them.
CID_ASSET_BROWSER_PREFERENCES);
const maxon::Int32 BROWSER_PREVIEW_WIDTH = 6;
bc->GetInt32(BROWSER_PREVIEW_WIDTH, 512), 128, 1024);
// The DotsPresetAssetImpl does not make use of the passed ProgressInterface as most preset
// assets do, due to to the negligible rendering times. If it would, a fully initialized
// ProgressInterface reference must be defined here instead of a dummy reference.
maxon::ProgressRef dummy;
// Call the DotsPresetAssetImpl to generate the preview and store new preview url. The fact
// that we can do this with the BasePresetAssetInterface reference #presetAsset is due to the
// component system of the maxon API. The BasePresetAssetInterface referenced by #presetAsset
// will carry the DotsPresetAssetImpl component which has been defined in the dots preset asset
// implementation. It will take over with its method of the same name when GeneratePreview() is
// being called. So, we are in fact calling here DotsPresetAssetImpl::GeneratePreview().
maxon::Url newPreviewUrl = presetAsset.GeneratePreview(previewWidth, dummy, 0) iferr_return;
if (newPreviewUrl.IsEmpty())
return maxon::UnexpectedError(
MAXON_SOURCE_LOCATION, "Dots preset asset thumbnail rendering failed."_s);
// Clear out the old preview cache for static previews, as the dots preset type only does
// provide such preview thumbnails.
maxon::Url oldPreviewUrl = metadata.Get(
maxon::ASSETMETADATA::ASSET_PREVIEWIMAGEURL, maxon::Url()) iferr_return;
if (oldPreviewUrl.IsPopulated())
{
assetDescription.StoreUrlMetaData(maxon::ASSETMETADATA::ASSET_PREVIEWIMAGEURL,
}
// Update the asset metadata for the new preview url.
assetDescription.StoreUrlMetaData(
maxon::ASSETMETADATA::ASSET_PREVIEWIMAGEURL, newPreviewUrl,
maxon::DataDictionary metaProperties = metadata.Get(
maxon::ASSETMETADATA::MetaProperties, maxon::DataDictionary()) iferr_return;
metaProperties.Set(maxon::ASSET::METAPROPERTIES::BASE::AUTOMATICPREVIEW, true) iferr_return;
assetDescription.StoreMetaData(maxon::ASSETMETADATA::MetaProperties,
return maxon::OK;
}
PERSISTENT
The meta data is persistent.
Definition: assets.h:2
BaseContainer * GetWorldContainerInstance()
Int32 GetInt32(Int32 id, Int32 preset=0) const
Definition: c4d_basecontainer.h:303
BaseContainer * GetContainerInstance(Int32 id)
Definition: c4d_basecontainer.h:425
@ PERSISTENT
The meta data is persistent.
static MAXON_METHOD Result< void > InvalidateCache(const Url &url)
Result< typename std::conditional< STD_IS_REPLACEMENT(void, T), typename IsFidClass< KEY >::type, T >::type > Get(KEY &&key) const
Definition: url.h:1012
MAXON_ATTRIBUTE_FORCE_INLINE X ClampValue(X value, X lowerLimit, X upperLimit)
Clips a value against a lower and upper limit. The new value is returned.
Definition: apibasemath.h:358