[Closed] (C++) GetValue
My goal is to write all subanim values of an object to a file. So far I can get values from the controller assigned to a subanim like this:
void SaveSubAnims(Animatable* subAnim)
{
for (size_t i = 0; i < subAnim->NumSubs(); i++)
{
Animatable* childSubAnim = subAnim->SubAnim(i);
if (childSubAnim)
{
TimeValue time = GetCOREInterface()->GetTime();
Control* controller = (Control*)subAnim->GetInterface(I_CONTROL);
if (controller)
{
switch (controller->SuperClassID())
{
case CTRL_FLOAT_CLASS_ID:
{
float val;
controller->GetValue(time, &val, CTRL_ABSOLUTE);
// Writing val to the text file ...
break;
}
// Checking other Cases ...
}
}
}
SaveSubAnims(childSubAnim);
}
}
But, How we can get value from a parameter which doesn’t have any controller assigned? for example Radius?
you need the paramblock(s) –> GetParamBlockByID(…)
and then you need the paramid of the radius
following will dump infos about every param in a pblock, no need for controllers
//-----------------------------------------------
void dumpParamBlocks(Animatable* anim, TimeValue t, const std::wstring& fileName)
{
if(nullptr != anim)
{
FILE* f= _tfopen(fileName.c_str(), _M("w"));
int i, nBlocks = anim->NumParamBlocks();
for(i=0; i<nBlocks; ++i)
{
IParamBlock2* pBlock = anim->GetParamBlock(i);
if(nullptr != pBlock)
{
int id, nParams = pBlock->NumParams();
for(id=0; id<nParams; ++id)
{
ParamID pid = pBlock->IndextoID(id);
ParamDef pDef = pBlock->GetParamDef(pid);
if(pDef.size > 0)
{
std::wstring type = _M("<unknown>");
std::wstring value = _M("<unknown>");
switch(pDef.type)
{
case TYPE_FLOAT: type = _M("TYPE_FLOAT"); value = std::to_wstring(pBlock->GetFloat(pid, t)); break;
case TYPE_INT: type = _M("TYPE_INT"); value = std::to_wstring(pBlock->GetInt(pid, t)); break;
case TYPE_BOOL: type = _M("TYPE_BOOL"); value = (pBlock->GetInt(pid, t) != 0) ? _M("true") : _T("false"); break;
// more param-types....
default:
break;
}
MSTR animatable = (pDef.flags & P_ANIMATABLE) ? _M("true") : _M("false");
if(nullptr != pDef.int_name)
_ftprintf(f, _M("pblock: %d, id=%d, name: %s, type: %s, Anim: %s, value: %s\n"), i, pid, pDef.int_name, type.c_str(), animatable.data(), value.c_str());
}
}
}
}
fclose(f);
}
}
Thank you for your reply, this is my test result:
pblock: 0, id=0, name: radius, type: <unknown>, Anim: true, value: <unknown>
pblock: 0, id=1, name: segs, type: TYPE_INT, Anim: true, value: 8
pblock: 0, id=2, name: smooth, type: TYPE_BOOL, Anim: true, value: true
pblock: 0, id=3, name: , type: TYPE_INT, Anim: false, value: -1
pblock: 0, id=4, name: body, type: TYPE_BOOL, Anim: true, value: true
pblock: 0, id=5, name: handle, type: TYPE_BOOL, Anim: true, value: true
pblock: 0, id=6, name: spout, type: TYPE_BOOL, Anim: true, value: true
pblock: 0, id=7, name: lid, type: TYPE_BOOL, Anim: true, value: true
pblock: 0, id=8, name: mapCoords, type: TYPE_BOOL, Anim: false, value: true
Radius should be float right?
radius could be TYPE_WORLD
win32 ui is using TYPE_WORLD, qt it will be TYPE_FLOAT, but need to check
paramID=3 has a blank name, that’s a retired param in teapot
custom attribs should be possible, but never used them
My question is what part of the animation graph we should save?
SubAnims?
Controllers?
ParameterBlocks?
Custom Attributes?
How many of this classes we have?
this should handle the CA’s
ICustAttribContainer* cc = anim->GetCustAttribContainer();
if(cc)
{
int num_attribs = cc->GetNumCustAttribs();
for (int i = 0; i < num_attribs; ++i )
{
CustAttrib *ca = cc->GetCustAttrib(i);
if(ca)
{
IParamBlock2* pb = ca->GetParamBlock(0);
if(pb)
{
//repeat as above
}
}
}
}
though something is nagging at the back of my mind about an odd quirk of scripted CA’s and scripted plugins parameter blocks, It will probably come back to me.
This is my test to save all CustomAttributes, ParameterBlocks and controllers:
#include <QtXml>
#include <QFile>
#include <QTextStream>
#include "MAX.H"
#include <maxscript/maxscript.h>
#include "ICustAttribContainer.h"
#include "custattrib.h"
void SaveParamBlock(IParamBlock2* paramBlock, QDomElement element,TimeValue time, QString subAnimType)
{
int numParams = paramBlock->NumParams();
for (size_t i = 0; i < numParams; i++)
{
int paramID = paramBlock->IndextoID(i);
ParamDef paramDef = paramBlock->GetParamDef(paramID);
if (paramDef.size > 0)
{
QDomElement childElement = element.ownerDocument().createElement("SubAnim"); element.appendChild(childElement);
childElement.setAttribute("SubAnimType", subAnimType);
childElement.setAttribute("Name", QString::fromStdWString(paramDef.int_name));
switch (paramDef.type)
{
case TYPE_FLOAT:
case TYPE_WORLD:
case TYPE_ANGLE:
case TYPE_FLOAT_BR:
case TYPE_WORLD_BR:
case TYPE_ANGLE_BR:
case TYPE_FLOAT_BP:
case TYPE_WORLD_BP:
case TYPE_ANGLE_BP:
childElement.setAttribute("Value", paramBlock->GetFloat(paramID, time)); break;
case TYPE_INT:
case TYPE_BOOL:
case TYPE_bool:
case TYPE_TIMEVALUE:
case TYPE_INDEX:
case TYPE_ENUM:
case TYPE_INT_BR:
case TYPE_BOOL_BR:
case TYPE_bool_BR:
case TYPE_TIMEVALUE_BR:
case TYPE_INDEX_BR:
case TYPE_ENUM_BR:
case TYPE_INT_BP:
case TYPE_BOOL_BP:
case TYPE_bool_BP:
case TYPE_TIMEVALUE_BP:
case TYPE_INDEX_BP:
case TYPE_ENUM_BP:
childElement.setAttribute("Value", paramBlock->GetInt(paramID, time)); break;
case TYPE_DWORD:
case TYPE_DWORD_BR:
case TYPE_DWORD_BP:
childElement.setAttribute("Value", QString::fromStdWString(paramBlock->GetStr(paramID, time))); break;
default:
break;
}
}
}
}
void SaveSubAnims(Animatable* subAnim, QDomElement element,TimeValue time)
{
if (subAnim)
{
ICustAttribContainer* custAttribContainer = subAnim->GetCustAttribContainer();
if (custAttribContainer)
{
int numCustAttribs = custAttribContainer->GetNumCustAttribs();
for (int i = 0; i < numCustAttribs; ++i)
{
CustAttrib* custAttrib = custAttribContainer->GetCustAttrib(i);
if (custAttrib)
{
IParamBlock2* paramBlock = custAttrib->GetParamBlock(0);
if (paramBlock)
{
SaveParamBlock(paramBlock, element,time,"CustAttrib");
}
}
}
}
int numSubs = subAnim->NumSubs();
for (size_t i = 0; i < numSubs; i++)
{
Animatable* childSubAnim = subAnim->SubAnim(i);
QDomElement childElement = element.ownerDocument().createElement("SubAnim"); element.appendChild(childElement);
childElement.setAttribute("Name", subAnim->SubAnimName(i));
IParamBlock2* paramBlock = subAnim->GetParamBlock(0);
if (paramBlock)
{
SaveParamBlock(paramBlock, childElement,time,"Param");
}
else
{
if (childSubAnim)
{
Control* childControl = (Control*)childSubAnim->GetInterface(I_CONTROL);
if (childControl)
{
childElement.setAttribute("SubAnimType", "Controller");
switch (childControl->SuperClassID())
{
case CTRL_FLOAT_CLASS_ID:
{
float val;
childControl->GetValue(time, &val, CTRL_ABSOLUTE);
childElement.setAttribute("Value", val);
break;
}
// Checking other Cases ...
}
}
}
SaveSubAnims(childSubAnim, childElement,time);
}
}
}
}
void SavePose()
{
INode* node = GetCOREInterface()->GetSelNode(0);
TimeValue time = GetCOREInterface()->GetTime();
if (node == nullptr) return;
QFile xmlFile("C:/Test/Pose.xml");
if (xmlFile.open(QFile::WriteOnly | QFile::Text))
{
QTextStream textStream(&xmlFile);
qSetGlobalQHashSeed(0);
QDomDocument document;
QDomElement documentElement = document.createElement("DocumentElement");document.appendChild(documentElement);
QDomElement nodesElement = document.createElement("Nodes");documentElement.appendChild(nodesElement);
QDomElement nodeElement = document.createElement("Node");nodesElement.appendChild(nodeElement);
nodeElement.setAttribute("Name",QString::fromStdWString(node->GetName()));
SaveSubAnims(node, nodeElement, time);
textStream << document.toString();
xmlFile.close();
qSetGlobalQHashSeed(-1);
}
else
{
xmlFile.close();
}
}
Do you think it will cover all situations?
3dsMax 2022 (Qt)
Qt shouldn’t be a problem
its also about paramblocks
only the controltype in paramDef is win32 only