HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
VOP_Switch.C
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2025
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 *
191 {
192  UT_ASSERT(idx >= 0);
193  if (idx >= orderedInputs())
194  {
195  static UT_String theLabel;
196  char numstr[UT_NUMBUF];
197 
198  // Inputs after the first one are just numbered starting at 1.
199  theLabel = "Input Number ";
200  UT_String::itoa(numstr, idx + 1 - orderedInputs());
201  theLabel += numstr;
202 
203  return theLabel;
204  }
205  else
206  return theSwitcherName.getLabel();
207 }
208 
209 const char *
211 {
212  UT_ASSERT(idx == 0);
213 
214  return "Chosen Value";
215 }
216 
217 void
219 {
220  if (idx >= orderedInputs())
221  {
222  char numstr[UT_NUMBUF];
223 
224  // Inputs after the first one are just numbered starting at 1.
225  in = theInputRoot;
226  UT_String::itoa(numstr, idx + 1 - orderedInputs());
227  in += numstr;
228  }
229  else
230  in = theSwitcherName.getToken();
231 }
232 
233 int
235 {
236  int inputnum = -1;
237 
238  // The switcher input is always first.
239  if( in == theSwitcherName.getToken() )
240  return 0;
241 
242  // Use the numeric suffix on the input name to determine the input index.
243  if( !strncmp(in, theInputRoot, strlen(theInputRoot)) )
244  inputnum = ::atoi((const char *)in + strlen(theInputRoot));
245 
246  return inputnum - 1 + orderedInputs();
247 }
248 
249 void
251 {
252  // For any input past our ordered inputs, all input types are the
253  // same - whatever is plugged into the first variable input.
254  if( idx >= orderedInputs() )
255  // Helper method, which essentially invokes
256  // vop->getOutputTypeInfo( type_info, input->getNodeOutputIndex() );
257  // on the input vop node
259  else
261 }
262 
263 void
265  VOP_VopTypeInfoArray &type_infos)
266 {
267  VOP_Node *vop;
268  OP_Input *input;
269 
270  if( idx >= orderedInputs() )
271  {
272  // For any input past our ordered inputs, all input types are the
273  // same - whatever is plugged into the first variable input.
274  if( (input = getInputReference(orderedInputs(), 0)) )
275  {
276  vop = CAST_VOPNODE(input->getNode());
277  if( vop )
278  {
279  VOP_TypeInfo type_info;
280 
281  vop->getOutputTypeInfo(type_info, input->getNodeOutputIndex());
282  type_infos.append(type_info);
283  }
284  }
285  }
286  else
287  {
288  VOP_TypeInfo type_info(VOP_TYPE_INTEGER);
289  type_info.conditionType(*myLanguage);
290  type_infos.append(type_info);
291  }
292 }
293 
294 void
296 {
297  UT_ASSERT(idx == 0);
298 
299  name = theOutputName;
300 }
301 
302 void
304 {
305  UT_ASSERT(idx == 0);
306 
307  // The output data type is the same as the data type of the first
308  // input after the switch index.
309  getInputTypeInfo(type_info, orderedInputs());
310 }
311 
312 unsigned
314 {
315  int max = nInputs();
316 
317  // Make sure there is always exactly one unconnected unordered input
318  // visible.
319  if( max < orderedInputs() )
320  max = orderedInputs();
321 
322  return max + 1;
323 }
324 
325 unsigned
327 {
328  // The first input (corresponding to the switch index) must always be
329  // visible.
330  return 1;
331 }
332 
333 int
335 {
336  return evalInt(theOutOfBoundsName, 0, 0.0f);
337 }
338 
GLint first
Definition: glcorearb.h:405
void getOutputNameSubclass(UT_String &out, int idx) const override
Definition: VOP_Switch.C:295
void newVopOperator(OP_OperatorTable *table)
Definition: VOP_Switch.C:38
int OP_InputIdx
Definition: OP_DataTypes.h:184
#define VOP_VARIABLE_INOUT_MAX
Definition: VOP_Node.h:59
bool updateParmsFlags() override
PRM_API const PRM_Type PRM_ORD
SYS_FORCE_INLINE const char * buffer() const
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
void getInputNameSubclass(UT_String &in, int idx) const override
Definition: VOP_Switch.C:218
void getInputName(UT_String &in, int idx) const override
bool addOperator(OP_Operator *op, std::ostream *err=nullptr)
const char * getLabel() const
Definition: PRM_Name.h:83
void getAllowedInputTypeInfosSubclass(unsigned idx, VOP_VopTypeInfoArray &type_infos) override
Definition: VOP_Switch.C:264
const UT_WorkBuffer & str()
Returns a read-only reference to the underlying UT_WorkBuffer.
void getOutputName(UT_String &out, int idx) const override
constexpr auto in(type t, int set) -> bool
Definition: core.h:611
~VOP_Switch() override
Definition: VOP_Switch.C:101
void getOutputTypeInfo(VOP_TypeInfo &type_info, int idx) const
virtual unsigned nInputs() const
void getOutputTypeInfoSubclass(VOP_TypeInfo &type_info, int idx) override
Fills out the info about the data type of each output connector.
Definition: VOP_Switch.C:303
PRM_API const PRM_Type PRM_INT
unsigned getNumVisibleInputs() const override
Controls the number of input buttons visible on the node tile.
Definition: VOP_Switch.C:313
const char * buffer() const
Definition: UT_String.h:516
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
GLfloat f
Definition: glcorearb.h:1926
const VOP_Language * myLanguage
Definition: VOP_Node.h:1576
const char * inputLabel(OP_InputIdx idx) const override
Provides the labels to appear on input and output buttons.
Definition: VOP_Switch.C:190
void getInputTypeInfoSubclass(VOP_TypeInfo &type_info, int idx) override
Fills in the info about the vop type connected to the idx-th input.
Definition: VOP_Switch.C:250
bool enableParm(int pi, int state, int v=-1)
bool updateParmsFlags() override
Disable our parameters based on which inputs are connected.
Definition: VOP_Switch.C:106
OP_Node * getNode()
void harden()
Take shallow copy and make it deep.
Definition: UT_String.h:222
void getCode(UT_String &codestr, const VOP_CodeGenContext &context) override
Generate the code for this operator.
Definition: VOP_Switch.C:118
constexpr UT_StringLit theOutputName
Definition: APEX_Names.h:27
unsigned orderedInputs() const override
Definition: VOP_Switch.C:326
GLuint const GLchar * name
Definition: glcorearb.h:786
GLenum GLenum GLsizei void * table
Definition: glad.h:5129
static int itoa(char *str, int64 i)
exint append()
Definition: UT_Array.h:142
GLint j
Definition: glad.h:2733
OP_Node * getInput(OP_InputIdx idx, bool mark_used=false) const
Returns the node connected to a particular input (may be null).
virtual VOP_Type conditionType(VOP_Type type) const =0
Take an arbitrary type and return the type supported by the language.
#define OP_FLAG_UNORDERED
Definition: OP_Operator.h:83
bool getInputTypeInfoFromInputNode(VOP_TypeInfo &type_info, int idx, bool grow_inputs_to_idx=false) const
#define UT_NUMBUF
Definition: UT_Defines.h:24
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
void getInputTypeInfo(VOP_TypeInfo &type_info, int idx) const
int OP_OutputIdx
Definition: OP_DataTypes.h:185
OP_OutputIdx getNodeOutputIndex()
const char * outputLabel(OP_OutputIdx idx) const override
Definition: VOP_Switch.C:210
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
exint evalInt(int pi, int vi, fpreal t) 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:270
int getInputFromNameSubclass(const UT_String &in) const override
Reverse mapping of internal input names to an input index.
Definition: VOP_Switch.C:234
virtual OP_Input * getInputReference(OP_InputIdx idx, bool grow)
const char * getToken() const
Definition: PRM_Name.h:79
OP_InputIdx getConnectedInputIndex(OP_InputIdx start_at=-1) const