|
Katana Plug-in APIs 0.1
|
00001 #ifndef FnOpDescriptionBuilder_H 00002 #define FnOpDescriptionBuilder_H 00003 00004 #include <FnAttribute/FnAttribute.h> 00005 #include <FnAttribute/FnGroupBuilder.h> 00006 00007 #include <vector> 00008 #include <string> 00009 #include <iostream> 00010 00011 #include "ns.h" 00012 00013 /* This file defines the FnOpDescriptionBuilder and associated functionality. 00014 * 00015 * The FnOpDescriptionBuilder is intended to be used to aid developers in 00016 * documenting their Ops - describing what inputs and outputs the Op has, etc. 00017 * Whilst the FnOpDescriptionBuilder hides away underlying conventions, the 00018 * end result is a GroupAttribute. As such, you can bypass the 00019 * FnOpDescriptionBuilder and create a GroupAttribute manually yourself. Below 00020 * is a description of the attribute conventions expected in the GroupAttribute. 00021 * 00022 * Please note that these conventions are subject to change and using the 00023 * FnOpDescriptionBuilder is the preferred/recommended way of generating this 00024 * GroupAttribute. 00025 * 00026 * The top-level children of the GroupAttribute can be: 00027 * * 'opSummary': A StringAttribute that gives a *brief* description of the 00028 * Op 00029 * * 'opHelp': A StringAttribute that gives a more detailed, potentially 00030 * multi-line description of the Op. 00031 * * 'opNumInputs': An IntAttribute representing the number of inputs the Op 00032 * requires. 00033 * * 'opArgs': A GroupAttribute whose children represent Attributes 00034 * expected/required as opArgs to the Op (see below for structure) 00035 * * 'inputAttrs': A GroupAttribute whose children represent Attributes 00036 * that the Op will read from the input scene graph (see below for 00037 * structure) 00038 * * 'outputAttrs': A GroupAttribute whose children represent Attributes 00039 * that the Op will write to the output scene graph (see below for 00040 * structure) 00041 * * 'meta': A GroupAttribute that is used to maintain ordering of opArgs, 00042 * inputAttrs and outputAttrs. This GroupAttribute should have three 00043 * children: 'opArgs', 'inputAttrs' and 'outputAttrs'. Each of these 00044 * is expected to be a multi-sampled StringAttribute, with the names 00045 * of the opArgs/inputAttrs/outputAttrs respectively, ordered 00046 * appropriately. This ordering will be maintained in any UI display 00047 * generated from this description. 00048 * 00049 * For the opArgs, inputAttrs and outputAttrs GroupAttributes, it is expected 00050 * that each of their children is another GroupAttribute, named as the name 00051 * of the respective attribute (including any "."s). Underneath that name is 00052 * then expected to be a special GroupAttribute named __FnOpDescription. This 00053 * is to help separate the description from the naming, when the attribute name 00054 * contains children (has "."s). The __FnOpDescription group can have the 00055 * following children (unless otherwise specified, these children are optional): 00056 * 00057 * * 'description': (Required) A StringAttribute that describes the usage 00058 * of the attribute in as much detail as necessary 00059 * * 'type': (Required) An IntAttribute that describes the type of the 00060 * attribute. This numeric value should correspond to one of the type 00061 * values defined by the AttrTypeDescription enum below 00062 * * 'optional': An IntAttribute that is 1 if the attribute isn't required 00063 * for the Ops correct operation, 0 if it is required. 00064 * * 'default': (Required iff optional=1) An Attribute that is only used if 00065 * 'optional' is 1. This represents the default value that is used if 00066 * the (optional) attribute is not found by the Op 00067 * * 'defaultDescription': (Required iff optional=1 and default is not 00068 * specified) A StringAttribute that is only used if 'optional' is 1. 00069 * This can be used in place of the 'default' value if it's not 00070 * possible for you to provide a concrete default value, and instead 00071 * wish to provide a description of what happens in the default case 00072 * * 'inputIndex': An IntAttribute that defines which input index on the Op 00073 * that the attribute will be read from. This is only used/expected 00074 * in the inputAttrs GroupAttribute. 00075 * * 'widgetHint': A StringAttribute that corresponds to a UI widget hint. 00076 * This can be used by UI code to guess at an appropriate widget to 00077 * use when providing a UI for the Op. Examples include 'cel', 00078 * 'scenegraphLocation', etc. 00079 * * 'atLocation': A StringAttribute that can be used to specify a static 00080 * scene graph location that the attribute will always be read 00081 * from/written to. This is only used (and is optional) in the 00082 * inputAttrs and outputAttrs GroupAttributes. This is useful if, for 00083 * example, the attribute is always read from /root/world (for 00084 * example for constraint or globals lists). 00085 * 00086 * There are some conventions that can be used when naming things: 00087 * 00088 * * opArgs that are intended to be internal/private to the Op should be 00089 * prefixed with an underscore. Often, Ops will call themselves as 00090 * children and pass down modified and extra opArgs. In this case, if 00091 * the opArg is not intended to ever be provided by external users of the 00092 * Op (other than the Op itself), the opArg name should be prefixed with 00093 * a "_". 00094 * 00095 * * Wildcards ("*") can be used in attribute names. Some Ops may have a 00096 * flexible interface, not specifically requiring a particular named 00097 * attribute, but instead handling any attribute under a certain parent. 00098 * One example of this is the StaticSceneCreate Op. This Op has three 00099 * main expected opArgs: a, c and x. Whilst these are known values, the 00100 * structure and nature of their children isn’t known, and so cannot be 00101 * completely described. But we can describe what we do know and do want 00102 * to restrict using wildcards: a.*, c.*, x.* and also x.*.opType and 00103 * x.*.opArgs can be used as names when creating the opArgs 00104 * GroupAttribute. 00105 */ 00106 00107 FNGEOLIBOP_NAMESPACE_ENTER 00108 { 00109 namespace FnOpDescription 00110 { 00114 typedef enum AttrTypeDescription { 00115 kTypeIntAttribute = 1, 00116 kTypeFloatAttribute = 2, 00117 kTypeDoubleAttribute = 4, 00118 kTypeStringAttribute = 8, 00119 kTypeGroupAttribute = 16, 00120 kTypeDynamic = 32, // type is inferred from some other value/thing 00121 kTypeNumericAttribute = kTypeIntAttribute | 00122 kTypeFloatAttribute | 00123 kTypeDoubleAttribute, 00124 kTypeAnyAttribute = kTypeIntAttribute | 00125 kTypeFloatAttribute | 00126 kTypeDoubleAttribute | 00127 kTypeStringAttribute | 00128 kTypeGroupAttribute 00129 } AttrTypeDescription; 00130 00135 class AttrDescription 00136 { 00137 friend class FnOpDescriptionBuilder; 00138 00139 public: 00140 virtual ~AttrDescription() {} 00141 00143 const std::string& getDescription() const { return m_description; } 00145 const std::string& getName() const { return m_name; } 00147 AttrTypeDescription getAttrType() const { return m_type; } 00148 00150 void setDescription(const std::string& description) 00151 { 00152 m_description = description; 00153 } 00154 00155 protected: 00156 virtual FnAttribute::GroupAttribute build() const 00157 { 00158 FnAttribute::GroupBuilder attrGb; 00159 00160 attrGb.set("description", 00161 FnAttribute::StringAttribute(m_description)); 00162 attrGb.set("type", 00163 FnAttribute::IntAttribute(m_type)); 00164 00165 return attrGb.build(); 00166 } 00167 00170 AttrDescription(AttrTypeDescription type, const std::string& name) 00171 : m_type(type), m_name(name), m_description("") {} 00172 00173 private: 00174 AttrTypeDescription m_type; 00175 std::string m_name; 00176 std::string m_description; 00177 }; 00178 00183 class OptionalAttrDescription : public AttrDescription 00184 { 00185 friend class FnOpDescriptionBuilder; 00186 00187 public: 00189 bool isOptional() const { return m_optional; } 00192 const FnAttribute::Attribute getDefaultValue() const 00193 { 00194 return m_defaultValue; 00195 } 00196 00198 void setOptional(bool optional) 00199 { 00200 m_optional = optional; 00201 } 00206 void setDefaultValue(const FnAttribute::Attribute& defaultValue) 00207 { 00208 if (defaultValue.getType() != kFnKatAttributeTypeNull) 00209 { 00210 setOptional(true); 00211 } 00212 m_defaultValue = defaultValue; 00213 } 00214 00219 void setDefaultDescription(const std::string& defaultDescription) 00220 { 00221 m_defaultDescription = defaultDescription; 00222 } 00223 00224 protected: 00225 virtual FnAttribute::GroupAttribute build() const 00226 { 00227 FnAttribute::GroupBuilder attrGb; 00228 attrGb.update(AttrDescription::build()); 00229 00230 if (m_optional) 00231 { 00232 attrGb.set("optional", FnAttribute::IntAttribute(1)); 00233 00234 if (m_defaultValue.getType() != kFnKatAttributeTypeNull) 00235 { 00236 attrGb.set("default", m_defaultValue); 00237 } 00238 else if (!m_defaultDescription.empty()) 00239 { 00240 attrGb.set("defaultDescription", 00241 FnAttribute::StringAttribute( 00242 m_defaultDescription)); 00243 } 00244 else 00245 { 00246 throw std::runtime_error( 00247 "Attribute declared as optional, but no default " 00248 "value or description was given."); 00249 } 00250 00251 attrGb.set("default", m_defaultValue); 00252 } 00253 00254 return attrGb.build(); 00255 } 00256 00259 OptionalAttrDescription(AttrTypeDescription type, 00260 const std::string& name) 00261 : AttrDescription(type, name), 00262 m_optional(false), 00263 m_defaultValue(FnAttribute::NullAttribute()) {} 00264 00265 private: 00266 bool m_optional; 00267 FnAttribute::Attribute m_defaultValue; 00268 std::string m_defaultDescription; 00269 }; 00270 00277 class OpArgDescription : public OptionalAttrDescription 00278 { 00279 friend class FnOpDescriptionBuilder; 00280 00281 public: 00284 OpArgDescription(AttrTypeDescription type, const std::string& name) 00285 : OptionalAttrDescription(type, name), 00286 m_widgetHint("") {} 00287 00291 const std::string& getWidgetHint() const { return m_widgetHint; } 00292 00296 void setWidgetHint(const std::string& widgetHint) 00297 { 00298 m_widgetHint = widgetHint; 00299 } 00300 00301 protected: 00302 virtual FnAttribute::GroupAttribute build() const 00303 { 00304 FnAttribute::GroupBuilder attrGb; 00305 attrGb.update(OptionalAttrDescription::build()); 00306 00307 if (!m_widgetHint.empty()) 00308 { 00309 attrGb.set("widgetHint", 00310 FnAttribute::StringAttribute(m_widgetHint)); 00311 } 00312 00313 return attrGb.build(); 00314 } 00315 00316 private: 00317 std::string m_widgetHint; 00318 }; 00319 00324 class InputAttrDescription : public OptionalAttrDescription 00325 { 00326 friend class FnOpDescriptionBuilder; 00327 00328 public: 00331 InputAttrDescription(AttrTypeDescription type, 00332 const std::string& name) 00333 : OptionalAttrDescription(type, name), 00334 m_inputIndex(0), 00335 m_atLocation("") {} 00336 00339 int getInputIndex() const { return m_inputIndex; } 00342 std::string getAtLocation() const { return m_atLocation; } 00343 00346 void setInputIndex(int inputIndex) 00347 { 00348 m_inputIndex = inputIndex; 00349 } 00354 void setAtLocation(const std::string& atLocation) 00355 { 00356 m_atLocation = atLocation; 00357 } 00358 00359 protected: 00360 virtual FnAttribute::GroupAttribute build() const 00361 { 00362 FnAttribute::GroupBuilder attrGb; 00363 attrGb.update(OptionalAttrDescription::build()); 00364 00365 attrGb.set("inputIndex", 00366 FnAttribute::IntAttribute(m_inputIndex)); 00367 00368 if (!m_atLocation.empty()) 00369 { 00370 attrGb.set("atLocation", 00371 FnAttribute::StringAttribute(m_atLocation)); 00372 } 00373 00374 return attrGb.build(); 00375 } 00376 00377 private: 00378 int m_inputIndex; 00379 std::string m_atLocation; 00380 }; 00381 00386 class OutputAttrDescription : public AttrDescription 00387 { 00388 friend class FnOpDescriptionBuilder; 00389 00390 public: 00393 OutputAttrDescription(AttrTypeDescription type, 00394 const std::string& name) 00395 : AttrDescription(type, name), 00396 m_atLocation("") {} 00397 00400 std::string getAtLocation() const { return m_atLocation; } 00401 00406 void setAtLocation(const std::string& atLocation) 00407 { 00408 m_atLocation = atLocation; 00409 } 00410 00411 protected: 00412 virtual FnAttribute::GroupAttribute build() const 00413 { 00414 FnAttribute::GroupBuilder attrGb; 00415 attrGb.update(AttrDescription::build()); 00416 00417 if (!m_atLocation.empty()) 00418 { 00419 attrGb.set("atLocation", 00420 FnAttribute::StringAttribute(m_atLocation)); 00421 } 00422 00423 return attrGb.build(); 00424 } 00425 00426 private: 00427 std::string m_atLocation; 00428 }; 00429 00436 class FnOpDescriptionBuilder 00437 { 00438 public: 00439 00440 FnOpDescriptionBuilder() {} 00441 ~FnOpDescriptionBuilder() {} 00442 00448 static std::vector<FnKatAttributeType> 00449 AttrTypeDescriptionToFnKatAttributeTypes( 00450 AttrTypeDescription attrType) 00451 { 00452 std::vector<FnKatAttributeType> result; 00453 if (attrType & kTypeIntAttribute) 00454 result.push_back(kFnKatAttributeTypeInt); 00455 if (attrType & kTypeFloatAttribute) 00456 result.push_back(kFnKatAttributeTypeFloat); 00457 if (attrType & kTypeDoubleAttribute) 00458 result.push_back(kFnKatAttributeTypeDouble); 00459 if (attrType & kTypeStringAttribute) 00460 result.push_back(kFnKatAttributeTypeString); 00461 if (attrType & kTypeGroupAttribute) 00462 result.push_back(kFnKatAttributeTypeGroup); 00463 return result; 00464 } 00465 00470 void setSummary(const std::string& summary) 00471 { 00472 m_gb.set("opSummary", FnAttribute::StringAttribute(summary)); 00473 } 00474 00479 void setHelp(const std::string& help) 00480 { 00481 m_gb.set("opHelp", FnAttribute::StringAttribute(help)); 00482 } 00483 00485 void setNumInputs(unsigned int numInputs) 00486 { 00487 m_gb.set("opNumInputs", FnAttribute::IntAttribute(numInputs)); 00488 } 00489 00491 FnAttribute::GroupAttribute build() 00492 { 00493 // Add details of the ordering of the opArgs/inattrs/outattrs 00494 m_gb.set("meta.ordering.opArgs", 00495 FnAttribute::StringAttribute(m_opArgOrder)); 00496 m_gb.set("meta.ordering.inputAttrs", 00497 FnAttribute::StringAttribute(m_inputAttrOrder)); 00498 m_gb.set("meta.ordering.outputAttrs", 00499 FnAttribute::StringAttribute(m_outputAttrOrder)); 00500 00501 // Reset state. m_gb.build() will reset the state of the 00502 // internal GroupBuilder, so reset our state too. 00503 m_opArgOrder.clear(); 00504 m_inputAttrOrder.clear(); 00505 m_outputAttrOrder.clear(); 00506 00507 return m_gb.build(); 00508 } 00509 00511 std::vector<std::string> getOpArgOrder() 00512 { 00513 return m_opArgOrder; 00514 } 00515 00518 std::vector<std::string> getInputAttrOrder() 00519 { 00520 return m_inputAttrOrder; 00521 00522 } 00523 00526 std::vector<std::string> getOutputAttrOrder() 00527 { 00528 return m_outputAttrOrder; 00529 } 00530 00537 void describeOpArg(const OpArgDescription& opArg) 00538 { 00539 set(std::string("opArgs.") + opArg.getName(), opArg.build()); 00540 00541 // Store the name in a vector to maintain order 00542 m_opArgOrder.push_back(opArg.getName()); 00543 } 00544 00552 void describeInputAttr(const InputAttrDescription& inputAttr) 00553 { 00554 set(std::string("inputAttrs.") + inputAttr.getName(), 00555 inputAttr.build()); 00556 00557 // Store the name in a vector to maintain order 00558 m_inputAttrOrder.push_back(inputAttr.getName()); 00559 } 00560 00568 void describeOutputAttr(const OutputAttrDescription& outputAttr) 00569 { 00570 set(std::string("outputAttrs.") + outputAttr.getName(), 00571 outputAttr.build()); 00572 00573 // Store the name in a vector to maintain order 00574 m_outputAttrOrder.push_back(outputAttr.getName()); 00575 } 00576 00577 private: 00578 00579 void set(const std::string& name, 00580 const FnAttribute::Attribute& attr) 00581 { 00582 const std::string keyedName = name + ".__FnOpDescription"; 00583 m_gb.set(keyedName, attr); 00584 } 00585 00586 FnAttribute::GroupBuilder m_gb; 00587 00588 std::vector<std::string> m_opArgOrder; 00589 std::vector<std::string> m_inputAttrOrder; 00590 std::vector<std::string> m_outputAttrOrder; 00591 }; 00592 } 00593 } 00594 FNGEOLIBOP_NAMESPACE_EXIT 00595 00596 #endif
1.7.3