HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cvexsample.C
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2024
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  * Sample of the CVEX interface to call VEX.
27  *
28  * CVEX is most efficient when operating on arrays of data. The interface
29  * allows you to create a VEX function to perform some computation. Instead of
30  * hard-coding the algorithm in your C++ code, you can alter the algorithm by
31  * running different VEX code. It allows flexibility in design of your code.
32  */
33 
34 #include <CVEX/CVEX_Context.h>
35 #include <UT/UT_Main.h>
36 #include <UT/UT_Vector3.h>
37 
38 namespace HDK_Sample {
39 
40 // This is the array length for the sample program.
41 #define CV_SIZE 8
42 
43 // Static methods to fill input variables to the VEX function
44 static void
45 fillP(UT_Vector3 *P)
46 {
47  int i;
48  fpreal t;
49  for (i = 0; i < CV_SIZE; i++)
50  {
51  t = (fpreal)i / (CV_SIZE-1);
52  P[i].assign(t, SYSsin(t*M_PI), 0);
53  }
54 }
55 
56 static void
57 fillN(UT_Vector3 *N)
58 {
59  int i;
60  for (i = 0; i < CV_SIZE; i++)
61  N[i].assign(0, 1, 0);
62 }
63 
64 static void
65 fillST(fpreal32 *s, fpreal32 *t)
66 {
67  int i;
68  for (i = 0; i < CV_SIZE; i++)
69  {
70  s[i] = (fpreal)i / (CV_SIZE-1);
71  t[i] = 1-s[i];
72  }
73 }
74 
75 //
76 // Convenience methods to print output from the function
77 //
78 static void
79 dumpFloat(const fpreal32 *v, int n)
80 {
81  int i;
82 
83  printf("%g", v[0]);
84  for (i = 1; i < n; i++)
85  printf(", %g", v[i]);
86 }
87 
88 static void
89 dumpVector(const UT_Vector3 *v, int n)
90 {
91  int i;
92  printf("{%g,%g,%g}", v[0].x(), v[0].y(), v[0].z());
93  for (i = 1; i < n; i++)
94  printf(", {%g,%g,%g}", v[i].x(), v[i].y(), v[i].z());
95 }
96 
97 static void
98 dumpValue(CVEX_Value *value)
99 {
100  if (!value || !value->isExport())
101  return;
102  printf("%s = [", (const char *) value->getName());
103  switch (value->getType())
104  {
105  case CVEX_TYPE_FLOAT:
106  dumpFloat((fpreal32 *)value->getRawData(), value->getArraySize());
107  break;
108  case CVEX_TYPE_VECTOR3:
109  dumpVector((UT_Vector3 *)value->getRawData(), value->getArraySize());
110  break;
111  default:
112  printf("No output supported currently\n");
113  }
114  printf("]\n");
115 }
116 
117 static void
118 dumpValueList(const char *label, CVEX_ValueList &list)
119 {
120  int i;
121  CVEX_Value *value;
122  printf("%s:\n", label);
123  for (i = 0; i < list.entries(); i++)
124  {
125  value = list.getValue(i);
126  printf("\t%2d.", i+1);
127  if (value->isExport())
128  printf("export ");
129  switch (value->getType())
130  {
131  case CVEX_TYPE_INTEGER: printf("int"); break;
132  case CVEX_TYPE_FLOAT: printf("float"); break;
133  case CVEX_TYPE_VECTOR3: printf("vector"); break;
134  case CVEX_TYPE_VECTOR4: printf("vector4"); break;
135  case CVEX_TYPE_MATRIX3: printf("matrix3"); break;
136  case CVEX_TYPE_MATRIX4: printf("matrix"); break;
137  case CVEX_TYPE_STRING: printf("string"); break;
138  default: printf("unknown"); break;
139  }
140  printf(" %s[%d]\n", (const char *) value->getName(), value->getArraySize());
141  }
142 }
143 }
144 
145 using namespace HDK_Sample;
146 
147 int
148 theMain(int argc, char *argv[])
149 {
150  CVEX_Context cvex;
151 
152  // Define storage for the input parameters to the CVEX function. If the
153  // CVEX function accesses these variables by name, we need to make sure
154  // they are initialized. Any parameters which aren't "bound" by inputs,
155  // will be handled by the parameters the user specifies.
156  UT_Vector3 P[CV_SIZE];
157  UT_Vector3 N[CV_SIZE];
158  fpreal32 s[CV_SIZE], t[CV_SIZE];
160  int32 seed = 1;
161  CVEX_StringArray map;
162 
163  // When parameters are declared as exports, we can grab the data as
164  // computed by VEX. These buffers are used to store the output of the Cf
165  // and Of export parameters.
166  UT_Vector3 Cf[CV_SIZE];
167  UT_Vector3 Of[CV_SIZE];
168 
169  // Before we load the VEX function, we need to declare which variables are
170  // defined as input parameters. We can do "lazy" assignment, or
171  // pre-computed assignment. Lazy assignment just declares the variable
172  // without specifying its value.
173  //
174  // Declare P, N, s, and t without computing their values.
175  cvex.addInput("P", CVEX_TYPE_VECTOR3, true);
176  cvex.addInput("N", CVEX_TYPE_VECTOR3, true);
177  cvex.addInput("s", CVEX_TYPE_FLOAT, true);
178  cvex.addInput("t", CVEX_TYPE_FLOAT, true);
179 
180  //
181  // Declare parameters which have values automatically assigned. This is
182  // more of a convenience for simple parameters.
183  map.append("Mandril.pic");
184  memset(zero, 0, sizeof(zero));
185  // seed is a "uniform" variable -- it has a single value
186  // zero is a "varying" variable -- it has a different value for each
187  // element of the array. Well, not actually, but it could.
188  // map is a "uniform" variable since there is only one string in the array
189  cvex.addInput("seed", CVEX_TYPE_INTEGER, &seed, 1);
190  cvex.addInput("zero", CVEX_TYPE_FLOAT, zero, CV_SIZE);
191  cvex.addInput("map", map);
192 
193  // Load the VEX function
194  if (!cvex.load(argc-1, argv+1))
195  {
196  fprintf(stderr, "Unable to load cvex function: %s\n", argv[1]);
197  return 1;
198  }
199 
200  // Now that the function is loaded, we can find out all sorts of
201  // information about the function.
202  dumpValueList("Input Parameters", cvex.getInputList());
203  dumpValueList("Output Parameters", cvex.getOutputList());
204 
205  // Now, we need to initialize the variables we declared. But we only have
206  // to do this if the variable was specified in the VEX function.
207  CVEX_Value *Pval, *Nval, *sval, *tval;
208  Pval = cvex.findInput("P", CVEX_TYPE_VECTOR3);
209  Nval = cvex.findInput("N", CVEX_TYPE_VECTOR3);
210  sval = cvex.findInput("s", CVEX_TYPE_FLOAT);
211  tval = cvex.findInput("t", CVEX_TYPE_FLOAT);
212 
213  if (Pval)
214  {
215  fillP(P); // Initialize P
216  Pval->setTypedData(P, CV_SIZE); // Set the parameter value
217  }
218  if (Nval)
219  {
220  fillN(N);
221  Nval->setTypedData(N, CV_SIZE);
222  }
223  if (sval || tval)
224  {
225  fillST(s, t);
226  if (sval) sval->setTypedData(s, CV_SIZE);
227  if (tval) tval->setTypedData(t, CV_SIZE);
228  }
229 
230  // We can also find exported parameters.
231  CVEX_Value *CfVal, *OfVal, *sout, *tout;
232 
233  CfVal = cvex.findOutput("Cf", CVEX_TYPE_VECTOR3);
234  OfVal = cvex.findOutput("Of", CVEX_TYPE_VECTOR3);
235 
236  // When an input parameter (like P, N, s or t) is specified as an export
237  // parameter, CVEX will _not_ modify the data buffer assigned to the input
238  // value.
239  sout = cvex.findOutput("s", CVEX_TYPE_FLOAT);
240  tout = cvex.findOutput("t", CVEX_TYPE_FLOAT);
241 
242  if (!CfVal && !OfVal)
243  fprintf(stderr, "%s doesn't seem to write to Cf or Of\n", argv[1]);
244 
245  if (CfVal)
246  CfVal->setTypedData(Cf, CV_SIZE);
247  if (OfVal)
248  OfVal->setTypedData(Of, CV_SIZE);
249 
250  // To get the output value, you need to grab the output variable and set
251  // its data. You can think of input variables as being "const" for the VEX
252  // function. You can obviously have VEX write to a different buffer, or it
253  // can overwrite the input buffer (like below)
254  if (sout)
255  sout->setTypedData(s, CV_SIZE);
256  if (tout)
257  tout->setTypedData(t, CV_SIZE);
258 
259  // Now, call VEX
260  printf("Calling VEX ----------------------------\n\n");
261  cvex.run(CV_SIZE, false);
262  printf("\n\nFinished VEX ----------------------------\n");
263 
264  // And print out the output values
265  dumpValue(CfVal);
266  dumpValue(OfVal);
267  dumpValue(sout);
268  dumpValue(tout);
269 
270  return 0;
271 }
CVEX_ValueListT< PREC > & getInputList()
Definition: CVEX_Context.h:314
int int32
Definition: SYS_Types.h:39
GLuint GLsizei const GLchar * label
Definition: glcorearb.h:2545
bool addInput(const UT_StringHolder &name, CVEX_Type type, bool varying)
CVEX_Type getType() const
Query type of VEX value.
Definition: CVEX_Value.h:71
const GLdouble * v
Definition: glcorearb.h:837
auto printf(const S &fmt, const T &...args) -> int
Definition: printf.h:626
#define M_PI
Definition: fmath.h:90
GLsizei const GLfloat * value
Definition: glcorearb.h:824
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:848
GLdouble s
Definition: glad.h:3009
const CVEX_ValueT< PREC > * findOutput(const UT_StringRef &name, CVEX_Type type) const
Find an output by name/type.
Definition: CVEX_Context.h:340
#define CV_SIZE
Definition: cvexsample.C:41
GLint y
Definition: glcorearb.h:103
const UT_StringHolder & getName() const
Query name of VEX value.
Definition: CVEX_Value.h:69
float fpreal32
Definition: SYS_Types.h:200
int getArraySize() const
Definition: CVEX_Value.h:80
List of input or output values for a CVEX_Context.
A class representing a VEX value.
Definition: CVEX_Value.h:60
bool setTypedData(VEXint< PREC > *data, int array_size)
GLdouble n
Definition: glcorearb.h:2008
const CVEX_ValueT< PREC > * findInput(const UT_StringRef &name, CVEX_Type type) const
Find an input by name/type.
Definition: CVEX_Context.h:318
int entries() const
bool run(int array_size, bool interruptable, CVEX_RunDataT< PREC > *rundata=nullptr)
GLint GLenum GLint x
Definition: glcorearb.h:409
exint append()
Definition: UT_Array.h:142
auto fprintf(std::FILE *f, const S &fmt, const T &...args) -> int
Definition: printf.h:602
GLdouble t
Definition: glad.h:2397
void assign(T xx=0.0f, T yy=0.0f, T zz=0.0f)
Set the values of the vector components.
Definition: UT_Vector3.h:694
UT_MAIN(theMain)
const CVEX_ValueListT< PREC > & getOutputList() const
Definition: CVEX_Context.h:336
bool isExport() const
Query whether the VEX value is an export (or read-only)
Definition: CVEX_Value.h:74
void * getRawData()
Definition: CVEX_Value.h:94
fpreal64 fpreal
Definition: SYS_Types.h:277
int theMain(int argc, char *argv[])
Definition: cvexsample.C:148
const CVEX_ValueT< PREC > * getValue(int i) const
Get a value by index.
GA_API const UT_StringHolder N
Definition: core.h:1131
bool load(int argc, const char *const argv[])
Call VEX from C++.
Definition: CVEX_Context.h:203
ImageBuf OIIO_API zero(ROI roi, int nthreads=0)