-
注册
当创建一个新的操作符(节点),从本质上说是你在一个给定网络类型的操作符表中添加了新的条目,表格中各个入口是一个
OP_Operator类的对象,主要是为了在新类型中创建节点,定义houdini需求的每一件事。这包括:
- 内部的操作符名称(在操作符表中一定是唯一的)
- 标签——一个更易识别的操作符名称(for ui)
- 一个构建此类型构造节点的类制造函数
- 一个PRM_Template对象的的数组——定义这个操作符的参数
- 需求输入的最小数目
- 需求输入的最大数目
- 一个被操作符使用的任意局部变量数组
- 添加标记(比如:它是否产生新的数据:OP_FLAG_GENERATOR)
为了创建一个新的操作符,你自定义DSO需要提供为自身注册的一个特殊入口点,入口点从newFooOperator()进入,Foo用你的网络类型替换(Sop,Obj,Dop,etc),比如,在SOP_Star.C中你将看到如下:
代码
void
newSopOperator(OP_OperatorTable
*
table)
{
table
->
addOperator(
new
OP_Operator(
"
hdk_star
"
,
//
Internal name
"
Star
"
,
//
UI name
SOP_Star::myConstructor,
//
How to build the SOP
SOP_Star::myTemplateList,
//
My parameters
0
,
//
Min # of sources
0
,
//
Max # of sources
SOP_Star::myVariables,
//
Local variables
OP_FLAG_GENERATOR)
//
Generates new geo
);
}
houdini运行这个函数来创建一个新的操作符并且添加它到操作符表,注意,(那些OP_Operator构造器提供的参数)op_operator的声明支持所有先前提及的构造信息,看局部变量如何使用它们自己.
参数
主题
- ~基础
- ~参数类型
- ~转换器
- ~多重参数
- ~Ramps
- ~菜单
- ~屏蔽参数
- ~作废参数
基础
创建一个新的操作符大量的跑腿活是建立PRM_Template对象数组,使用这些模板为操作符创建参数列表(PRM_ParmList),和参数对话框一样出现在给定节点类型的参数窗体上
让我们看看SOP_Star.C例子
首先注意PRM_Include.h包含各种不同的PRM_Template类和类型,然后我们有一些静态数据被PRM_Template的主数组使用(也是静态的)因为每个PRM_Template对象,我们用期望的信息初始化它。PRM_Template::PRM_Template()构造器连同各种不同的默认参数有许多格式,这儿有些主函数参数:
~thetype
定义储存格式并且它将如何出现在用户界面上
~thetype_ext
界面参数类型的附加选项PRM_TypeExtended.
thevectorsize
参数数据元素(或者参数部件)数目,比如,代表RGB颜色矢量规格应该建立成3
thenameptr
PRM_Name描述参数名称的指针,每个 PRM_Name对象包含一个记号和一个标签,记号有许多的目的,用来保存和加载参数,考虑它作为一个符号名称。因为它的使用,什么可以使用作为标记名称中有一些限制。它不能包含特殊字符(比如标准C变量名)并且不能包含任何的空格。标签用于界面目的,并应尽可能描述(不要太长),是实际文本显示给用户。
thedefaults
PRM_Default对象数组,每个组件。 PRM_Default有两个部分:浮点和字符串。浮点参数,假如默认字符串被定义,然后参数讲可以开始动画并且可以通过字符串定义通道表达式。另外,浮点默认用于浮点类型和整数类型,而字符串是用来初始化字符串类型。
thechoicelistptr
PRM_ChoiceList对象指针提供一个参数菜单选择,这只提供序号和字符串参数
therangeptr
PRM_Range对象指针定义有效的浮点或者整数类型值的有效范围。该范围也可以指定是否界面限制或者硬性限制。
thecallbackfunc
PRM_Callback函数指针通过用户修改界面参数来执行。
thehelptext
提供可选字符串作为参数在弹出对话框提示使用,为了给用户提供有关参数的快速提示这非常有用。
theexportlevel
出口对话框中指定相应的参数可能会出现,如果给定,这必须是第二个参数PRM_Template::PRM_Template().
thespareptr
这是由不同的参数类型使用可选的数据。
在上面的例子有很多PRM开头的共公参数名,默认,范围的数目,清单列表见 PRM_Shared.h 文件 (included by PRM_Include.h).
There are numerous predefined PRM_Type objects covering most of the commonly use parameter types declared in PRM_Type.h. They follow a common naming convention. If it ends in _E
, then it can contain non-animated expressions. If it ends in _J
, then it can be animated. If it ends with neither of these suffixes, then it is non-animatable. Some commonly used ones are:
PRM_FLT
A parameter containing float components. The channel name suffixes will be numbers like 1
, 2
, 3
, etc.
PRM_ANGLE
A single value representing an angle. A 2D circle representation is shown in the UI.
PRM_RGB
A parameter specifying a floating point triplet with channel suffixes r
, g
, b
, and a
.
PRM_XYZ
A parameter specifying a floating point triplet with channel suffixes x
, y
, and z
.
PRM_UVW
A parameter specifying a floating point triplet with channel suffixes u
, v
, and w
.
PRM_DIRECTION
A 3 component vector parameter used to indication a direction. It has channel suffixes x
, y
, and z
.
PRM_INT
A parameter that contains integer values but is stored in floating point. It uses numbers for channel suffixes like 1
, 2
, 3
, etc.
PRM_FLT_MINMAX
, PRM_INT_MINMAX
, PRM_ANGLE_MINMAX
A 2 component floating point parameter with channel suffixes min
and max
. For angle parameters, it will show a 2D circle representation.
PRM_STARTEND
A 2 component floating point parameter with channel suffixes start
and end
.
PRM_BEGINEND
A 2 component floating point parameter with channel prefixes start
and end
.
PRM_STRING
A simple string parameter.
PRM_FILE
, PRM_PICFILE
, PRM_GEOFILE
These types define different file path types. Each type expects a string to be used and that string will represent a file. Therefore, in the UI, there will be a file browser available for the parameter. However, for geo files, the filter on the file prompter will be set to only show geometry files. For pictures, only image files will be displayed, etc.
PRM_ORD
A parameter containing integer components. This is also used for index-based menus.
PRM_TOGGLE
A parameter that is a checkbox
PRM_CALLBACK
Button parameter that runs a callback function when pressed.
PRM_BUTTONSTRIP
A strip of text buttons for an ordinal bitmask parameter (up to 32 bits). A PRM_ChoiceList should be supplied for the button text names.
PRM_SWITCHER
Used to define a page or folder tab within the parameter list. In this case, the default float values determine the number of parameters per page, while the string component specifies the title for the folder tab. The vector size of the parameter specifies the number of pages contained. The parameters directly following this parameter make up the parameters in the folder tabs. By default, changing switcher parameters will not create undos or cause the owner node to re-cook. If you want to do this, you should use PRM_SWITCHER_REFRESH instead.
In addition to these types, one may bitwise or one of the following flags:
PRM_TYPE_JOIN_NEXT
Join the next parameter with the current one onto the same line
PRM_TYPE_LABEL_NONE
Omit the label
A detailed breakdown for a PRM_Type follows. It has three basic types (PRM_Type::PRM_BasicType):
FLOAT
Floating point parameters
STRING
String parameters
ORDINAL
Integer parameters
For each of these types, there are several possibilities to give it more semantic meaning (PRM_Type::PRM_FloatType, PRM_Type::PRM_OrdinalType, PRM_Type::PRM_StringType, PRM_Type::PRM_PathType). This allows the parameter pane to present the parameter in a way that is more suited to its real purpose. For example, if you have a string parameter, you might mark it as being a file path of some sort so that it will have a button in the parameter pane that brings up a file browser. For file paths, you can additionally specify them as particular file types so that the file browser has certain default file extensions. Additionally, there are some other modifiers on PRM_Type:
PRM_ChannelType
Specifies the suffix used for channel names. For example, the PRMradiusName parameter above has the name "rad" with an XYZ suffix. This means that the resulting channel names of the parameter will be "radx", "rady", and "radz".
PRM_InterfaceType
The main flag here is PRM_TYPE_CHANNEL which specifies whether this parameter can be animated. This field also contains some extra UI options for how the parameter should be displayed (such as PRM_INTERFACE_LABEL_NONE and PRM_INTERFACE_JOIN_NEXT).
PRM_BehaviorType
This specifies additional options for when the parameter's value is modified. Important flags here are: PRM_BEHAVIOR_NOREFRESH (does not trigger UI refresh, will not create undos) and PRM_BEHAVIOR_NOCOOK (will not cause nodes to recook).
In addition to PRM_Type, one also supply an optional PRM_ExtendedType. The most widely used options for PRM_ExtendedType are:
PRM_TYPE_DYNAMIC_PATH
Specifies a node path parameter with a node chooser icon button. If this is used, then you should additionally specify the desired node type for the path parameter via one of the predefiend PRM_SpareData objects such as PRM_SpareData::objPath or PRM_SpareData::sopPath.
PRM_TYPE_DYNAMIC_PATH_LIST
Similar to PRM_TYPE_DYNAMIC_PATH except it accepts a list of node paths.
PRM_TYPE_LOGARITHMIC
Specifies a logarithmic scale for floating point sliders.
Switcher parameters types (PRM_SWITCHER, PRM_SWITCHER_NOREFRESH) allows one to organize the parameters that follow it into a set of folders. The number of folders is specified as the vector size. The folder labels, and the number of parameters in the folder are given by the array of defaults. Note that if there are switchers inside switchers, the nested switcher inside and all its child parameters only count as 1 entry in the PRM_Default.
Here is a simple example that creates a switcher that has 2 folders where the first folder has 1 parameter, and the second folder has no parameters:
代码
static
PRM_Name switcherName(
"
shakeswitcher
"
);
static
PRM_Default switcherList[]
=
{
PRM_Default(
1
,
"
Shake
"
),
//
1 is number of parameters in tab
PRM_Default(
0
,
"
Other
"
),
//
actually have no parameters here
};
static
PRM_Name jitterName(
"
jitter
"
,
"
Jitter scale
"
);
static
PRM_Template templateList[]
=
{
PRM_Template(PRM_SWITCHER,
//
parm type
sizeof
(switcher)
/
sizeof
(PRM_Default),
//
number of folders
&
switcherName,
//
name
switcherList),
//
folder labels
PRM_Template(PRM_XYZ_J,
3
,
&
jitterName),
PRM_Template()
//
sentinel
};
Multi-parms are dynamically sized parameters. Each multi-parm has a variable number of child instances. Each multi-parm child instance itself consists of a fixed number of parameters (defined by an array of PRM_Template objects).
A multi-parm has a separate PRM_Template constructor so it cannot be confused with a standard parameter. Here's the constructor: (there is also a version with a PRM_Export parameter)
代码
PRM_Template(PRM_MultiType type,
PRM_Template
*
templates,
int
vectorsize,
PRM_Name
*
name,
PRM_Default
*
defaultsize
=
0
,
PRM_Range
*
defaultrange
=
0
,
int
startoffset
=
1
);
type
The type of multi-parm. Currently one of:
PRM_MULTITYPE_LIST
The simplest multi-parm. The instances are listed in one big list, expanding the dialog vertically as much as needed. Good for multi-parms that are nested in scrolled multi-parms, as they can share the scroll region. Also good for multi-parms with small ranges (max 20 or so).
The vectorsize parameter is not used.
PRM_MULTITYPE_SCROLL
The instances are listed in a UI container with scroll bars.
The vectorsize determines the size of the scroll region (in vertical UI inches).
PRM_MULTIPARM_SWITCHER
The instances are put in folder tabs. This type is good for instances which have large numbers of parameters (like full transforms).
The vectorsize determines the number of instances assigned to one tab.
type
templates
A PRM_Template list, which is almost identical in structure to the normal OP_Parameters template lists. All the parameter names in this list must contain a pound (#) character for each of its multi-parm parents.
vectorsize
Used in different ways by different multi types (see above).
name
Name of the multi-parm.
defaultsize
The default number of instances upon node creation.
defaultrange
The allowed range for the # of instances. PRM_RANGE_RESTRICTED must be used to define a limit. The limits must both be non-negative (>=0).
startoffset
This is where we start counting from. By default it is one. For example, for a child parameter named "parm#", the first instance of it will be named "parm1". Use can also use 0 for a zero offset, or other values.
Multi-parm template lists are almost identical to a normal template list. The differences are:
- The token names should have a # character in them to determine where to put the instance number. If using a generic vector, like PRM_FLT_J (vectorsize 2), then the # shouldn't be at the end of the token. This is because the component number for the subindex is appended to the token for the channel name, resulting in rather confusing channels like pos11, pos12, pos21, pos22, etc.). If a # is not found, the instance number will be appended to the token.
- Labels can have a # character, but it is not required. If the # is not present, the label appears as-is.
- Switchers of any kind are not allowed in multi-parm template lists.
- Multi-parm templates ARE allowed in multi-parm template lists (see below).
Here is an example that creates a series of 2D points with a RGBA color.
代码
static
PRM_Name names[]
=
{
PRM_Name(
"
points
"
,
"
Number of Points
"
),
};
static
PRM_Name pnames[]
=
{
PRM_Name(
"
pnt#pos
"
,
"
Point #
"
),
PRM_Name(
"
pnt#color
"
,
"
Color
"
),
};
static
PRM_Template thePointTemplates[]
=
{
PRM_Template(PRM_FLT_J,
2
,
&
pnames[
0
], PRMtwoDefaults),
PRM_Template(PRM_RGB_J, PRM_TYPE_COLOR_SWATCH,
4
,
&
pnames[
1
],
PRMoneDefaults),
PRM_Template()
};
PRM_Template
OP_Sample::myTemplateList[]
=
{
PRM_Template(PRM_MULTITYPE_SCROLL, thePointTemplates,
2
,
&
names[
0
]),
PRM_Template()
};
You can access the value of any multi-parm by name, or by using the PRM_Name with the # in it. You should not access multi-parms by index, nor should you lookup the parameter by name and store the index. Child parameters of a multi-parm are NOT guaranteed to be stored in any particular order (especially if 2 multi-parms or nested multi-parms are used in an OP_Node).
You may access any parameter before a multi-parm by index, but parameters after a multi-parm must be accessed by name.
As a convenience, you can use the eval...Inst() and set...Inst() functions to evaluate parameters. From the sample above, this code evaluates the point position of a series of points in the multi-parm:
int
num
=
evalInt(
"
points
"
,
0
,
0.0f
);
for
(
int
i
=
1
; i
<=
num; i
++
)
{
float
px
=
evalFloatInst(
"
pnt#pos
"
,
&
i,
0
, t);
float
py
=
evalFloatInst(
"
pnt#color
"
,
&
i,
0
, t);
}
Note that indexing multi-parms starts at 1, not 0 by default. This so that user-friendly instance names are generated. You can override this behaviour by changing the start offset in the parameter template constructor. However, this should only be done for exceptional cases or for backwards compatibility. The address of i is taken in the above example because the instance is actually a list; by default the list is 1 element long, but nested multi-parms require longer lists (you may have noticed the last parameter is 'int nestlevel = 1')
Nested multi-parms are slightly more complicated, simply because more levels of instance numbers are required. Consider the example:
代码
//
Node:
//
Curve 1
//
Points...
//
Curve 2
//
Points...
//
:
static
PRM_Name pnames[]
=
{
PRM_Name(
"
point#pos
"
,
"
Point #
"
),
};
static
PRM_Template thePointTemplates[]
=
{
PRM_Template(PRM_XYZ_J,
2
,
&
pnames[
0
]),
PRM_Template()
};
static
PRM_Name cnames[]
=
{
PRM_Name(
"
curve#def
"
,
"
Curve # Definition
"
),
};
static
PRM_Template theCurveTemplates[]
=
{
PRM_Template(PRM_MULTITYPE_LIST, thePointTemplates,
1
,
&
cnames[
0
]),
PRM_Template()
};
static
PRM_Name names[]
=
{
PRM_Name(
"
curves
"
,
"
Number of Curves
"
),
};
PRM_Template
OP_Sample::myTemplateList[]
=
{
PRM_Template(PRM_SWITCHER,
2
,
&
PRMswitcherName, switcher),
PRM_Template(PRM_MULTITYPE_SCROLL, theCurveTemplates,
2
,
&
names[
0
]),
PRM_Template(),
};
Each curve contains a series of 2D points, and the node itself has a series of curves, each of which are a variable size.
To access a specific point, you need to specify both the curve index and the point index.
代码
//
Eval all the points on all the curves.
int
ref
[
2
];
int
i,j;
int
num_curves
=
evalInt(
"
curves
"
,
0
,
0.0f
);
int
num_points;
float
px, py;
for
(i
=
0
; i
<
num_curves; i
++
)
{
ref
[
0
]
=
i;
//
only want nest level 1 to access the curve multiparm itself, to
//
determine the number of points in that curve.
num_points
=
evalIntInst(
"
curve#def
"
,
ref
,
0
,
0.0f
,
1
);
for
(j
=
0
; j
<
num_points; j
++
)
{
ref
[
1
]
=
j;
//
note the 2 at the end of the evalFloatInst - it's the nest level
px
=
evalFloatInst(
"
curve#point#pos
"
,
ref
,
0
,
0.0f
,
2
);
py
=
evalFloatInst(
"
curve#point#pos
"
,
ref
,
1
,
0.0f
,
2
);
}
}
Finally, note that you can't export multi-parms to the Toolbox (PRM_EXPORT_TBX). They're just too big.
Although ramp parameters are internally represented as multi-parms, they have a simplified declaration using the multi-parm PRM_Template constructor. You choose the PRM_MultiType as either PRM_MULTITYPE_RAMP_RGB (color) or PRM_MULTITYPE_RAMP_FLT (float) ramps. Then you pass NULL for the template list. The vector size must be 1 and the first PRM_Default entry specifies default number of ramp points (which itself must be at least 1).
代码
static
PRM_Template templateList[]
=
{
//
Color ramp
PRM_Template(PRM_MULTITYPE_RAMP_RGB, NULL,
1
,
&
POPrampColorName,
PRMtwoDefaults),
//
Float ramp
PRM_Template(PRM_MULTITYPE_RAMP_FLT, NULL,
1
,
&
POPrampAlphaName,
PRMtwoDefaults),
PRM_Template()
};
To create a parameter with a menu, a PRM_ChoiceList object needs to be supplied. The PRM_ChoiceList constructor takes various PRM_ChoiceListType flags:
PRM_CHOICELIST_REPLACE
Chosen choice replaces the existing parameter value.
PRM_CHOICELIST_TOGGLE
Chosen choice toggles the string token in the existing parameter value
PRM_CHOICELIST_APPEND
Chosen choice's string token is appended to the existing parameter value
PRM_CHOICELIST_WILD
Used with PRM_CHOICELIST_TOGGLE to indicate *
as a valid value to mean all choices.
PRM_CHOICELIST_SINGLE
Chosen choice is exclusive and replaces the existing parameter value. A PRM_ChoiceList object should only be used for PRM_ORD or PRM_STRING type parameters. For PRM_ORD parameters, PRM_ChoiceListType::PRM_CHOICELIST_SINGLE should always be used. For the other flags with PRM_STRING parameters, a string value will be presented with a separate icon for making menu choices.
The example below demonstrates a simple static menu setup for ordinal and string parameters.
代码
#include
<
PRM
/
PRM_ChoiceList.h
>
static
PRM_Name sopOrdinalName(
"
ordmenu
"
,
"
Ordinal Menu
"
);
static
PRM_Name sopOrdChoices[]
=
{
PRM_Name(
"
choice1
"
,
"
Choice 1
"
),
PRM_Name(
"
choice2
"
,
"
Choice 2
"
),
PRM_Name(
"
choice3
"
,
"
Choice 3
"
),
PRM_Name(
0
)
};
static
PRM_ChoiceList sopOrdinalMenu(PRM_CHOICELIST_SINGLE, sopOrdChoices);
static
PRM_Name sopStringName(
"
strmenu
"
,
"
String Menu
"
);
static
PRM_Name sopStrChoices[]
=
{
PRM_Name(
"
strchoice1
"
,
"
Str Choice 1
"
),
PRM_Name(
"
strchoice2
"
,
"
Str Choice 2
"
),
PRM_Name(
"
strchoice3
"
,
"
Str Choice 3
"
),
PRM_Name(
0
)
};
static
PRM_ChoiceList sopStringMenu(PRM_CHOICELIST_TOGGLE, sopStrChoices);
PRM_Template
SOP_MyNode::myTemplateList[]
=
{
PRM_Template(PRM_ORD,
1
,
&
sopOrdinalName,
0
,
&
sopOrdinalMenu),
PRM_Template(PRM_STRING,
1
,
&
sopStringName,
0
,
&
sopStringMenu),
PRM_Template()
};
Menus with items generated dynamically are done with a different form of the PRM_ChoiceList constructor that is given a PRM_ChoiceGenFunc callback. The callback fills out a PRM_Name array along with a trailing sentinel item. Care should be taken to NOT generate more than listsize
items.
For group menus, one can also use SOP_Node functions like in the example below.
代码
static
void
sopBuildRestGroup(
void
*
data, PRM_Name
*
choicenames,
int
listsize,
const
PRM_SpareData
*
spare, PRM_Parm
*
parm)
{
SOP_Node
*
sop
=
CAST_SOPNODE((OP_Node
*
)data);
if
( sop )
{
sop
->
buildInputGroups( SOP_REST_INPUT, choicenames, listsize,
PRIM_GROUP,
0
,
true
, parm );
}
else
{
choicenames[
0
].setToken(
0
);
choicenames[
1
].setLabel(
0
);
}
}
static
PRM_ChoiceList sopRestGroupMenu(PRM_CHOICELIST_TOGGLE,
sopBuildRestGroup);
To disable parameters, one should override the OP_Parameters::disableParms() method. This method is called by the parameter pane to give the node a chance to disable parameters in the UI which will not used when cooked. Parameters are usually disabled due to the values of other parameters which render them unused.
The disableParms() implementation typically evaluates some parameters to determine whether different set of parameters should be used. Then the OP_Parameters::enableParm() method should be called with a true or false value. Note that enableParm() should always be called for any parameter that might be enabled or disabled. OP_Parameters::enableParm() returns 1 if the parameter's enable state actually changed. disableParms() should keep a count and return the number of parameters actually changed.
代码
unsigned
int
SOP_CopRaster::disableParms()
{
float
t
=
CHgetEvalTime();
int
changed
=
0
;
bool
use_path;
use_path
=
!
evalInt(
"
usedisk
"
,
0
, t);
changed
=
enableParm(
"
coppath
"
, use_path);
changed
+=
enableParm(
"
copcolor
"
, use_path);
return
changed;
}
As new features are added to your custom operator, you may find a need to change the behaviour of how some of the old parameters work. However, there might be legacy scene files that you need to support which relies on a particular value of the old parameter behaving a particular way. The usual way to solve these type of problems is to create a new parameter that works similarly to the old parameter but has a different name. The old parameter is then moved into the obsolete parameter list for special handling at load time.
As Houdini loads a scene file, an obsolete parameter list is created for each node that it is loading. If it encounters a parameter on a node that does not match any of the existing parameters of that node, it will first attempt to find a matching obsolete parameter for loading. When the node is done loading, the OP_Node::resolveObsoleteParms() method is called to convert the values of the obsolete parameters into values of the current parameter list that will result in the old behaviour. Finally, the obsolete parm list is destroyed.
To use obsolete parameters, first define an obsolete PRM_Template array similar to how it is done with regular parameter templates. Then when you register your operator, call OP_Operator::setObsoleteTemplates() with your obsolete template list.
代码
void
newSopOperator(OP_OperatorTable
*
table)
{
OP_Operator
*
op;
op
=
new
OP_Operator(
"
myoperator
"
,
"
My Operator
"
,
/*
...
*/
);
op
->
setObsoleteTemplates(OP_MyNode::myObsoleteList);
table
->
addOperator(op);
}
Then implement OP_Node:resolveObsoleteParms() in your subclass. The important thing to note is that the obsolete parameter list is like any parameter list with its default values. The only way to know if a particular obsolete parm was found, is to test if the value of the parameter is at its default value. The example below illustrates the coding pattern for resolveObsoleteParms
.
代码
void
SOP_MyNode::resolveObsoleteParms(PRM_ParmList
*
obsolete_parms)
{
float
t
=
CHgetEvalTime();
//
If there are none defined, we don't do any conversions...
if
(
!
obsolete_parms)
return
;
PRM_Parm
*
parm
=
obsolete_parms
->
getParmPtr(
"
obsolete_parm_name
"
);
if
(parm
&&
!
parm
->
isFactoryDefault())
{
int
old_val
=
obsolete_parms
->
evalInt(
"
obsolete_parm_name
"
,
0
, t);
int
new_val;
//
... convert old_val into some new_val
setInt(
"
new_parm
"
,
0
, t, new_val);
//
... may also need to set other parameters according to old_val
}
//
delegate to base class
SOP_Node::resolveObsoleteParms(obsolete_parms);
}