Vuo  2.0.0
VuoMeshParametric.cc
Go to the documentation of this file.
1 
10 #include "VuoMeshParametric.h"
11 #include <muParser/muParser.h>
12 #include "VuoMeshUtility.h"
13 
14 #include "module.h"
15 
16 extern "C"
17 {
18 #ifdef VUO_COMPILER
20  "title" : "VuoMeshParametric",
21  "dependencies" : [
22  "muparser",
23  "VuoMathExpressionParser",
24  "VuoMeshUtility"
25  ]
26  });
27 #endif
28 }
29 
33 VuoMesh VuoMeshParametric_generate(VuoReal time, VuoText xExp, VuoText yExp, VuoText zExp, VuoInteger uSubdivisions, VuoInteger vSubdivisions, bool closeU, VuoReal uMin, VuoReal uMax, bool closeV, VuoReal vMin, VuoReal vMax, VuoDictionary_VuoText_VuoReal *constants)
34 {
35  if (uSubdivisions < 2 || vSubdivisions < 2 || !xExp || !yExp || !zExp)
36  return VuoMesh_make(0);
37 
38  mu::Parser xParser, yParser, zParser;
39 
40  xParser.SetExpr(xExp);
41  yParser.SetExpr(yExp);
42  zParser.SetExpr(zExp);
43 
44  mu::value_type uVar = 0;
45  mu::value_type vVar = 0;
46 
47  xParser.DefineVar("u", &uVar); xParser.DefineVar("U", &uVar);
48  yParser.DefineVar("u", &uVar); yParser.DefineVar("U", &uVar);
49  zParser.DefineVar("u", &uVar); zParser.DefineVar("U", &uVar);
50  xParser.DefineVar("v", &vVar); xParser.DefineVar("V", &vVar);
51  yParser.DefineVar("v", &vVar); yParser.DefineVar("V", &vVar);
52  zParser.DefineVar("v", &vVar); zParser.DefineVar("V", &vVar);
53 
54  mu::value_type iVar = 0;
55  mu::value_type jVar = 0;
56 
57  xParser.DefineVar("i", &iVar); xParser.DefineVar("I", &iVar);
58  yParser.DefineVar("i", &iVar); yParser.DefineVar("I", &iVar);
59  zParser.DefineVar("i", &iVar); zParser.DefineVar("I", &iVar);
60  xParser.DefineVar("j", &jVar); xParser.DefineVar("J", &jVar);
61  yParser.DefineVar("j", &jVar); yParser.DefineVar("J", &jVar);
62  zParser.DefineVar("j", &jVar); zParser.DefineVar("J", &jVar);
63 
64  xParser.DefineConst("time", (double)time); xParser.DefineConst("Time", (double)time); xParser.DefineConst("TIME", (double)time);
65  yParser.DefineConst("time", (double)time); yParser.DefineConst("Time", (double)time); yParser.DefineConst("TIME", (double)time);
66  zParser.DefineConst("time", (double)time); zParser.DefineConst("Time", (double)time); zParser.DefineConst("TIME", (double)time);
67 
71 
72  if (constants)
73  {
74  unsigned long constantCount = VuoListGetCount_VuoText(constants->keys);
75  VuoText *constantKeys = VuoListGetData_VuoText(constants->keys);
76  VuoReal *constantValues = VuoListGetData_VuoReal(constants->values);
77  for (unsigned long i = 0; i < constantCount; ++i)
78  {
79  xParser.DefineConst(constantKeys[i], constantValues[i]);
80  yParser.DefineConst(constantKeys[i], constantValues[i]);
81  zParser.DefineConst(constantKeys[i], constantValues[i]);
82  }
83  }
84 
85  int width = uSubdivisions;
86  int height = vSubdivisions;
87 
88  float ustep = 1./(width-1.), vstep = 1./(height-1.);
89 
90  int vertexCount = width * height;
91 
92  VuoPoint4d *positions = (VuoPoint4d *)malloc(sizeof(VuoPoint4d)*vertexCount);
93  VuoPoint4d *normals = (VuoPoint4d *)malloc(sizeof(VuoPoint4d)*vertexCount);
94  VuoPoint4d *textures = (VuoPoint4d *)malloc(sizeof(VuoPoint4d)*vertexCount);
95 
96  try
97  {
98  int i = 0;
99  float u = 0., v = 0.;
100  for(int y = 0; y < height; y++)
101  {
102  vVar = VuoReal_lerp(vMin, vMax, (closeV && y==height-1) ? 0 : v);
103  for(int x = 0; x < width; x++)
104  {
105  uVar = VuoReal_lerp(uMin, uMax, (closeU && x==width-1) ? 0 : u);
106 
107  iVar = x + 1;
108  jVar = y + 1;
109 
110  positions[i].x = xParser.Eval();
111  positions[i].y = yParser.Eval();
112  positions[i].z = zParser.Eval();
113  positions[i].w = 1.;
114 
115  normals[i].x = 0.;
116  normals[i].y = 0.;
117  normals[i].z = 0.;
118  normals[i].w = 0.;
119 
120  textures[i].x = u;
121  textures[i].y = v;
122  textures[i].z = 0.;
123  textures[i].w = 0.;
124 
125  u += ustep;
126  i++;
127  }
128 
129  u = 0.;
130  v += vstep;
131  }
132  }
133  catch (mu::Parser::exception_type &e)
134  {
135  VUserLog("Error: %s", e.GetMsg().c_str());
136  free(positions);
137  free(normals);
138  free(textures);
139  return VuoMesh_make(0);
140  }
141 
142  // wind triangles
143 
144  width = uSubdivisions-1;
145  height = vSubdivisions-1;
146 
147  unsigned int triangleCount = (width*height)*3*2;
148  unsigned int *triangles = (unsigned int *)malloc(sizeof(unsigned int)*triangleCount);
149 
150  // Prepare an array to count how many neighboring face normals have been added to the vertex normal, so we can divide later to get the average.
151  unsigned int* normalCount = (unsigned int*)calloc(sizeof(unsigned int) * vertexCount, sizeof(unsigned int));
152  for (int i=0;i<vertexCount;++i)
153  normalCount[i] = 0;
154 
155  int index = 0;
156  int one, two, three, four;
157  int row = 0;
158  index = 0;
159 
160  int stride = width+1;
161 
162  for(int y=0;y<height;++y)
163  {
164  for(int x=0;x<width;++x)
165  {
166  one = x + row;
167  two = x+row+1;
168  three = x+row+stride;
169  four = x+row+stride+1;
170 
171  // calculate face normal, add to normals, augment normalCount for subsequent averaging
172  VuoPoint4d faceNormal = VuoMeshUtility_faceNormal(positions[one], positions[two], positions[three]);
173 
174  normals[one] = VuoPoint4d_add(normals[one], faceNormal);
175  normals[two] = VuoPoint4d_add(normals[two], faceNormal);
176  normals[three] = VuoPoint4d_add(normals[three], faceNormal);
177  normals[four] = VuoPoint4d_add(normals[four], faceNormal);
178 
179  normalCount[one]++;
180  normalCount[two]++;
181  normalCount[three]++;
182  normalCount[four]++;
183 
184  if(closeU && x == width-1)
185  {
186  // Add the first face in row normal to right-most vertices
187  VuoPoint4d uNrm = VuoMeshUtility_faceNormal( positions[row], positions[row+1], positions[row+stride] );
188 
189  normals[two] = VuoPoint4d_add(normals[two], uNrm);
190  normals[four] = VuoPoint4d_add(normals[four], uNrm);
191  // And add the current face normal to the origin row vertex normals
192  normals[row] = VuoPoint4d_add(normals[row], faceNormal);
193  normals[row+stride] = VuoPoint4d_add(normals[row+stride], faceNormal);
194 
195  normalCount[two]++;
196  normalCount[four]++;
197  normalCount[row]++;
198  normalCount[row+stride]++;
199  }
200 
201  if(closeV && y==height-1)
202  {
203  VuoPoint4d vNrm = VuoMeshUtility_faceNormal( positions[x], positions[x+1], positions[x+stride] );
204 
205  normals[three] = VuoPoint4d_add(normals[three], vNrm);
206  normals[four] = VuoPoint4d_add(normals[four], vNrm);
207  normals[x] = VuoPoint4d_add(normals[x], faceNormal);
208  normals[x+1] = VuoPoint4d_add(normals[x+1], faceNormal);
209 
210  normalCount[three]++;
211  normalCount[four]++;
212  normalCount[x]++;
213  normalCount[x+1]++;
214  }
215 
216  // Elements are wound to be front-facing for Vuo's right-handed coordinate system.
217  // Order the elements so that the diagonal edge of each triangle
218  // is last, so that vuo.shader.make.wireframe can optionally omit them.
219  triangles[index+0] = three;
220  triangles[index+1] = one;
221  triangles[index+2] = two;
222  triangles[index+3] = two;
223  triangles[index+4] = four;
224  triangles[index+5] = three;
225 
226  index += 6;
227  }
228  row += stride;
229  }
230 
231  // average normals
232  for(int i = 0; i < vertexCount; i++)
233  {
234  normals[i] = VuoPoint4d_multiply(normals[i], 1./(double)normalCount[i]);
235  }
236  free(normalCount);
237 
238  VuoSubmesh submesh = VuoSubmesh_makeFromBuffers(vertexCount,
239  positions, normals, NULL, NULL, textures,
240  triangleCount, triangles, VuoMesh_IndividualTriangles);
241 
243 
244  return VuoMesh_makeFromSingleSubmesh(submesh);
245 }