HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SNOW_Solver.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  */
27 
28 #include "SNOW_Solver.h"
29 
30 #include <SIM/SIM_Engine.h>
31 #include <SIM/SIM_Options.h>
32 #include <SIM/SIM_Object.h>
33 #include <SIM/SIM_ObjectArray.h>
34 #include <SIM/SIM_DopDescription.h>
35 #include <SIM/SIM_Random.h>
36 #include <SIM/SIM_RandomTwister.h>
37 #include <SIM/SIM_Position.h>
38 #include <SIM/SIM_PRMShared.h>
39 #include <SIM/SIM_Guide.h>
40 #include <SIM/SIM_GuideShared.h>
41 #include <GU/GU_Detail.h>
42 #include <GU/GU_PrimPart.h>
43 #include <GU/GU_RayIntersect.h>
44 #include <GEO/GEO_PrimPoly.h>
45 #include <GA/GA_Handle.h>
46 #include <GA/GA_Types.h>
47 #include <PRM/PRM_Include.h>
48 #include <UT/UT_DSOVersion.h>
49 #include <UT/UT_Map.h>
50 #include <UT/UT_StringStream.h>
51 #include <UT/UT_Vector3.h>
52 #include <UT/UT_WorkBuffer.h>
53 #include <SYS/SYS_Floor.h>
54 #include <SYS/SYS_Math.h>
55 
56 
57 using namespace HDK_Sample;
58 
59 
61  : BaseClass(factory),
63 {
64 }
65 
67 {
68 }
69 
70 const SIM_DopDescription *
71 SNOW_Solver::getSolverSNOWDopDescription()
72 {
73  static PRM_Name theBirthRateName(SIM_NAME_BIRTHRATE, "Birth Rate");
74  static PRM_Name theOriginalDepthName(SIM_NAME_ORIGINALDEPTH, "Original Depth");
75 
76  static PRM_Template theTemplates[] = {
77  PRM_Template(PRM_FLT_J, 1, &theBirthRateName, PRMpointOneDefaults),
78  PRM_Template(PRM_INT_J, 1, &theOriginalDepthName),
79  PRM_Template()
80  };
81 
82  static SIM_DopDescription theDopDescription(true,
83  "hdk_snowsolver",
84  "SNOW Solver",
86  classname(),
87  theTemplates);
88 
89  return &theDopDescription;
90 }
91 
92 SIM_Random *
94 {
95  SIM_Random *rand = 0;
96 
97  // Create the random data as subdata attached to the solver. First
98  // we look for any existing SIM_Random. If none is found, we create
99  // a SIM_RandomTwister.
100  rand = SIM_DATA_GET(*obj, "Random", SIM_Random);
101  if( !rand )
102  rand = SIM_DATA_CREATE(*obj, "Random", SIM_RandomTwister, 0);
103 
104  return rand;
105 }
106 
107 bool
108 SNOW_Solver::brownianize(int &v, int dv, int max, SIM_Random *rand) const
109 {
110  if (dv)
111  {
112  v += dv;
113  if (v < 0 || v >= max)
114  return false;
115  }
116  else
117  {
118  v += rand_choice(3, rand) - 1;
119  if (v < 0)
120  v = 0;
121  if (v >= max)
122  v = max - 1;
123  }
124 
125  return true;
126 }
127 
128 int
130  int sx, int sy, int sz,
131  int dx, int dy, int dz,
132  int &rx, int &ry, int &rz,
133  int maxdist,
134  SIM_Random *rand) const
135 {
136  UT_Vector3 div = snow.getDivisions();
137  int xdiv = (int)div.x();
138  int ydiv = (int)div.y();
139  int zdiv = (int)div.z();
140 
141  int dist = 0;
142  while (1)
143  {
144  // Assume our current location is invalid. Try one step.
145  if (!brownianize(sx, dx, xdiv, rand))
146  return maxdist;
147  if (!brownianize(sy, dy, ydiv, rand))
148  return maxdist;
149  if (!brownianize(sz, dz, zdiv, rand))
150  return maxdist;
151 
152  // Now, see if we are suddenly valid.
153  if (snow.getVoxel(sx, sy, sz) == VOXEL_EMPTY)
154  {
155  break;
156  }
157 
158  dist++;
159  }
160 
161  rx = sx;
162  ry = sy;
163  rz = sz;
164  return dist;
165 }
166 
167 // Assumes that x,y,z had a piece of snow. Will find a new home
168 // for this snow.
169 void
171  int x, int y, int z, SIM_Random *rand) const
172 {
173  // There are 6 primary axes for snow to be distributed along.
174  // The snow tries all 6 directions, and moves in the one that
175  // has the shortest path.
176 
177  int end_x[6], end_y[6], end_z[6], dist[6];
178 
179  int dxvals[6] = { -1, 0, 0, 1, 0, 0 };
180  int dyvals[6] = { 0, -1, 1, 0, 0, 0 };
181  int dzvals[6] = { 0, 0, 0, 0, 1, -1 };
182  int direction, mindir, mindist = 320000;
183 
184  for (direction = 0; direction < 6; direction++)
185  {
186  dist[direction] =
187  clearInDirection(snow,
188  x, y, z,
189  dxvals[direction], dyvals[direction], dzvals[direction],
190  end_x[direction], end_y[direction], end_z[direction],
191  mindist,
192  rand);
193 
194  if (dist[direction] < mindist)
195  {
196  mindir = direction;
197  mindist = dist[direction];
198  }
199  }
200 
201  if (mindist == 320000)
202  {
203  // Complete failure!
204  UT_ASSERT(!"No snow removal possible!");
205  }
206  else
207  {
208  // Store in the resulting position...
209  snow.setVoxel(VOXEL_SNOW, end_x[mindir], end_y[mindir], end_z[mindir]);
210  }
211 }
212 
213 int
214 SNOW_Solver::rand_choice(int numchoice, SIM_Random *rand) const
215 {
216  int choice = rand->choice(numchoice);
217  return choice;
218 }
219 
220 void
222  fpreal startx, fpreal endx,
223  int y, int z,
224  u8 voxeltype,
225  SIM_Random *rand) const
226 {
227  UT_Vector3 div = snow.getDivisions();
228  int xdiv = (int)div.x();
229 
230  int sx = (int)(startx * xdiv);
231  int ex = (int)(endx * xdiv);
232  if (sx < 0) sx = 0;
233  if (sx >= xdiv) return;
234  if (ex < 0) return;
235  if (ex >= xdiv) ex = xdiv - 1;
236 
237  if (voxeltype == VOXEL_OBJECT)
238  {
239  for (int x = sx; x < ex; x++)
240  {
241  // Set this voxel. TODO: Move away snow!
242  if (snow.getVoxel(x, y, z) == VOXEL_SNOW)
243  clearSnow(snow, x, y, z, rand);
244  snow.setVoxel(VOXEL_OBJECT, x, y, z);
245  }
246  }
247  else if (voxeltype == VOXEL_SNOW)
248  {
249  for (int x = sx; x < ex; x++)
250  {
251  snow.setVoxel(VOXEL_SNOW, x, y, z);
252  }
253  }
254 }
255 
256 void
258  const GU_ConstDetailHandle &gdh,
259  const UT_DMatrix4 &xform,
260  u8 voxeltype,
261  SIM_Random *rand) const
262 {
263  if (!gdh.isNull())
264  {
266  const GU_Detail *gdp = gdl.getGdp();
267 
268  UT_Vector3 div = snow.getDivisions();
269  int xdiv = (int)div.x();
270  int ydiv = (int)div.y();
271  int zdiv = (int)div.z();
272 
273  UT_Matrix4 fxform;
274  fxform = xform;
275  fxform.invert();
276 
277  UT_BoundingBox bbox;
278  gdp->getBBox(&bbox);
279  bbox.transform(fxform);
280 
281  // Find where this is at least valid...
282  // Find the range of the bounding box - we only need
283  // to search this part of the voxel array.
284  int bminx = (int)SYSfloor(bbox(0, 0) * (xdiv + 1));
285  if (bminx < 0) bminx = 0;
286  int bmaxx = (int)SYSceil(bbox(0, 1) * (xdiv + 1));
287  if (bmaxx >= xdiv) bmaxx = xdiv-1;
288  int bminy = (int)SYSfloor(bbox(1, 0) * (ydiv + 1));
289  if (bminy < 0) bminy = 0;
290  int bmaxy = (int)SYSceil(bbox(1, 1) * (ydiv + 1));
291  if (bmaxy >= ydiv) bmaxy = ydiv-1;
292  int bminz = (int)SYSfloor(bbox(2, 0) * (zdiv + 1));
293  if (bminz < 0) bminz = 0;
294  int bmaxz = (int)SYSceil(bbox(2, 1) * (zdiv + 1));
295  if (bmaxz >= zdiv) bmaxz = zdiv-1;
296 
297  // Build the ray intersect cache.
298  GU_RayIntersect *isect = new GU_RayIntersect(gdp);
299 
300  // We build downwards so snow tends to
301  // compact.
302  UT_Vector3 orig;
303  orig.x() = 0.0;
304  UT_Vector3 dir(1.0, 0.0, 0.0);
305  UT_Vector3 xdir(dir);
306  xdir.multiply3(xform);
307 
308  GU_RayInfo hitinfo;
309  for (int z = bmaxz; z >= bminz; z--)
310  {
311  orig.z() = (z + 0.5) / (zdiv + 1);
312  for (int y = bminy; y <= bmaxy; y++)
313  {
314  orig.y() = (y + 0.5) / (ydiv + 1);
315  hitinfo.reset();
316 
317  UT_Vector3 xorig(orig);
318  xorig *= xform;
319 
320  hitinfo.init(1.0, 0.0, GU_FIND_ALL, 1e-4);
321 
322  int numhit = isect->sendRay(xorig, xdir, hitinfo);
323 
324  // -1 means interrupt from user.
325  if (numhit < 0)
326  return;
327 
328  // Even if there were no hits, we may still be entirely
329  // inside the object.
330  numhit = hitinfo.myHitList->entries();
331 
332  // Now, walk through each hit...
333  // First "hit" occurs at position zero. Last "hit"
334  // occurs at position 1.
335  fpreal lt = 0.0;
336 
337  for (int hitnum = 0; hitnum <= numhit; hitnum++)
338  {
339  fpreal t;
340  if (hitnum < numhit)
341  t = (*hitinfo.myHitList)(hitnum).t;
342  else
343  t = 1.0;
344 
345  // Determine if the lt - t segment is inside or not.
346  UT_Vector3 pos(orig);
347  pos.x() = (t + lt) / 2.0;
348  UT_Vector3 xpos(pos);
349  xpos *= xform;
350  if (isect->isInsideWinding(xpos, 0))
351  {
352  fillRow(snow, lt, t, y, z, voxeltype, rand);
353  }
354 
355  lt = t;
356  }
357  }
358  }
359 
360  delete isect;
361  }
362 }
363 
364 void
365 SNOW_Solver::solveForObject(SIM_Object &object,
366  SNOW_VoxelArray &snow,
367  const SIM_Time & /*timestep*/) const
368 {
369  // Birth new snow at top.
370  SIM_Random *rand = createRandomData(&object);
371 
372  UT_Vector3 div = snow.getDivisions();
373  int xdiv = (int)div.x();
374  int ydiv = (int)div.y();
375  int zdiv = (int)div.z();
376 
377  UT_Vector3 center = snow.getCenter();
378  UT_Vector3 size = snow.getSize();
379  UT_DMatrix4 tosnow;
380 
381  tosnow.identity();
382  tosnow.scale(size.x(), size.y(), size.z());
383  tosnow.pretranslate(-0.5, -0.5, -0.5);
384  tosnow.translate(center.x(), center.y(), center.z());
385 
386  fpreal birthrate = getBirthRate();
387 
388  // Update according to the possibly changed intersection information.
389  const SIM_Geometry *geometry = 0;
390 
391  // First, clear out all old intersection information.
392  for (int z = 0; z < zdiv; z++)
393  {
394  for (int y = 0; y <= ydiv; y++)
395  {
396  for (int x = 0; x <= xdiv; x++)
397  {
398  if (snow.getVoxel(x, y, z) == VOXEL_OBJECT)
399  snow.setVoxel(VOXEL_EMPTY, x, y, z);
400  }
401  }
402  }
403 
404  // Run through each affector looking for source generators...
405  SIM_ObjectArray sourceaffectors;
406  SIM_ColliderInfoArray colliderinfo;
407  UT_String sourceobjects;
408 
409  object.getAffectors(sourceaffectors, "SIM_RelationshipSource");
410  int n = sourceaffectors.entries();
411  for (int i = 0; i < n; i++)
412  {
413  const SIM_Object *affector = sourceaffectors(i);
414  const SIM_Position *pos = affector->getPosition();
415  UT_DMatrix4 xform, worldtogeo;
416 
417  geometry = affector->getGeometry();
418  // Ignore people that don't have a "geometry" field.
419  if (!geometry)
420  continue;
421 
422  geometry->getTransform(xform);
423  xform.invert();
424  if (pos)
425  {
426  pos->getInverseTransform(worldtogeo);
427  xform = worldtogeo * xform;
428  }
429 
430  xform = tosnow * xform;
431 
432  applyGeometry(snow, geometry->getGeometry(), xform, VOXEL_SNOW, rand);
433  }
434 
435  // Run through each affector looking for geometry data...
436  object.getColliderInfo(colliderinfo);
437  n = colliderinfo.entries();
438  for (int i = 0; i < n; i++)
439  {
440  const SIM_Object *affector = colliderinfo(i).getAffector();
441  const SIM_Position *pos = affector->getPosition();
442  UT_DMatrix4 xform, worldtogeo;
443 
444  geometry = affector->getGeometry();
445  // Ignore people that don't have a "geometry" field.
446  if (!geometry)
447  continue;
448 
449  geometry->getTransform(xform);
450  xform.invert();
451  if (pos)
452  {
453  pos->getInverseTransform(worldtogeo);
454  xform = worldtogeo * xform;
455  }
456  xform = tosnow * xform;
457 
458  applyGeometry(snow, geometry->getGeometry(), xform, VOXEL_OBJECT, rand);
459  }
460 
461  // Birth new snow at the top of the box.
462  if (!SYSequalZero(birthrate))
463  for (int y = 0; y < ydiv; y++)
464  {
465  for (int x = 0; x < xdiv; x++)
466  {
467  if (rand->frandom() < birthrate)
468  {
469  snow.setVoxel(VOXEL_SNOW, x, y, zdiv-1);
470  }
471  }
472  }
473 
474  int dxvals[9] = { -1, -1, -1, 0, 0, 0, 1, 1, 1 };
475  int dyvals[9] = { -1, 0, 1, -1, 0, 1, -1, 0, 1 };
476  int validdxidx[9];
477  int numdxidx, dxidx;
478 
479  // And move everything down one level...
480 #if 1
481  for (int z = 1; z < zdiv; z++)
482  {
483  // If this snow voxel is set to 1, we want to try and move it down
484  // to z-1.
485  // We don't want to be too consistent with our direction or we'll
486  // induce a strong bias. Thus we reverse our loops depending
487  // on z value.
488  int yend, ystart, yinc;
489  int xend, xstart, xinc;
490 
491  if (z & 1)
492  {
493  ystart = 0;
494  yend = ydiv;
495  yinc = 1;
496  xstart = 0;
497  xend = xdiv;
498  xinc = 1;
499  }
500  else
501  {
502  ystart = ydiv-1;
503  yend = -1;
504  yinc = -1;
505  xstart = xdiv-1;
506  xend = -1;
507  xinc = -1;
508  }
509 
510  for (int y = ystart; y != yend; y += yinc)
511  {
512  for (int x = xstart; x != xend; x += xinc)
513  {
514  if (snow.getVoxel(x, y, z) == VOXEL_SNOW)
515  {
516  // Try all dx combinations.
517  numdxidx = 0;
518  for (dxidx = 0; dxidx < 9; dxidx++)
519  {
520  if (snow.getVoxel(x + dxvals[dxidx],
521  y + dyvals[dxidx],
522  z-1) == VOXEL_EMPTY)
523  {
524  validdxidx[numdxidx++] = dxidx;
525  }
526  }
527 
528  if (numdxidx)
529  {
530  dxidx = rand_choice(numdxidx, rand);
531 
532  dxidx = validdxidx[dxidx];
533 
534  // We can successfully move...
535  snow.setVoxel(VOXEL_EMPTY, x, y, z);
536  UT_ASSERT(snow.getVoxel(x + dxvals[dxidx],
537  y + dyvals[dxidx],
538  z-1) == VOXEL_EMPTY);
539  snow.setVoxel(VOXEL_SNOW, x + dxvals[dxidx],
540  y + dyvals[dxidx],
541  z-1);
542  }
543  }
544  }
545  }
546  }
547 #endif
548 
549  // Now we want to auto-collapse anything that is constant.
550  snow.collapseAllTiles();
551  snow.pubHandleModification();
552 }
553 
554 void
555 SNOW_Solver::setVoxelArrayAttributes(SNOW_VoxelArray *voxelarray) const
556 {
557  if (voxelarray)
558  {
559  UT_Vector3 div = voxelarray->getDivisions();
560  int xdiv = (int)div.x();
561  int ydiv = (int)div.y();
562  int zdiv = (int)div.z();
563 
564  int depth = getOriginalDepth();
565 
566  for (int z = 0; z < SYSmin(depth, zdiv); z++)
567  {
568  for (int y = 0; y < ydiv; y++)
569  {
570  for (int x = 0; x < xdiv; x++)
571  {
572  voxelarray->setVoxel(VOXEL_SNOW, x, y, z);
573  }
574  }
575  }
576  voxelarray->collapseAllTiles();
577  voxelarray->pubHandleModification();
578  }
579 }
580 
583  SIM_Object &object,
584  SIM_ObjectArray &,
585  const SIM_Time &timestep,
586  bool isnewobject)
587 {
589  // First, collect (or create) all the data we need from the object.
590  SNOW_VoxelArray *snow = SIM_DATA_GET(object, "SnowValue", SNOW_VoxelArray);
591  if (!snow)
592  {
593  snow = SIM_DATA_CREATE(object, "SnowValue", SNOW_VoxelArray, 0);
594  }
595 
596  // Rebuild the snow data to the desired base level if this is a new object.
597  if (snow)
598  {
599  if (isnewobject)
600  {
601  setVoxelArrayAttributes(snow);
602  result = SIM_SOLVER_SUCCESS;
603  }
604  else
605  {
606  solveForObject(object, *snow, timestep);
607  result = SIM_SOLVER_SUCCESS;
608  }
609  }
610 
611  return result;
612 }
613 
614 
616  : BaseClass(factory),
617  myVoxelArray(0)
618 {
619 }
620 
622 {
623  freeArray();
624 }
625 
626 const SIM_DopDescription *
627 SNOW_VoxelArray::getVoxelArrayDopDescription()
628 {
629  static PRM_Name theDivisionsName(SNOW_NAME_DIVISIONS, "Divisions");
630  static PRM_Name theCenterName(SNOW_NAME_CENTER, "Center");
631  static PRM_Name theSizeName(SNOW_NAME_SIZE, "Size");
632 
633  static PRM_Template theTemplates[] = {
634  PRM_Template(PRM_INT, 3, &theDivisionsName, PRMtenDefaults),
635  PRM_Template(PRM_XYZ, 3, &theCenterName, PRMzeroDefaults),
636  PRM_Template(PRM_XYZ, 3, &theSizeName, PRMoneDefaults),
637  PRM_Template()
638  };
639 
640  static SIM_DopDescription theDopDescription(true,
641  "hdk_snowvoxelarray",
642  "SNOW VoxelArray",
643  "SnowValue",
644  classname(),
645  theTemplates);
646 
647  return &theDopDescription;
648 }
649 
650 void
652 {
653  if (!name ||
654  !strcmp(name, SNOW_NAME_DIVISIONS))
655  {
656  // Any current array will be invalid now.
657  freeArray();
658  }
659 
661 }
662 
663 u8
664 SNOW_VoxelArray::getVoxel(int x, int y, int z) const
665 {
666  if (!myVoxelArray)
667  allocateArray();
668 
669  return myVoxelArray->getValue(x, y, z);
670 }
671 
672 void
673 SNOW_VoxelArray::setVoxel(u8 voxel, int x, int y, int z)
674 {
675  if (!myVoxelArray)
676  allocateArray();
677 
678  if (myVoxelArray->isValidIndex(x, y, z))
679  myVoxelArray->setValue(x, y, z, voxel);
680 }
681 
684 {
685  ((SNOW_VoxelArray *)this)->buildGeometryFromArray();
686  return myDetailHandle;
687 }
688 
689 void
690 SNOW_VoxelArray::freeArray() const
691 {
692  delete myVoxelArray;
693  myVoxelArray = 0;
694 }
695 
696 void
697 SNOW_VoxelArray::allocateArray() const
698 {
699  UT_ASSERT(myVoxelArray == 0);
700 
701  myVoxelArray = new UT_VoxelArray<u8>;
702 
703  UT_Vector3 div = getDivisions();
704  int divx = SYSmax((int)div.x(), 1);
705  int divy = SYSmax((int)div.y(), 1);
706  int divz = SYSmax((int)div.z(), 1);
707 
708  myVoxelArray->size(divx, divy, divz);
709 
710  // We want out of bound values to evaluate to wall voxels.
712 }
713 
714 GA_Offset
715 SNOW_VoxelArray::createOrFindPoint(GU_Detail *gdp, int x, int y, int z)
716 {
717  UT_Vector3 div = getDivisions();
718  int xdiv = (int)div.x();
719  int ydiv = (int)div.y();
720  int zdiv = (int)div.z();
721 
722  exint idx = (exint(z) * (ydiv + 1) + y)*(xdiv + 1) + x;
723 
724  UT_Map<exint, GA_Offset>::iterator it = myPointHash.find(idx);
725  if (it != myPointHash.end())
726  {
727  return it->second;
728  }
729 
730  // Create and add!
731 
732 #if defined(HOUDINI_11)
733  pt = gdp->appendPoint();
734 #else
735  GA_Offset ptoff = gdp->appendPointOffset();
736 #endif
737 
738  UT_Vector3 v((fpreal) x / (fpreal) (xdiv + 1),
739  (fpreal) y / (fpreal) (ydiv + 1),
740  (fpreal) z / (fpreal) (zdiv + 1));
741 
742  v -= 0.5;
743  v *= getSize();
744  v += getCenter();
745 
746  gdp->setPos3(ptoff, v);
747 
748  // And add to the hash...
749  myPointHash[idx] = ptoff;
750 
751  return ptoff;
752 }
753 
754 void
755 SNOW_VoxelArray::buildFace(GU_Detail *gdp,
756  int x0, int y0, int z0,
757  int x1, int y1, int z1,
758  int x2, int y2, int z2,
759  int x3, int y3, int z3)
760 {
761  // Do not append points, as we may scavenge.
762  GEO_PrimPoly *poly = GEO_PrimPoly::build(gdp, 4, false, false);
763 
764  GA_Offset ptoff;
765  ptoff = createOrFindPoint(gdp, x0, y0, z0);
766  poly->setPointOffset(0, ptoff);
767  ptoff = createOrFindPoint(gdp, x1, y1, z1);
768  poly->setPointOffset(1, ptoff);
769  ptoff = createOrFindPoint(gdp, x2, y2, z2);
770  poly->setPointOffset(2, ptoff);
771  ptoff = createOrFindPoint(gdp, x3, y3, z3);
772  poly->setPointOffset(3, ptoff);
773 }
774 
775 void
776 SNOW_VoxelArray::buildGeometryFromArray()
777 {
778  if (myDetailHandle.isNull())
779  {
780  GU_Detail *gdp = new GU_Detail();
781 
782  UT_Vector3 div = getDivisions();
783  int xdiv = (int)div.x();
784  int ydiv = (int)div.y();
785  int zdiv = (int)div.z();
786 
787  myDetailHandle.allocateAndSet(gdp);
788 
789  // Find the appropriate step value...
790  int xstep = 1;
791  int ystep = 1;
792  int zstep = 1;
793  if (xdiv > 64)
794  xstep = xdiv / 64;
795  if (ydiv > 64)
796  ystep = ydiv / 64;
797  if (zdiv > 64)
798  zstep = zdiv / 64;
799 
800  for (int z = 0; z < zdiv; z+=zstep)
801  {
802  for (int y = 0; y < ydiv; y+=ystep)
803  {
804  for (int x = 0; x < xdiv; x+=xstep)
805  {
806  if (getVoxel(x, y, z) == VOXEL_SNOW)
807  {
808  // Check each of the cardinal directions
809  // to see if we want to build a face.
810 
811  // We want to render the faces of this cube
812  // that are bordered by an empty unit.
813  // We specify the points as (x,y,z) triplets.
814  // This cube is (x,y,z) to (x+1,y+1,z+1)
815  if (getVoxel(x-xstep, y, z) != VOXEL_SNOW)
816  {
817  buildFace( gdp, x, y, z,
818  x, y+ystep, z,
819  x, y+ystep, z+zstep,
820  x, y, z+zstep );
821  }
822  if (getVoxel(x+xstep, y, z) != VOXEL_SNOW)
823  {
824  buildFace( gdp, x+xstep, y, z,
825  x+xstep, y, z+zstep,
826  x+xstep, y+ystep, z+zstep,
827  x+xstep, y+ystep, z );
828  }
829  if (getVoxel(x, y-ystep, z) != VOXEL_SNOW)
830  {
831  buildFace( gdp, x, y, z,
832  x, y, z+zstep,
833  x+xstep, y, z+zstep,
834  x+xstep, y, z );
835  }
836  if (getVoxel(x, y+ystep, z) != VOXEL_SNOW)
837  {
838  buildFace( gdp, x, y+ystep, z,
839  x+xstep, y+ystep, z,
840  x+xstep, y+ystep, z+zstep,
841  x, y+ystep, z+zstep );
842  }
843  if (getVoxel(x, y, z-zstep) != VOXEL_SNOW)
844  {
845  buildFace( gdp, x, y, z,
846  x+xstep, y, z,
847  x+xstep, y+ystep, z,
848  x, y+ystep, z );
849  }
850  if (getVoxel(x, y, z+zstep) != VOXEL_SNOW)
851  {
852  buildFace( gdp, x, y, z+zstep,
853  x, y+ystep, z+zstep,
854  x+xstep, y+ystep, z+zstep,
855  x+xstep, y, z+zstep );
856  }
857  }
858  }
859  }
860  }
861 
862  // Wipe out all the points we allocated.
863  myPointHash.clear();
864  }
865 }
866 
867 void
869 {
870  BaseClass::initializeSubclass();
871  freeArray();
872  myDetailHandle.clear();
873 }
874 
875 void
877 {
878  const SNOW_VoxelArray *srcvox;
879 
880  BaseClass::makeEqualSubclass(source);
881  srcvox = SIM_DATA_CASTCONST(source, SNOW_VoxelArray);
882  if( srcvox )
883  {
884  setDivisions(srcvox->getDivisions());
885 
886  if (srcvox->myVoxelArray)
887  {
888  // Copy over the voxels.
889  allocateArray();
890 
891  *myVoxelArray = *srcvox->myVoxelArray;
892  }
893  else
894  {
895  // No voxel array, so nothing to copy.
896  freeArray();
897  }
898  }
899 }
900 
901 void
903 {
904  UT_Vector3 div = getDivisions();
905  int xdiv = (int)div.x();
906  int ydiv = (int)div.y();
907  int zdiv = (int)div.z();
908 
909  BaseClass::saveIOSubclass(os, io);
910 
911  os << "{\n";
912  for (int z = 0; z < zdiv; z++)
913  {
914  for (int y = 0; y < ydiv; y++)
915  {
916  os << "\t";
917  for (int x = 0; x < xdiv; x++)
918  {
919  int value = getVoxel(x, y, z);
920  os << " " << value;
921  }
922  os << "\n";
923  }
924  }
925  os << "}\n";
926 }
927 
928 bool
930 {
931  if (!BaseClass::loadIOSubclass(is, io))
932  return false;
933 
934  UT_Vector3 div = getDivisions();
935  int xdiv = (int)div.x();
936  int ydiv = (int)div.y();
937  int zdiv = (int)div.z();
938 
939  exint arraysize = exint(xdiv) * ydiv * zdiv;
940  int x = 0;
941  int y = 0;
942  int z = 0;
944  if (is.getLine(buf) && *buf.buffer() == '{')
945  {
946  exint idx = 0;
947  while (is.getLine(buf) && *buf.buffer() != '}')
948  {
949  UT_IStringStream bufis;
950  // Steal the contents of the UT_WorkBuffer.
951  bufis.rdbuf()->swap(buf);
952 
953  while (idx < arraysize && bufis)
954  {
955  int value;
956  if (bufis >> value)
957  {
958  setVoxel(value, x, y, z);
959  idx++;
960  x++;
961  if (x >= xdiv)
962  {
963  x = 0;
964  y++;
965  if (y >= ydiv)
966  {
967  y = 0;
968  z++;
969  }
970  }
971  }
972  }
973  }
974  UT_ASSERT(idx == arraysize);
975  }
976 
977  return true;
978 }
979 
980 int64
982 {
983  int64 mem = sizeof(*this);
984  if (myVoxelArray)
985  mem += myVoxelArray->getMemoryUsage(true);
986  if (!myDetailHandle.isNull())
987  {
988  GU_DetailHandleAutoReadLock gdl(myDetailHandle);
989  const GU_Detail *gdp = gdl.getGdp();
990 
991  mem += gdp->getMemoryUsage(true);
992  }
993 
994  return mem;
995 }
996 
997 void
999 {
1000  BaseClass::handleModificationSubclass(code);
1001 
1002  // Ensure we rebuild our display proxy geometry.
1003  myDetailHandle.clear();
1004 }
1005 
1006 void
1008 {
1009  if (!myVoxelArray)
1010  return;
1011 
1012  myVoxelArray->collapseAllTiles();
1013 }
1014 
1016  : BaseClass(factory),
1018 {
1019  myArray = 0;
1020 }
1021 
1023 {
1024 }
1025 
1026 const SIM_DopDescription *
1027 SNOW_Visualize::getVisualizeDopDescription()
1028 {
1029  static PRM_Name theGuideBox("usebox", "Bounding Box");
1030 
1031  static PRM_Template theTemplates[] = {
1032  PRM_Template()
1033  };
1034 
1035  static PRM_Template theGuideTemplates[] = {
1037  PRMzeroDefaults),
1038  PRM_Template(PRM_RGB, 3,
1040  0, &PRMunitRange),
1041  PRM_Template(PRM_TOGGLE, 1, &theGuideBox, PRMzeroDefaults),
1042  PRM_Template()
1043  };
1044 
1045  static SIM_DopDescription theDopDescription(true,
1046  "hdk_snowvisualize",
1047  "SNOW Visualize",
1048  "Visualization",
1049  classname(),
1050  theTemplates);
1051  theDopDescription.setGuideTemplates(theGuideTemplates);
1052 
1053  return &theDopDescription;
1054 }
1055 
1056 SIM_Guide *
1058 {
1059  // Return a shared guide so that we only have to build our geometry
1060  // once. But set the displayonce flag to false so that we can set
1061  // a different transform for each object.
1062  return new SIM_GuideShared(this, false);
1063 }
1064 
1065 void
1067  const UT_BoundingBox &bbox,
1068  const UT_Vector3 &color)
1069 {
1071  if (!cdh.isValid())
1072  {
1073 #if defined(HOUDINI_11)
1074  static float one[3] = { 1, 1, 1 };
1075  gdp->addPointAttrib("Cd", 3 * sizeof(float), GB_ATTRIB_FLOAT, one);
1076  cd_gah = gdp->getPointAttribute("Cd");
1077 #else
1078  cdh = GA_RWHandleV3(gdp->addFloatTuple(GA_ATTRIB_POINT, "Cd", 3,
1079  GA_Defaults(1.0)));
1080  cdh->setTypeInfo(GA_TYPE_COLOR);
1081 #endif
1082  }
1083 
1084  GA_PrimitiveGroup *bboxgrp = gdp->newPrimitiveGroup("bbox");
1085 
1086  // Create the 8 points with the rule that
1087  // we use max(axis) if idx1 & (1 << axis) is true.
1088  GA_Offset corners[8];
1089  for (int idx1 = 0; idx1 < 8; idx1++)
1090  {
1091  corners[idx1] = gdp->appendPointOffset();
1092 
1093  UT_Vector3 pos;
1094  pos.x() = (idx1 & 1) ? bbox.xmax() : bbox.xmin();
1095  pos.y() = (idx1 & 2) ? bbox.ymax() : bbox.ymin();
1096  pos.z() = (idx1 & 4) ? bbox.zmax() : bbox.zmin();
1097  gdp->setPos3(corners[idx1], pos);
1098 
1099  cdh.set(corners[idx1], color);
1100  }
1101 
1102  // Create each edge. Edges are in increaing direction of index.
1103  // Two indicies are connected if they differ in one and only one
1104  // axis. Brute force and ignorance saves the day.
1105  // We run the n^2 possible indices and only build if the bit
1106  // field of differences matches a desired pattern.
1107  for (int idx1 = 0; idx1 < 8; idx1++)
1108  {
1109  for (int idx2 = idx1+1; idx2 < 8; idx2++)
1110  {
1111  switch (idx1 ^ idx2)
1112  {
1113  case 1:
1114  case 2:
1115  case 4:
1116  {
1117  GEO_PrimPoly *line = GEO_PrimPoly::build(gdp, 2, GU_POLY_OPEN, false);
1118  bboxgrp->add(line);
1119 
1120  line->setPointOffset(0, corners[idx1]);
1121  line->setPointOffset(1, corners[idx2]);
1122 
1123  break;
1124  }
1125  }
1126  }
1127  }
1128 }
1129 
1130 void
1132  const SIM_Options &options,
1133  const GU_DetailHandle &gdh,
1134  UT_DMatrix4 *,
1135  const SIM_Time &) const
1136 {
1137  // Build our template geometry, if we are so asked.
1139 
1140  if (!myArray)
1141  return;
1142 
1143  if (gdh.isNull())
1144  return;
1145 
1147  GU_Detail *gdp = gdl.getGdp();
1148 
1149  UT_Vector3 color = getColor(options);
1150 
1151  // Find our bounding box.
1152  UT_Vector3 bbmin, bbmax;
1153  bbmin = myArray->getCenter();
1154  bbmax = bbmin;
1155  bbmin -= myArray->getSize()*0.5;
1156  bbmax += myArray->getSize()*0.5;
1157  UT_BoundingBox bbox;
1158  bbox.initBounds(bbmin, bbmax);
1159 
1160  GA_RWHandleV3 cdh(gdp->findPointAttribute("Cd"));
1161  if (!cdh.isValid())
1162  {
1163  cdh = GA_RWHandleV3(gdp->addFloatTuple(GA_ATTRIB_POINT, "Cd", 3,
1164  GA_Defaults(1.0)));
1165  cdh->setTypeInfo(GA_TYPE_COLOR);
1166  }
1167 
1168  UT_Vector3 div = myArray->getDivisions();
1169  int divx = (int)div.x();
1170  int divy = (int)div.y();
1171  int divz = (int)div.z();
1172 
1173  // Build our particle system to hold all of our snow voxels.
1174  GU_PrimParticle *part = GU_PrimParticle::build(gdp, 0);
1175 
1176  for (int z = 0; z < divz; z++)
1177  for (int y = 0; y < divy; y++)
1178  for (int x = 0; x < divx; x++)
1179  {
1180  if (myArray->getVoxel(x, y, z) == VOXEL_SNOW)
1181  {
1182  GA_Offset ptoff = gdp->appendPointOffset();
1183  cdh.set(ptoff, color);
1184 
1185  UT_Vector3 v((fpreal) x / (fpreal) (divx + 1),
1186  (fpreal) y / (fpreal) (divy + 1),
1187  (fpreal) z / (fpreal) (divz + 1));
1188 
1189  v -= 0.5;
1190  v *= myArray->getSize();
1191  v += myArray->getCenter();
1192 
1193  gdp->setPos3(ptoff, v);
1194 
1195  // Add this free floating point to our particle system.
1196  part->appendParticle(ptoff);
1197  }
1198  }
1199 
1200 
1201  if (getUseBox(options))
1202  createBoundingBoxGuide(gdp, bbox, color);
1203 }
1204 
1205 void
1207 {
1208  BaseClass::initializeSubclass();
1209 
1210  myArray = 0;
1211 }
1212 
1213 bool
1215 {
1216  return true;
1217 }
1218 
1219 void
1221 {
1222  const SNOW_VoxelArray *sf = SIM_DATA_CASTCONST(&parent, SNOW_VoxelArray);
1223  myArray = sf;
1224 }
1225 
1226 void
1228 {
1232 }
1233 
void reset()
#define SYSmax(a, b)
Definition: SYS_Math.h:1538
GU_Detail * getGdp() const
int sendRay(const UT_Vector3 &org, const UT_Vector3 &dir, GU_RayInfo &hitinfo) const
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
GA_API const UT_StringHolder dist
GA_API const UT_StringHolder div
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2540
SYS_FORCE_INLINE GA_Attribute * addPointAttrib(const GA_Attribute *src)
Definition: GEO_Detail.h:1684
#define SIM_DATA_CASTCONST(Data, DataClass)
Definition: SIM_Utils.h:34
void initAlternateRepresentationSubclass(const SIM_Data &) override
Definition: SNOW_Solver.C:1220
exint entries() const
PRM_API PRM_Range PRMunitRange
Unsorted map container.
Definition: UT_Map.h:107
#define VOXEL_EMPTY
Definition: SNOW_Solver.h:124
virtual void optionChangedSubclass(const char *name)
int choice(int choices)
void getTransform(UT_DMatrix4 &xform) const
GLsizei GLfloat xorig
Definition: glad.h:2115
void setValue(UT_Vector3I index, T value)
#define IMPLEMENT_DATAFACTORY(DataClass)
void transform(const MATRIX &mat)
Class which stores the default values for a GA_Attribute.
Definition: GA_Defaults.h:35
bool getBBox(UT_BoundingBox *bbox, const GA_PrimitiveGroup *g=nullptr) const
PRM_API const PRM_Type PRM_RGB
int64 getMemoryUsage(bool inclusive) const
Return the amount of memory used by this array.
void initializeSubclass() override
Definition: SNOW_Solver.C:1206
GA_Attribute * addFloatTuple(GA_AttributeOwner owner, GA_AttributeScope scope, const UT_StringHolder &name, int tuple_size, const GA_Defaults &defaults=GA_Defaults(0.0), const UT_Options *creation_args=0, const GA_AttributeOptions *attribute_options=0, GA_Storage storage=GA_STORE_REAL32, const GA_ReuseStrategy &reuse=GA_ReuseStrategy())
const GLdouble * v
Definition: glcorearb.h:837
IMF_EXPORT IMATH_NAMESPACE::V3f direction(const IMATH_NAMESPACE::Box2i &dataWindow, const IMATH_NAMESPACE::V2f &pixelPosition)
GLsizei const GLfloat * value
Definition: glcorearb.h:824
Data represents a color. Token "color".
Definition: GA_Types.h:115
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:848
SYS_FORCE_INLINE void setPointOffset(GA_Size i, GA_Offset ptoff)
Definition: GA_Primitive.h:260
constexpr SYS_FORCE_INLINE T & z() noexcept
Definition: UT_Vector3.h:667
int64 exint
Definition: SYS_Types.h:125
#define VOXEL_WALL
Definition: SNOW_Solver.h:127
fpreal frandom()
Returns a random float from [0..1)
const GA_Attribute * findDiffuseAttribute(GA_AttributeOwner who) const
void makeEqualSubclass(const SIM_Data *source) override
Makes this geometry equal to some other SIM_Geometry.
Definition: SNOW_Solver.C:876
SYS_FORCE_INLINE const char * buffer() const
void initializeSubclass() override
Set initial values on all the geometry attributes.
Definition: SNOW_Solver.C:868
SIM_API PRM_Name SIMshowguideName
int64 getMemorySizeSubclass() const override
Definition: SNOW_Solver.C:981
GA_Offset appendParticle(GA_Offset pt)
Append a new particle.
An input stream object that owns its own string buffer storage.
**But if you need a or simply need to know when the task has note that the like this
Definition: thread.h:617
GLint y
Definition: glcorearb.h:103
PRM_API PRM_Default PRMpointOneDefaults[]
void fillRow(SNOW_VoxelArray &snow, fpreal startx, fpreal endx, int y, int z, u8 voxeltype, SIM_Random *rand) const
Definition: SNOW_Solver.C:221
**But if you need a result
Definition: thread.h:613
void clear()
Definition: UT_Map.h:184
GU_ConstDetailHandle getGeometrySubclass() const override
Definition: SNOW_Solver.C:683
PRM_API const PRM_Type PRM_INT_J
void size(int xres, int yres, int zres, bool reset=true)
bool getIsAlternateRepresentationSubclass() const override
Definition: SNOW_Solver.C:1214
GLdouble GLdouble x2
Definition: glad.h:2349
u8 getVoxel(int x, int y, int z) const
Definition: SNOW_Solver.C:664
GA_PrimitiveGroup * newPrimitiveGroup(const UT_StringHolder &name)
Definition: GA_Detail.h:1296
int64 getMemoryUsage(bool inclusive) const override
Compute memory usage (includes all shared memory)
GA_RWHandleT< UT_Vector3F > GA_RWHandleV3
Definition: GA_Handle.h:1382
PRM_API const PRM_Type PRM_INT
#define VOXEL_OBJECT
Definition: SNOW_Solver.h:128
void allocateAndSet(GU_Detail *gdp, bool own=true)
GA_Size GA_Offset
Definition: GA_Types.h:641
unsigned char u8
Definition: SNOW_Solver.h:54
GLdouble n
Definition: glcorearb.h:2008
void initAlternateRepresentation() const
PRM_API PRM_Default PRMtenDefaults[]
void initializeSIM(void *)
Definition: SNOW_Solver.C:1227
int rand_choice(int numchoice, SIM_Random *rand) const
Definition: SNOW_Solver.C:214
bool getLine(UT_WorkBuffer &buffer, int end='\n')
Holds pointers to a number of SIM_Object objects.
void saveIOSubclass(std::ostream &os, SIM_DataThreadedIO *io) const override
Definition: SNOW_Solver.C:902
#define SIM_DATA_GET(Parent, DataName, DataClass)
Definition: SIM_Utils.h:40
PRM_API const PRM_Type PRM_XYZ
GLsizei GLsizei GLchar * source
Definition: glcorearb.h:803
SYS_FORCE_INLINE GA_Offset appendPoint()
Append a new point, returning its new data offset.
Definition: GA_Detail.h:326
GLdouble y1
Definition: glad.h:2349
const SIM_Geometry * getGeometry() const
long long int64
Definition: SYS_Types.h:116
#define SIM_SOLVER_DATANAME
Definition: SIM_Names.h:55
void identity()
Set the matrix to identity.
Definition: UT_Matrix4.h:1128
SNOW_Visualize(const SIM_DataFactory *factory)
Definition: SNOW_Solver.C:1015
SYS_API fpreal32 SYSfloor(fpreal32 val)
GLuint const GLchar * name
Definition: glcorearb.h:786
int clearInDirection(const SNOW_VoxelArray &snow, int sx, int sy, int sz, int dx, int dy, int dz, int &rx, int &ry, int &rz, int maxdist, SIM_Random *rand) const
Definition: SNOW_Solver.C:129
GLint GLenum GLint x
Definition: glcorearb.h:409
static void createBoundingBoxGuide(GU_Detail *gdp, const UT_BoundingBox &bbox, const UT_Vector3 &color)
Definition: SNOW_Solver.C:1066
void swap(UT_WorkBuffer &buf)
PRM_API const PRM_Type PRM_FLT_J
void setVoxel(u8 voxel, int x, int y, int z)
Definition: SNOW_Solver.C:673
void add(const GA_Primitive *prim)
void applyGeometry(SNOW_VoxelArray &snow, const GU_ConstDetailHandle &gdh, const UT_DMatrix4 &xform, u8 voxletype, SIM_Random *rand) const
Definition: SNOW_Solver.C:257
#define SIM_NAME_BIRTHRATE
Definition: SNOW_Solver.h:50
void getInverseTransform(UT_DMatrix4 &xform) const
GLdouble t
Definition: glad.h:2397
SIM_Guide * createGuideObjectSubclass() const override
Definition: SNOW_Solver.C:1057
GLint GLint GLsizei GLsizei GLsizei depth
Definition: glcorearb.h:476
void optionChangedSubclass(const char *name) override
Definition: SNOW_Solver.C:651
exint entries() const
Alias of size(). size() is preferred.
Definition: UT_Array.h:648
bool SYSequalZero(const UT_Vector3T< T > &v)
Definition: UT_Vector3.h:1069
void scale(T sx, T sy, T sz, T sw=1)
Definition: UT_Matrix4.h:701
PRM_API PRM_Default PRMoneDefaults[]
SNOW_Solver(const SIM_DataFactory *factory)
Definition: SNOW_Solver.C:60
GLsizeiptr size
Definition: glcorearb.h:664
SYS_FORCE_INLINE GA_Offset appendPointOffset()
Definition: GEO_Detail.h:1143
bool brownianize(int &v, int dv, int max, SIM_Random *rand) const
Definition: SNOW_Solver.C:108
GEO_AttributeHandle getPointAttribute(const char *attrib_name) const
SYS_FORCE_INLINE void setPos3(GA_Offset ptoff, const UT_Vector3 &pos)
Set P from a UT_Vector3.
Definition: GA_Detail.h:237
const SIM_Position * getPosition() const
T getValue(int x, int y, int z) const
void clearSnow(SNOW_VoxelArray &snow, int x, int y, int z, SIM_Random *rand) const
Definition: SNOW_Solver.C:170
#define GU_POLY_OPEN
Definition: GU_Types.h:120
void translate(T dx, T dy, T dz=0)
Definition: UT_Matrix4.h:773
GLuint color
Definition: glcorearb.h:1261
SNOW_VoxelArray(const SIM_DataFactory *factory)
Definition: SNOW_Solver.C:615
fpreal64 fpreal
Definition: SYS_Types.h:277
GU_ConstDetailHandle getGeometry() const
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
SYS_FORCE_INLINE void initBounds()
PRM_API const PRM_Type PRM_TOGGLE
void handleModificationSubclass(int code) override
Definition: SNOW_Solver.C:998
static GU_PrimParticle * build(GU_Detail *gdp, GA_Size numparts, bool appendPts=true)
UT_StringStreamBuffer * rdbuf() const
Returns the underlying stream buffer object.
int isInsideWinding(const UT_Vector3 &pt, bool ignoretrim=true, float tol=0.1) const
int invert(T tol=0.0F)
bool loadIOSubclass(UT_IStream &is, SIM_DataThreadedIO *io) override
Definition: SNOW_Solver.C:929
#define VOXEL_SNOW
Definition: SNOW_Solver.h:125
#define SNOW_NAME_CENTER
Definition: SNOW_Solver.h:131
SIM_Result solveSingleObjectSubclass(SIM_Engine &engine, SIM_Object &object, SIM_ObjectArray &feedbacktoobjects, const SIM_Time &timestep, bool newobject) override
Definition: SNOW_Solver.C:582
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
Definition: core.h:1131
void setBorder(UT_VoxelBorderType type, T t)
SIM_API PRM_Name SIMcolorName
void buildGuideGeometrySubclass(const SIM_RootData &root, const SIM_Options &options, const GU_DetailHandle &gdh, UT_DMatrix4 *xform, const SIM_Time &t) const override
Definition: SNOW_Solver.C:1131
GLdouble GLdouble GLdouble y2
Definition: glad.h:2349
void init(float max=1E18f, float min=0.0f, GU_RayFindType type=GU_FIND_CLOSEST, float tolerance=1e-1F, int ignoretrims=1, int usealgebraic=0)
SYS_FORCE_INLINE void setTypeInfo(GA_TypeInfo type)
Definition: GA_Attribute.h:260
#define SNOW_NAME_DIVISIONS
Definition: SNOW_Solver.h:130
SYS_FORCE_INLINE const GA_Attribute * findPointAttribute(GA_AttributeScope s, const UT_StringRef &name) const
Definition: GA_Detail.h:1034
constexpr SYS_FORCE_INLINE T & y() noexcept
Definition: UT_Vector3.h:665
#define SIM_NAME_ORIGINALDEPTH
Definition: SNOW_Solver.h:51
PRM_API PRM_Default PRMzeroDefaults[]
bool isValidIndex(int x, int y, int z) const
Returns true if the given x, y, z values lie inside the valid index.
#define SYSmin(a, b)
Definition: SYS_Math.h:1539
SIM_Random * createRandomData(SIM_Object *obj) const
Definition: SNOW_Solver.C:93
#define SIM_DATA_CREATE(Parent, DataName, DataClass, Flags)
Definition: SIM_Utils.h:63
const GU_Detail * getGdp() const
UT_Array< GU_RayInfoHit > * myHitList
SYS_FORCE_INLINE void multiply3(const UT_Matrix4T< S > &mat)
Definition: UT_Matrix4.h:2069
void pretranslate(T dx, T dy, T dz=0)
Definition: UT_Matrix4.h:792
#define SNOW_NAME_SIZE
Definition: SNOW_Solver.h:132
SYS_API fpreal32 SYSceil(fpreal32 val)
static GEO_PrimPoly * build(GA_Detail *gdp, GA_Size nvertices, bool open=false, bool appendpts=true)
constexpr SYS_FORCE_INLINE T & x() noexcept
Definition: UT_Vector3.h:663
bool isNull() const