Open Search
    CAMorph Manual

    About

    A CAMorph represents a morph of a CAPoseMorphTag. It allows access to the internally stored data and can apply this data to the host object. The class is defined in the lib_ca.h header file.

    Access

    CAMorph elements are stored in a CAPoseMorphTag, see CAPoseMorphTag Manual.

    // This example loops through all morphs of the given
    // CAPoseMorphTag and prints the morph name.
    const Int32 morphCount = poseMorphTag->GetMorphCount();
    for (Int32 i = 0; i < morphCount; ++i)
    {
    CAMorph* const morph = poseMorphTag->GetMorph(i);
    if (morph == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // print morph name
    ApplicationOutput("Morph: " + morph->GetName());
    }
    Py_ssize_t i
    Definition: abstract.h:645
    Definition: lib_ca.h:1475
    String GetName()
    maxon::Int32 Int32
    Definition: ge_sys_math.h:56
    #define MAXON_SOURCE_LOCATION
    Definition: memoryallocationbase.h:67
    #define ApplicationOutput(formatString,...)
    Definition: debugdiagnostics.h:204

    Allocation/Deallocation

    CAMorph elements are created and deleted using the parent CAPoseMorphTag, see CAPoseMorphTag Manual.

    // This example adds a new morph to the given CAPoseMorphTag.
    poseMorphTag->ExitEdit(doc, false);
    CAMorph* const morph = poseMorphTag->AddMorph();
    if (morph == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    morph->SetName("New Morph");
    poseMorphTag->UpdateMorphs();
    void SetName(const String &name)
    const char * doc
    Definition: pyerrors.h:226

    Copy

    The data stored in one CAMorph can be copied from a CAMorph to another CAMorph:

    // This example copies the currently active morph
    // and makes the copy the new active morph.
    poseMorphTag->ExitEdit(doc, false);
    // get active morph
    const Int32 activeIndex = poseMorphTag->GetActiveMorphIndex();
    CAMorph* const activeMorph = poseMorphTag->GetMorph(activeIndex);
    if (activeMorph == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // create new morph
    CAMorph* const morph = poseMorphTag->AddMorph();
    if (morph == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    // copy morph
    morph->CopyFrom(activeMorph, nullptr, CAMORPH_COPY_FLAGS::NONE);
    const String newName = activeMorph->GetName() + " Copy";
    morph->SetName(newName);
    // set new morph as active morph
    const Int32 newIndex = poseMorphTag->GetMorphIndex(morph);
    poseMorphTag->SetActiveMorphIndex(newIndex);
    poseMorphTag->UpdateMorphs();
    Bool CopyFrom(CAMorph *src, AliasTrans *trn, CAMORPH_COPY_FLAGS flags)
    Definition: c4d_string.h:41

    Properties

    The internal data and several properties of a CAMorph can be edited through dedicated functions. But some properties can only be edited through the parent CAPoseMorphTag when the morph is selected. See Properties.

    Name

    Every CAMorph has a name:

    ID

    Every CAMorph has an internal ID:

    Post Morph

    A morph can be applied as a post-deform morph (ID_CA_POSE_MIXING_DEFORMED). If this is the case can be checked with:

    CAMorphNode

    The actual morph data is stored internally in CAMorphNode elements. See CAMorphNode Manual.

    Mode

    To edit or access data stored in a CAMorph one must switch the morph to a certain mode:

    Valid flags are:

    The data modes are:

    // This example accesses the morph data of the
    // first morph of the given CAPoseMorphTag.
    poseMorphTag->ExitEdit(doc, false);
    // get active morph
    const Int32 activeIndex = poseMorphTag->GetActiveMorphIndex();
    CAMorph* const morph = poseMorphTag->GetMorph(activeIndex);
    if (morph == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    CAMorphNode* const mnode = morph->GetFirst();
    if (mnode == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // expand data to access it
    morph->SetMode(doc, poseMorphTag, expandFlags, CAMORPH_MODE::ABS);
    // check stored data
    {
    // access point data
    const Int32 pointCount = mnode->GetPointCount();
    for (Int32 i = 0; i < pointCount; ++i)
    {
    const Vector point = mnode->GetPoint(i);
    }
    }
    // collapse data
    morph->SetMode(doc, poseMorphTag, collapseFlags, CAMORPH_MODE::AUTO);
    poseMorphTag->UpdateMorphs();
    Bool SetMode(BaseDocument *doc, CAPoseMorphTag *tag, CAMORPH_MODE_FLAGS flags, CAMORPH_MODE mode)
    CAMorphNode * GetFirst()
    Definition: lib_ca.h:1072
    CAMORPH_DATA_FLAGS GetInfo() const
    Vector GetPoint(Int32 index) const
    Int32 GetPointCount() const
    static String VectorToString(const Vector32 &v, Int32 nnk=-1)
    Definition: c4d_string.h:573
    @ POINTS
    Points morphing.
    CAMORPH_MODE_FLAGS
    Definition: lib_ca.h:850
    @ ALL
    Expand or collapse all data.
    @ COLLAPSE
    Collapse data. Needs to be passed to collapse the expanded data, for instance after data access.
    @ EXPAND
    Expand data. Needs to be passed before accessing any data.
    @ ABS
    Absolute morph data.
    @ AUTO
    Auto mode. Used to collapse the data automatically into their correct mode.

    Target

    A CAMorph can use an object as a reference:

    // This example creates a new morph and uses
    // the given BaseObject as the target object.
    poseMorphTag->ExitEdit(doc, false);
    // create new morph
    CAMorph* const morph = poseMorphTag->AddMorph();
    if (morph == nullptr)
    return maxon::OutOfMemoryError(MAXON_SOURCE_LOCATION);
    // set given object as target
    morph->SetTarget(poseMorphTag, doc, targetObject);
    // set new morph as active morph
    const Int32 newIndex = poseMorphTag->GetMorphIndex(morph);
    poseMorphTag->SetActiveMorphIndex(newIndex);
    poseMorphTag->UpdateMorphs();
    const Int32 index = poseMorphTag->GetMorphIndex(morph);
    poseMorphTag->SetActiveMorphIndex(index);
    void SetTarget(CAPoseMorphTag *tag, BaseDocument *doc, BaseList2D *bl)
    Py_ssize_t * index
    Definition: abstract.h:374
    #define ConstDescID(...)
    Definition: lib_description.h:594
    Represents a level within a DescID.
    Definition: lib_description.h:298
    @ ID_CA_POSE_MIXING
    Definition: tcaposemorph.h:26
    @ ID_CA_POSE_MIXING_ABS
    Definition: tcaposemorph.h:89

    Strength

    The strength of a CAMorph controls how strongly it is applied to the host object.

    // This example loops through all morphs and sets the strength
    // of the currently active morph to 100%, all other morphs to 0%.
    poseMorphTag->ExitEdit(doc, false);
    // get index of active morph
    const Int32 activeMorphIndex = poseMorphTag->GetActiveMorphIndex();
    // loop through all morphs
    const Int32 morphCount = poseMorphTag->GetMorphCount();
    for (Int32 i = 0; i < morphCount; ++i)
    {
    CAMorph* const morph = poseMorphTag->GetMorph(i);
    if (morph == nullptr)
    return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    // set morph strength
    if (activeMorphIndex != i)
    morph->SetStrength(0.0);
    else
    morph->SetStrength(1.0);
    }
    poseMorphTag->UpdateMorphs(doc);
    void SetStrength(Float strength)

    Object

    The data stored in a CAMorph can be read from the host object and applied back to the host object:

    The flags used to control what data is stored or applied are defined in CAMORPH_DATA_FLAGS. These flags are also used with CAMorphNode::GetInfo(), see CAMorphNode Manual.

    // This example accesses the first (not base pose) morph
    // and applies it to the host object.
    poseMorphTag->ExitEdit(doc, false);
    // get first morph
    CAMorph* const morph = poseMorphTag->GetMorph(1);
    if (morph)
    {
    morph->Apply(doc, poseMorphTag, CAMORPH_DATA_FLAGS::ALL);
    }
    Bool Apply(BaseDocument *doc, CAPoseMorphTag *tag, CAMORPH_DATA_FLAGS flags)
    @ ALL
    All data morphing.

    Further Reading