Katana Plug-in APIs 0.1

FnOpDescriptionBuilder.h

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
 All Classes Functions Variables Typedefs Enumerations Enumerator