HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
VOP_Switch.C
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018
3  * Side Effects Software Inc. All rights reserved.
4  *
5  * Redistribution and use of Houdini Development Kit samples in source and
6  * binary forms, with or without modification, are permitted provided that the
7  * following conditions are met:
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. The name of Side Effects Software may not be used to endorse or
11  * promote products derived from this software without specific prior
12  * written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE `AS IS' AND ANY EXPRESS
15  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17  * NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
20  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
23  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25 
26 #include <stdlib.h>
27 #include <UT/UT_DSOVersion.h>
28 #include <UT/UT_StringStream.h>
29 #include <PRM/PRM_Include.h>
30 #include <OP/OP_OperatorTable.h>
31 #include <OP/OP_Input.h>
32 #include <VOP/VOP_Operator.h>
33 #include "VOP_Switch.h"
34 
35 using namespace HDK_Sample;
36 
37 void
39 {
40  OP_Operator *op;
41 
42  // Create a new VOP_Operator which describes the operator we are
43  // building. The parameters to this function are similar to the
44  // OP_Operator constructor except for the vopnet mask, and the
45  // last parameter, which specifies the number of outputs from
46  // this operator.
47  op = new VOP_Operator("hdkswitch", // internal name
48  "HDK Switch", // UI name
49  VOP_Switch::myConstructor, // How to create one
50  VOP_Switch::myTemplateList, // parm definitions
52  0, // Min # of inputs
53  VOP_VARIABLE_INOUT_MAX, // Max # of inputs
54  "*", // vopnet mask
55  0, // Local variables
56  OP_FLAG_UNORDERED, // Special flags
57  1); // # of outputs
58 
59  table->addOperator(op);
60 }
61 
62 static const char *theInputRoot = "input";
63 static const char *theOutputName = "result";
64 static PRM_Name theSwitcherName("switcher", "Switcher Index");
65 static PRM_Name theOutOfBoundsName("outofbounds",
66  "Out Of Bounds Behavior");
67 static PRM_Name theOutOfBoundsChoices[] =
68 {
69  PRM_Name("last", "Output Last Input Value"),
70  PRM_Name("zero", "Output Zero"),
71  PRM_Name()
72 };
73 enum
74 {
77 };
78 static PRM_ChoiceList theOutOfBoundsMenu(PRM_CHOICELIST_SINGLE,
79  theOutOfBoundsChoices);
80 
81 OP_Node *
83 {
84  return new VOP_Switch(net, name, entry);
85 }
86 
88 {
89  PRM_Template(PRM_INT, 1, &theSwitcherName, PRMzeroDefaults),
90  PRM_Template(PRM_ORD, 1, &theOutOfBoundsName, PRMzeroDefaults,
91  &theOutOfBoundsMenu),
92  // List terminator
93  PRM_Template()
94 };
95 
96 VOP_Switch::VOP_Switch(OP_Network *parent, const char *name, OP_Operator *entry)
97  : VOP_Node(parent, name, entry)
98 {
99 }
100 
102 {
103 }
104 
105 bool
107 {
108  bool changed = VOP_Node::updateParmsFlags();
109 
110  // Disable the switcher index parameter if the first input is connected
111  // because the input value will be used instead of the parameter value.
112  changed |= enableParm(theSwitcherName.getToken(), getInput(0) == 0);
113 
114  return changed;
115 }
116 
117 void
119 {
120  // If there isn't at least one input connected after the switch index
121  // input, then this node generates no code.
122  if (getNumVisibleInputs() > 2)
123  {
124  UT_OStringStream os;
125  UT_String inputName, outputName;
126  int outofbounds = OUTOFBOUNDS();
127  int i, j, next, first = 1;
128 
129  // The code generated by this node is a series of if/then/else
130  // statements. Each inputs has a chance to be assigned to the
131  // output value depending on the switch index value. The switch
132  // index may be defined by an input or by a parameter value if no
133  // input is connected.
134  getOutputName(outputName, 0);
135  for( i = getConnectedInputIndex(0), j = 0; i >= 0; i = next, j++ )
136  {
137  // For each connected input after the first one (the switch index
138  // input), we output code like:
139  // if( $switcher == 0 )
140  // $result = $input1;
141  // else if( $switcher == 1 )
142  // $result = $input2;
143  // else
144  // $result = $input3;
145  //
146  // Note that the inputs and output names are preceded by "$" so
147  // the code generator will use unique variables names, or the
148  // correct input variable names matching the connected inputs.
149  // The $switcher value will be expanded by the code generator to
150  // use either the matching input variable name or the switcher
151  // parameter value (if no input is connected).
152  next = getConnectedInputIndex(i);
153  getInputName(inputName, i);
154  if( next >= 0 || outofbounds == VOP_SWITCH_OOB_ZERO )
155  {
156  if( !first )
157  os << "else ";
158  os << "if( $" << theSwitcherName.getToken();
159  os << " == " << j << " )\n";
160  os << " ";
161  }
162  else if( !first )
163  {
164  os << "else\n" << " ";
165  }
166  os << "$" << outputName << " = $" << inputName << ";\n";
167  first = 0;
168  }
169  // If we are asked to use the first input for out of bounds switch
170  // indices, we need to append a final else clause to use the first
171  // input value.
172  if( outofbounds == VOP_SWITCH_OOB_ZERO )
173  {
174  VOP_TypeInfo output_type_info;
175  UT_String const_val;
176 
177  getOutputTypeInfo(output_type_info, 0);
178  myLanguage->getEmptyConstantCode(const_val, output_type_info);
179 
180  if( !first )
181  os << "else\n" << " ";
182  os << "$" << outputName << " = ";
183  os << const_val.buffer() << ";\n";
184  }
185  codestr.harden(os.str().buffer());
186  }
187 }
188 
189 const char *
190 VOP_Switch::inputLabel(unsigned idx) const
191 {
192  if (idx >= orderedInputs())
193  {
194  static UT_String theLabel;
195  char numstr[UT_NUMBUF];
196 
197  // Inputs after the first one are just numbered starting at 1.
198  theLabel = "Input Number ";
199  UT_String::itoa(numstr, idx + 1 - orderedInputs());
200  theLabel += numstr;
201 
202  return theLabel;
203  }
204  else
205  return theSwitcherName.getLabel();
206 }
207 
208 const char *
209 VOP_Switch::outputLabel(unsigned idx) const
210 {
211  UT_ASSERT(idx == 0);
212 
213  return "Chosen Value";
214 }
215 
216 void
218 {
219  if (idx >= orderedInputs())
220  {
221  char numstr[UT_NUMBUF];
222 
223  // Inputs after the first one are just numbered starting at 1.
224  in = theInputRoot;
225  UT_String::itoa(numstr, idx + 1 - orderedInputs());
226  in += numstr;
227  }
228  else
229  in = theSwitcherName.getToken();
230 }
231 
232 int
234 {
235  int inputnum = -1;
236 
237  // The switcher input is always first.
238  if( in == theSwitcherName.getToken() )
239  return 0;
240 
241  // Use the numeric suffix on the input name to determine the input index.
242  if( !strncmp(in, theInputRoot, strlen(theInputRoot)) )
243  inputnum = ::atoi((const char *)in + strlen(theInputRoot));
244 
245  return inputnum - 1 + orderedInputs();
246 }
247 
248 void
250 {
251  // For any input past our ordered inputs, all input types are the
252  // same - whatever is plugged into the first variable input.
253  if( idx >= orderedInputs() )
254  // Helper method, which essentially invokes
255  // vop->getOutputTypeInfo( type_info, input->getNodeOutputIndex() );
256  // on the input vop node
258  else
260 }
261 
262 void
264  VOP_VopTypeInfoArray &type_infos)
265 {
266  VOP_Node *vop;
267  OP_Input *input;
268 
269  if( idx >= orderedInputs() )
270  {
271  // For any input past our ordered inputs, all input types are the
272  // same - whatever is plugged into the first variable input.
273  if( (input = getInputReference(orderedInputs(), 0)) )
274  {
275  vop = CAST_VOPNODE(input->getNode());
276  if( vop )
277  {
278  VOP_TypeInfo type_info;
279 
280  vop->getOutputTypeInfo(type_info, input->getNodeOutputIndex());
281  type_infos.append(type_info);
282  }
283  }
284  }
285  else
286  {
287  VOP_TypeInfo type_info(VOP_TYPE_INTEGER);
288  type_info.conditionType(*myLanguage);
289  type_infos.append(type_info);
290  }
291 }
292 
293 void
295 {
296  UT_ASSERT(idx == 0);
297 
298  name = theOutputName;
299 }
300 
301 void
303 {
304  UT_ASSERT(idx == 0);
305 
306  // The output data type is the same as the data type of the first
307  // input after the switch index.
308  getInputTypeInfo(type_info, orderedInputs());
309 }
310 
311 unsigned
313 {
314  int max = nInputs();
315 
316  // Make sure there is always exactly one unconnected unordered input
317  // visible.
318  if( max < orderedInputs() )
319  max = orderedInputs();
320 
321  return max + 1;
322 }
323 
324 unsigned
326 {
327  // The first input (corresponding to the switch index) must always be
328  // visible.
329  return 1;
330 }
331 
332 int
334 {
335  return evalInt(theOutOfBoundsName.getToken(), 0, 0.0f);
336 }
337 
GLint first
Definition: glcorearb.h:404
virtual bool updateParmsFlags()
void newVopOperator(OP_OperatorTable *table)
Definition: VOP_Switch.C:38
virtual void getOutputTypeInfoSubclass(VOP_TypeInfo &type_info, int idx)
Fills out the info about the data type of each output connector.
Definition: VOP_Switch.C:302
virtual void getOutputNameSubclass(UT_String &out, int idx) const
Definition: VOP_Switch.C:294
virtual unsigned getNumVisibleInputs() const
Controls the number of input buttons visible on the node tile.
Definition: VOP_Switch.C:312
virtual void getOutputName(UT_String &out, int idx) const
virtual void getAllowedInputTypeInfosSubclass(unsigned idx, VOP_VopTypeInfoArray &type_infos)
Definition: VOP_Switch.C:263
#define VOP_VARIABLE_INOUT_MAX
Definition: VOP_Node.h:57
PRM_API const PRM_Type PRM_ORD
virtual void getEmptyConstantCode(UT_String &code, const VOP_TypeInfo &type_info) const =0
An output stream object that owns its own string buffer storage.
void setType(VOP_Type type, VOP_Type raw_type=VOP_TYPE_UNDEF, const char *type_name=NULL)
void conditionType(const VOP_Language &language)
VOP_Switch(OP_Network *net, const char *name, OP_Operator *entry)
Definition: VOP_Switch.C:96
const UT_WorkBuffer & str() const
Returns a read-only reference to the underlying UT_WorkBuffer.
bool addOperator(OP_Operator *op, std::ostream *err=nullptr)
const char * getLabel() const
Definition: PRM_Name.h:41
png_uint_32 i
Definition: png.h:2877
virtual const char * outputLabel(unsigned idx) const
Definition: VOP_Switch.C:209
void getOutputTypeInfo(VOP_TypeInfo &type_info, int idx) const
virtual unsigned nInputs() const
const hboost::disable_if_c< VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:132
PRM_API const PRM_Type PRM_INT
const char * buffer() const
Definition: UT_String.h:503
static OP_Node * myConstructor(OP_Network *net, const char *name, OP_Operator *entry)
Creates an instance of this node with the given name in the given network.
Definition: VOP_Switch.C:82
const VOP_Language * myLanguage
Definition: VOP_Node.h:1433
virtual void getCode(UT_String &codestr, const VOP_CodeGenContext &context)
Generate the code for this operator.
Definition: VOP_Switch.C:118
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:102
bool enableParm(int pi, int state, int v=-1)
virtual int getInputFromNameSubclass(const UT_String &in) const
Reverse mapping of internal input names to an input index.
Definition: VOP_Switch.C:233
OP_Node * getNode()
OP_Node * getInput(unsigned idx, bool mark_used=false) const
Returns the node connected to a particular input (may be null).
void harden()
Take shallow copy and make it deep.
Definition: UT_String.h:213
virtual void getInputNameSubclass(UT_String &in, int idx) const
Definition: VOP_Switch.C:217
GLuint const GLchar * name
Definition: glcorearb.h:785
static int itoa(char *str, int64 i)
virtual void getInputName(UT_String &in, int idx) const
virtual VOP_Type conditionType(VOP_Type type) const =0
Take an arbitrary type and return the type supported by the language.
unsigned getNodeOutputIndex()
#define OP_FLAG_UNORDERED
Definition: OP_Operator.h:68
bool getInputTypeInfoFromInputNode(VOP_TypeInfo &type_info, int idx, bool grow_inputs_to_idx=false) const
virtual void getInputTypeInfoSubclass(VOP_TypeInfo &type_info, int idx)
Fills in the info about the vop type connected to the idx-th input.
Definition: VOP_Switch.C:249
#define UT_NUMBUF
Definition: UT_Defines.h:24
void getInputTypeInfo(VOP_TypeInfo &type_info, int idx) const
virtual OP_Input * getInputReference(unsigned idx, bool grow)
exint append(void)
Definition: UT_Array.h:95
const char * buffer() const
exint evalInt(int pi, int vi, fpreal t) const
int getConnectedInputIndex(int startAt=-1) const
static PRM_Template myTemplateList[]
Our parameter templates.
Definition: VOP_Switch.h:47
PRM_API PRM_Default PRMzeroDefaults[]
static const char * theChildTableName
Definition: VOP_Node.h:266
virtual bool updateParmsFlags()
Disable our parameters based on which inputs are connected.
Definition: VOP_Switch.C:106
virtual const char * inputLabel(unsigned idx) const
Provides the labels to appear on input and output buttons.
Definition: VOP_Switch.C:190
const char * getToken() const
Definition: PRM_Name.h:40
virtual unsigned orderedInputs() const
Definition: VOP_Switch.C:325