HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GEO_PrimTetra.C
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * Produced by:
7  * Jeff Lait
8  * Side Effects Software Inc
9  * 477 Richmond Street West
10  * Toronto, Ontario
11  * Canada M5V 3E7
12  * 416-504-9876
13  *
14  * NAME: GEO_PrimTetra.C (HDK Sample, C++)
15  *
16  * COMMENTS: This is an HDK example for making a custom tetrahedron primitive type.
17  */
18 
19 #include "GEO_PrimTetra.h"
20 #include <UT/UT_Defines.h>
21 #include <UT/UT_SparseArray.h>
22 #include <UT/UT_SysClone.h>
23 #include <UT/UT_IStream.h>
24 #include <UT/UT_JSONParser.h>
25 #include <UT/UT_JSONWriter.h>
26 #include <UT/UT_MemoryCounter.h>
27 #include <UT/UT_ParallelUtil.h>
28 #include <UT/UT_Vector3.h>
29 #include <GA/GA_AttributeRefMap.h>
31 #include <GA/GA_Defragment.h>
32 #include <GA/GA_WorkVertexBuffer.h>
33 #include <GA/GA_WeightedSum.h>
34 #include <GA/GA_MergeMap.h>
35 #include <GA/GA_IntrinsicMacros.h>
36 #include <GA/GA_ElementWrangler.h>
37 #include <GA/GA_PrimitiveJSON.h>
38 #include <GA/GA_RangeMemberQuery.h>
39 #include <GA/GA_LoadMap.h>
40 #include <GA/GA_SaveMap.h>
41 #include <GEO/GEO_ConvertParms.h>
42 #include <GEO/GEO_Detail.h>
44 #include <GEO/GEO_PrimPoly.h>
45 #include <GEO/GEO_PrimType.h>
46 #include <DM/DM_RenderTable.h>
47 
48 #include "GR_PrimTetra.h"
49 #include "GT_PrimTetra.h"
50 
51 //#define TIMING_BUILDBLOCK
52 //#define SLOW_BUILDBLOCK
53 
54 #ifdef TIMING_BUILDBLOCK
55 #include <UT/UT_StopWatch.h>
56 #define TIMING_DEF \
57  UT_StopWatch timer; \
58  timer.start();
59 #define TIMING_LOG(msg) \
60  printf(msg ": %f milliseconds\n", 1000*timer.stop()); \
61  fflush(stdout); \
62  timer.start();
63 #else
64 #define TIMING_DEF
65 #define TIMING_LOG(msg)
66 #endif
67 
68 using namespace HDK_Sample;
69 
70 GA_PrimitiveDefinition *GEO_PrimTetra::theDefinition = nullptr;
71 
72 // So it doesn't look like a magic number
73 #define PT_PER_TET 4
74 
76  : GEO_Primitive(&d, offset)
77 {
78  // NOTE: There used to be an option to use a separate "merge constructor"
79  // to allow the regular constructor to add vertices to the detail,
80  // but this is no longer allowed. This constructor *must* be safe
81  // to call from multiple threads on the same detail at the same time.
82 }
83 
85 {
86  // This class doesn't have anything that needs explicit destruction,
87  // apart from what's done in the automatically-called base class
88  // destructor. If you add anything that needs to be explicitly
89  // cleaned up, do it here, and make sure that it's safe to be
90  // done to multiple primitives of the same detail at the same time.
91 }
92 
93 void
95 {
96  GEO_Primitive::stashed(beingstashed, offset);
97 
98  // This function is used as a way to "stash" and "unstash" a primitive
99  // as an alternative to freeing and reallocating a primitive.
100  // This class doesn't have any data apart from what's in the base class,
101  // but if you add any data, make sure that when beingstashed is true,
102  // any allocated memory gets freed up, and when beingstashed is false,
103  // (which will only happen after having first been called with true),
104  // make sure that the primitive is initialized to a state that is as
105  // if it were freshly constructed.
106  // It should be threadsafe to call this on multiple primitives
107  // in the same detail at the same time.
108 }
109 
110 bool
112  GA_AttributeRefMap &map,
113  fpreal u, fpreal v, unsigned du,
114  unsigned dv) const
115 {
116  // The parameter space of a tetrahedron requires 3 coordinates,
117  // (u,v,w), not just (u,v), so this just falls back to picking
118  // the first vertex's values.
119  if (du==0 && dv==0)
120  {
121  map.copyValue(GA_ATTRIB_VERTEX, result_vtx,
123  }
124  else
125  {
126  // Any derivative of a constant value is zero.
127  map.zeroElement(GA_ATTRIB_VERTEX, result_vtx);
128  }
129  return true;
130 }
131 
132 
133 void
135 {
136  // NOTE: We cannot reverse all of the vertices, else the sense
137  // of the tet is left unchnaged!
138  GA_Size r = 0;
139  GA_Size nr = 3 - r;
140  GA_Offset other = myVertexList.get(nr);
142  myVertexList.set(r, other);
143 }
144 
147 {
148  return UT_Vector3(0, 0, 0);
149 }
150 
151 fpreal
153 {
154  UT_Vector3 v0 = getPos3(0);
155  UT_Vector3 v1 = getPos3(1);
156  UT_Vector3 v2 = getPos3(2);
157  UT_Vector3 v3 = getPos3(3);
158 
159  // Measure signed volume of pyramid (v0,v1,v2,v3)
160  float signedvol = -(v3-v0).dot(cross(v1-v0, v2-v0));
161 
162  signedvol /= 6;
163 
164  return signedvol;
165 }
166 
167 fpreal
169 {
170  fpreal area = 0; // Signed area
171 
172  UT_Vector3 v0 = getPos3(0);
173  UT_Vector3 v1 = getPos3(1);
174  UT_Vector3 v2 = getPos3(2);
175  UT_Vector3 v3 = getPos3(3);
176 
177  area += cross((v1 - v0), (v2 - v0)).length();
178  area += cross((v3 - v1), (v2 - v1)).length();
179  area += cross((v3 - v0), (v1 - v0)).length();
180  area += cross((v2 - v0), (v3 - v0)).length();
181 
182  area = area / 2;
183 
184  return area;
185 }
186 
187 fpreal
189 {
190  fpreal length = 0;
191 
192  UT_Vector3 v0 = getPos3(0);
193  UT_Vector3 v1 = getPos3(1);
194  UT_Vector3 v2 = getPos3(2);
195  UT_Vector3 v3 = getPos3(3);
196 
197  length += (v1-v0).length();
198  length += (v2-v0).length();
199  length += (v3-v0).length();
200  length += (v2-v1).length();
201  length += (v3-v1).length();
202  length += (v3-v2).length();
203 
204  return length;
205 }
206 
207 int
209 {
210  GA_Size count = 0;
211  for (GA_Size i = 0; i < PT_PER_TET; ++i)
212  if (grp.containsOffset(getPointOffset(i)))
213  count++;
214 
215  if (count == 0)
216  return 0;
217 
218  if (count == PT_PER_TET)
219  return -2;
220 
221  return -1;
222 }
223 
226 {
227  for (GA_Size i = 0; i < PT_PER_TET; ++i)
228  {
229  if (getPointOffset(i) == point)
230  {
232  }
233  }
234  return GA_DEREFERENCE_OK;
235 }
236 
238 GEO_PrimTetra::dereferencePoints(const GA_RangeMemberQuery &point_query, bool dry_run)
239 {
240  int count = 0;
241  for (GA_Size i = 0; i < PT_PER_TET; ++i)
242  {
243  if (point_query.contains(getPointOffset(i)))
244  {
245  count++;
246  }
247  }
248 
249  if (count == PT_PER_TET)
250  return GA_DEREFERENCE_DESTROY;
251  if (count == 0)
252  return GA_DEREFERENCE_OK;
253 
254  if (isDegenerate())
256  return GA_DEREFERENCE_FAIL;
257 }
258 
259 ///
260 /// JSON methods
261 ///
262 
263 namespace HDK_Sample {
264 
265 using namespace UT::Literal;
266 
267 static UT_StringHolder theKWVertex = "vertex"_sh;
268 
270 {
271 public:
273  {
274  }
275  virtual ~geo_PrimTetraJSON() {}
276 
277  enum
278  {
280  geo_TBJ_ENTRIES
281  };
282 
283  const GEO_PrimTetra *tet(const GA_Primitive *p) const
284  { return static_cast<const GEO_PrimTetra *>(p); }
286  { return static_cast<GEO_PrimTetra *>(p); }
287 
288  virtual int getEntries() const { return geo_TBJ_ENTRIES; }
289  virtual const UT_StringHolder &getKeyword(int i) const
290  {
291  switch (i)
292  {
293  case geo_TBJ_VERTEX: return theKWVertex;
294  case geo_TBJ_ENTRIES: break;
295  }
296  UT_ASSERT(0);
298  }
299  virtual bool saveField(const GA_Primitive *pr, int i,
300  UT_JSONWriter &w, const GA_SaveMap &map) const
301  {
302  switch (i)
303  {
304  case geo_TBJ_VERTEX:
305  return tet(pr)->saveVertexArray(w, map);
306  case geo_TBJ_ENTRIES:
307  break;
308  }
309  return false;
310  }
311  virtual bool saveField(const GA_Primitive *pr, int i,
312  UT_JSONValue &v, const GA_SaveMap &map) const
313  {
314  switch (i)
315  {
316  case geo_TBJ_VERTEX:
317  return false;
318  case geo_TBJ_ENTRIES:
319  break;
320  }
321  UT_ASSERT(0);
322  return false;
323  }
324  virtual bool loadField(GA_Primitive *pr, int i, UT_JSONParser &p,
325  const GA_LoadMap &map) const
326  {
327  switch (i)
328  {
329  case geo_TBJ_VERTEX:
330  return tet(pr)->loadVertexArray(p, map);
331  case geo_TBJ_ENTRIES:
332  break;
333  }
334  UT_ASSERT(0);
335  return false;
336  }
337  virtual bool loadField(GA_Primitive *pr, int i, UT_JSONParser &p,
338  const UT_JSONValue &v, const GA_LoadMap &map) const
339  {
340  switch (i)
341  {
342  case geo_TBJ_VERTEX:
343  return false;
344  case geo_TBJ_ENTRIES:
345  break;
346  }
347  UT_ASSERT(0);
348  return false;
349  }
350  virtual bool isEqual(int i, const GA_Primitive *p0,
351  const GA_Primitive *p1) const
352  {
353  switch (i)
354  {
355  case geo_TBJ_VERTEX:
356  return false;
357  case geo_TBJ_ENTRIES:
358  break;
359  }
360  UT_ASSERT(0);
361  return false;
362  }
363 private:
364 };
365 }
366 
367 static const GA_PrimitiveJSON *
368 tetrahedronJSON()
369 {
370  static GA_PrimitiveJSON *theJSON = NULL;
371 
372  if (!theJSON)
373  theJSON = new geo_PrimTetraJSON();
374  return theJSON;
375 }
376 
377 const GA_PrimitiveJSON *
379 {
380  return tetrahedronJSON();
381 }
382 
383 
384 
385 bool
387  const GA_SaveMap &map) const
388 {
389  return myVertexList.jsonVertexArray(w, map);
390 }
391 
392 bool
394 {
395  GA_Offset startvtxoff = map.getVertexOffset();
396 
397  int64 vtxoffs[PT_PER_TET];
398  int nvertex = p.parseUniformArray(vtxoffs, PT_PER_TET);
399  if (startvtxoff != GA_Offset(0))
400  {
401  for (int i = 0; i < nvertex; i++)
402  {
403  if (vtxoffs[i] >= 0)
404  vtxoffs[i] += GA_Size(startvtxoff);
405  }
406  }
407  for (int i = nvertex; i < PT_PER_TET; ++i)
408  vtxoffs[i] = GA_INVALID_OFFSET;
409  myVertexList.set(vtxoffs, PT_PER_TET, GA_Offset(0));
410  if (nvertex < PT_PER_TET)
411  return false;
412  return true;
413 }
414 
415 
416 int
418 {
419  bbox->initBounds(getPos3(0));
420  bbox->enlargeBounds(getPos3(1));
421  bbox->enlargeBounds(getPos3(2));
422  bbox->enlargeBounds(getPos3(3));
423  return 1;
424 }
425 
428 {
429  UT_Vector3 sum(0,0,0);
430 
431  for (int i = 0; i < PT_PER_TET; ++i)
432  sum += getPos3(i);
433 
434  sum /= PT_PER_TET;
435 
436  return sum;
437 }
438 
439 bool
441 {
442  // Duplicate points means degenerate.
443  for (int i = 0; i < PT_PER_TET; i++)
444  {
445  for (int j = i+1; j < PT_PER_TET; j++)
446  {
447  if (getPointOffset(i) == getPointOffset(j))
448  return true;
449  }
450  }
451  return false;
452 }
453 
454 void
456 {
457  if (psrc == this)
458  return;
459 
460  // This sets the number of vertices to be the same as psrc, and wires
461  // the corresponding vertices to the corresponding points.
462  // This class doesn't have any more data, so we didn't need to
463  // override copyPrimitive, but if you add any more data, copy it
464  // below.
466 
467  // Uncomment this to access other data
468  //const GEO_PrimTetra *src = (const GEO_PrimTetra *)psrc;
469 }
470 
472 GEO_PrimTetra::copy(int preserve_shared_pts) const
473 {
474  GEO_Primitive *clone = GEO_Primitive::copy(preserve_shared_pts);
475 
476  if (!clone)
477  return nullptr;
478 
479  // This class doesn't have any more data to copy, so we didn't need
480  // to override this function, but if you add any, copy them here.
481 
482  // Uncomment this to access other data
483  //GEO_PrimTetra *tet = (GEO_PrimTetra*)clone;
484 
485  return clone;
486 }
487 
488 void
490  const GA_Primitive *prim_src,
491  const GA_MergeMap &map)
492 {
493  UT_ASSERT( prim_src != this );
494 
495  // This copies the vertex list, with offsets mapped using map.
496  GEO_Primitive::copyUnwiredForMerge(prim_src, map);
497 
498  // If you add any data that must be copyied from src in order for this
499  // to be a separate but identical copy of src, copy it here,
500  // but make sure it's safe to call copyUnwiredForMerge on multiple
501  // primitives at the same time.
502 
503  // Uncomment this to access other data
504  //const GEO_PrimTetra *src = static_cast<const GEO_PrimTetra *>(prim_src);
505 }
506 
508 GEO_PrimTetra::build(GA_Detail *gdp, bool appendPoints)
509 {
511 
512  // Add 4 vertices. The constructor did not add any.
513  GA_Offset vtxoff = gdp->appendVertexBlock(PT_PER_TET);
514  tet->myVertexList.setTrivial(vtxoff, PT_PER_TET);
515  GA_ATITopology *vtx_to_prim = gdp->getTopology().getPrimitiveRef();
516  if (vtx_to_prim)
517  {
518  GA_Offset primoff = tet->getMapOffset();
519  for (GA_Size i = 0; i < PT_PER_TET; i++)
520  vtx_to_prim->setLink(vtxoff+i, primoff);
521  }
522 
523  // NOTE: By design, npts will always be 4 (i.e. PT_PER_TET) for a tetrahedron.
524  // The call to getVertexCount() is just as an example.
525  const GA_Size npts = tet->getVertexCount();
526  if (appendPoints)
527  {
528  GEO_Primitive *prim = tet;
529  const GA_Offset startptoff = gdp->appendPointBlock(npts);
530  for (GA_Size i = 0; i < npts; i++)
531  {
532  prim->setPointOffset(i, startptoff+i);
533  }
534  }
535  return tet;
536 }
537 
538 namespace {
539 
540 class geo_SetTopoPrimsParallel
541 {
542 public:
543  geo_SetTopoPrimsParallel(
545  const GA_Offset startprim,
546  const GA_Offset startvtx)
547  : myTopology(topology)
548  , myStartPrim(startprim)
549  , myStartVtx(startvtx)
550  {}
551 
552  void operator()(const GA_SplittableRange &r) const
553  {
555  GA_Offset end;
556  for (GA_Iterator it = r.begin(); it.blockAdvance(start, end); )
557  {
558  GA_Size relativestart = start - myStartVtx;
559  GA_Size relativeend = end - myStartVtx;
560  GA_Offset tet = (relativestart / PT_PER_TET) + myStartPrim;
561  GA_Size vert = relativestart % PT_PER_TET;
562  GA_Offset endtet = (relativeend / PT_PER_TET) + myStartPrim;
563 
564  // The range may start after the beginning of the first tet
565  if (vert != 0)
566  {
567  for (; vert < PT_PER_TET; ++vert)
568  myTopology->setLink(start++, tet);
569  ++tet;
570  }
571 
572  // Full tets in the middle
573  for (; tet != endtet; ++tet)
574  {
575  for (GA_Size i = 0; i < PT_PER_TET; ++i)
576  myTopology->setLink(start++, tet);
577  }
578 
579  // The range may end before the end of the last tet
580  if (start < end)
581  {
582  while (start < end)
583  myTopology->setLink(start++, tet);
584  }
585  }
586  }
587 
588 private:
589  GA_ATITopology *myTopology;
590  const GA_Offset myStartPrim;
591  const GA_Offset myStartVtx;
592 };
593 
594 }
595 
596 // Instantiation here, because GCC can't figure out templates, even in header files
598 
599 GA_Offset
601  const GA_Offset startpt,
602  const GA_Size npoints,
603  const GA_Size ntets,
604  const int *tetpointnumbers)
605 {
606  if (ntets == 0)
607  return GA_INVALID_OFFSET;
608 
609  TIMING_DEF;
610 
611  const GA_Offset endpt = startpt + npoints;
612  const GA_Size nvertices = ntets * PT_PER_TET;
613 
614  // Create the empty primitives
615  const GA_Offset startprim = detail->appendPrimitiveBlock(GEO_PrimTetra::theTypeId(), ntets);
616 
617  TIMING_LOG("Creating primitives");
618 
619  // Create the uninitialized vertices
620  const GA_Offset startvtx = detail->appendVertexBlock(nvertices);
621  const GA_Offset endvtx = startvtx + nvertices;
622 
623  TIMING_LOG("Appending vertices");
624 
625  // Set the vertex-to-point mapping
626  GA_ATITopology *vertexToPoint = detail->getTopology().getPointRef();
627  if (vertexToPoint)
628  {
629  UTparallelForLightItems(GA_SplittableRange(GA_Range(detail->getVertexMap(), startvtx, endvtx)),
630  geo_SetTopoMappedParallel(vertexToPoint, startpt, startvtx, tetpointnumbers));
631 
632  TIMING_LOG("Setting vtx->pt");
633  }
634 
635  // Set the vertex-to-primitive mapping
636  GA_ATITopology *vertexToPrim = detail->getTopology().getPrimitiveRef();
637  if (vertexToPrim)
638  {
639  UTparallelForLightItems(GA_SplittableRange(GA_Range(detail->getVertexMap(), startvtx, endvtx)),
640  geo_SetTopoPrimsParallel(vertexToPrim, startprim, startvtx));
641 
642  TIMING_LOG("Setting vtx->prm");
643  }
644 
645  // Set the vertex lists of the tets
647  geo_SetVertexListsParallel(detail, startprim, startvtx));
648 
649  TIMING_LOG("Setting vertex lists");
650 
651  // Check whether the linked list topologies need to be set
652  GA_ATITopology *pointToVertex = detail->getTopology().getVertexRef();
653  GA_ATITopology *vertexToNext = detail->getTopology().getVertexNextRef();
654  GA_ATITopology *vertexToPrev = detail->getTopology().getVertexPrevRef();
655  if (pointToVertex && vertexToNext && vertexToPrev)
656  {
657  // Create a trivial map from 0 to nvertices
658  UT_IntArray map(nvertices, nvertices);
659 
660  TIMING_LOG("Allocating map");
661 
662  UTparallelForLightItems(UT_BlockedRange<GA_Size>(0, nvertices), geo_TrivialArrayParallel(map));
663 
664  TIMING_LOG("Creating trivial map");
665 
666  // Sort the map in parallel according to the point offsets of the vertices
667  UTparallelSort(map.array(), map.array() + nvertices, geo_VerticesByPointCompare<true>(tetpointnumbers));
668 
669  TIMING_LOG("Sorting array map");
670 
671  // Create arrays for the next vertex and prev vertex in parallel
672  // If we wanted to do this in geo_LinkToposParallel, we would first
673  // have to create an inverse map anyway to find out where vertices
674  // are in map, so this saves re-traversing things.
675  UT_IntArray nextvtxarray(nvertices, nvertices);
676  UT_IntArray prevvtxarray(nvertices, nvertices);
677  UT_Lock lock;
679  geo_NextPrevParallel(map, tetpointnumbers, nextvtxarray, prevvtxarray, startvtx, startpt, pointToVertex, vertexToPrev, lock));
680 
681  TIMING_LOG("Finding next/prev");
682 
683  // Set the point-to-vertex topology in parallel
684  // This needs to be done after constructing the next/prev array,
685  // because it checks for existing vertices using the points.
687  geo_Pt2VtxTopoParallel(pointToVertex, map, tetpointnumbers, startvtx, startpt));
688 
689  TIMING_LOG("Setting pt->vtx");
690 
691  // Clear up some memory before filling up the linked list topologies
692  map.setCapacity(0);
693 
694  TIMING_LOG("Clearing map");
695 
696  // Fill in the linked list topologies
697  UTparallelForLightItems(GA_SplittableRange(GA_Range(detail->getVertexMap(), startvtx, endvtx)),
698  geo_LinkToposParallel(vertexToNext, vertexToPrev, nextvtxarray, prevvtxarray, startvtx));
699 
700  TIMING_LOG("Setting links");
701  }
702 
703  return startprim;
704 }
705 
706 // Static callback for our factory.
707 static void
708 geoNewPrimTetraBlock(
709  GA_Primitive **new_prims,
710  GA_Size nprimitives,
711  GA_Detail &gdp,
712  GA_Offset start_offset,
713  const GA_PrimitiveDefinition &def,
714  bool allowed_to_parallelize)
715 {
716  if (allowed_to_parallelize && nprimitives >= 4*GA_PAGE_SIZE)
717  {
718  // Allocate them in parallel if we're allocating many.
719  // This is using the C++11 lambda syntax to make a functor.
720  UTparallelForLightItems(UT_BlockedRange<GA_Offset>(start_offset, start_offset+nprimitives),
721  [new_prims,&gdp,start_offset](const UT_BlockedRange<GA_Offset> &r){
722  GA_Offset primoff(r.begin());
723  GA_Primitive **pprims = new_prims+(primoff-start_offset);
724  GA_Offset endprimoff(r.end());
725  for ( ; primoff != endprimoff; ++primoff, ++pprims)
726  *pprims = new GEO_PrimTetra(gdp, primoff);
727  });
728  }
729  else
730  {
731  // Allocate them serially if we're only allocating a few.
732  GA_Offset endprimoff(start_offset + nprimitives);
733  for (GA_Offset primoff(start_offset); primoff != endprimoff; ++primoff, ++new_prims)
734  *new_prims = new GEO_PrimTetra(gdp, primoff);
735  }
736 }
737 
738 void
740 {
741  // Ignore double registration
742  if (theDefinition)
743  return;
744 
745  theDefinition = factory->registerDefinition(
746  "HDK_Tetrahedron",
747  geoNewPrimTetraBlock,
749  "hdk_tetrahedron");
750 
751  // NOTE: Calling setHasLocalTransform(false) is redundant,
752  // but if your custom primitive has a local transform,
753  // it must call setHasLocalTransform(true).
754  theDefinition->setHasLocalTransform(false);
755  registerIntrinsics(*theDefinition);
756 
757 #ifndef TETRA_GR_PRIMITIVE
758 
759  // Register the GT tesselation too (now we know what type id we have)
761 
762 #else
763 
764  // Since we're only registering one hook, the priority does not matter.
765  const int hook_priority = 0;
766 
768  new GR_PrimTetraHook,
769  theDefinition->getId(),
770  hook_priority,
772 #endif
773 
774 }
775 
776 int64
778 {
779  // NOTE: The only memory owned by this primitive is itself
780  // and its base class.
781  int64 mem = sizeof(*this) + getBaseMemoryUsage();
782  return mem;
783 }
784 
785 void
787 {
788  // NOTE: There's no shared memory in this primitive,
789  // apart from possibly in the case class.
790  counter.countUnshared(sizeof(*this));
791  countBaseMemory(counter);
792 }
793 
794 static GEO_Primitive *
795 geo_buildPoly(GEO_PrimTetra *tet, GEO_Detail *gdp, int v1, int v2, int v3,
796  GEO_ConvertParms &parms)
797 {
798  GEO_PrimPoly *poly = GEO_PrimPoly::build(gdp, 3, false, false);
799 
801  if (parms.preserveGroups)
803 
804  GA_VertexWrangler &wrangler = parms.getWranglers().getVertex();
805  gdp->copyVertex(poly->getVertexOffset(0), tet->getVertexOffset(v1), wrangler, NULL);
806  gdp->copyVertex(poly->getVertexOffset(1), tet->getVertexOffset(v2), wrangler, NULL);
807  gdp->copyVertex(poly->getVertexOffset(2), tet->getVertexOffset(v3), wrangler, NULL);
808 
809  return poly;
810 }
811 
814 {
815  GEO_Primitive *prim = NULL;
816  GEO_Detail *gdp = getParent();
817 
819  {
820  geo_buildPoly(this, gdp, 0, 1, 2, parms);
821  geo_buildPoly(this, gdp, 1, 3, 2, parms);
822  geo_buildPoly(this, gdp, 1, 0, 3, parms);
823  prim = geo_buildPoly(this, gdp, 0, 2, 3, parms);
824  }
825 
826  return prim;
827 }
828 
831 {
832  GEO_Primitive *prim = convertNew(parms);
833  GEO_Detail *gdp = getParent();
834  GA_PrimitiveGroup *group;
835 
836  if (prim)
837  {
838  if (usedpts) addPointRefToGroup(*usedpts);
839  if ((group = parms.getDeletePrimitives()))
840  group->add(this);
841  else gdp->deletePrimitive(*this, !usedpts);
842  }
843  return prim;
844 }
845 
846 void
848 {
849  // No need here.
850 }
851 
852 int
854  float tmax, float , float *distance,
855  UT_Vector3 *pos, UT_Vector3 *nml,
856  int, float *, float *, int) const
857 {
858  // TODO: Check each of the 4 triangles for intersection,
859  // instead of just checking the bounding box.
860 
861  UT_BoundingBox bbox;
862  getBBox(&bbox);
863 
864  float dist;
865  int result = bbox.intersectRay(org, dir, tmax, &dist, nml);
866  if (result)
867  {
868  if (distance) *distance = dist;
869  if (pos) *pos = org + dist * dir;
870  }
871  return result;
872 }
873 
874 // This is the usual DSO hook.
875 extern "C" {
876 void
878 {
880 }
881 }
882 
883 // Implement intrinsic attributes
884 enum
885 {
886  geo_INTRINSIC_ADDRESS, // Return the address of the primitive
887  geo_INTRINSIC_AUTHOR, // Developer's name
888  geo_NUM_INTRINSICS // Number of intrinsics
889 };
890 
891 namespace
892 {
893  static int64
894  intrinsicAddress(const GEO_PrimTetra *prim)
895  {
896  // An intrinsic attribute which returns the address of the primitive
897  return (int64)prim;
898  }
899  static const char *
900  intrinsicAuthor(const GEO_PrimTetra *)
901  {
902  // An intrinsic attribute which returns the HDK author's name
903  return "My Name";
904  }
905 };
906 
907 // Start defining intrinsic attributes, we pass our class name and the number
908 // of intrinsic attributes.
910 
911  // See GA_IntrinsicMacros.h for further information on how to define
912  // intrinsic attribute evaluators.
914  intrinsicAddress)
915  GA_INTRINSIC_S(GEO_PrimTetra, geo_INTRINSIC_AUTHOR, "author",
916  intrinsicAuthor)
917 
918 // End intrinsic definitions (our class and our base class)
919 GA_END_INTRINSIC_DEF(GEO_PrimTetra, GEO_Primitive)
int intersectRay(const UT_Vector3T< T > &org, const UT_Vector3T< T > &dir, T tmax=1E17F, T *distance=0, UT_Vector3T< T > *nml=0) const
void UTparallelSort(RandomAccessIterator begin, RandomAccessIterator end, const Compare &compare)
static void registerMyself(GA_PrimitiveFactory *factory)
GA_VertexWrangler & getVertex()
virtual void copyUnwiredForMerge(const GA_Primitive *src, const GA_MergeMap &map)
virtual void copyUnwiredForMerge(const GA_Primitive *src, const GA_MergeMap &map)
bool saveVertexArray(UT_JSONWriter &w, const GA_SaveMap &map) const
GA_API const UT_StringHolder dist
#define GA_START_INTRINSIC_DEF(CLASS, NUM_INTRINSICS)
virtual GEO_Primitive * copy(int preserve_shared_pts=0) const
void copyAttributeValues(GA_Offset dest, GA_Offset src)
SYS_FORCE_INLINE GA_Offset getPointOffset(GA_Size i) const
Definition: GA_Primitive.h:246
virtual const GA_PrimitiveJSON * getJSON() const
static GEO_PrimTetra * build(GA_Detail *gdp, bool appendpts=true)
Optional build function.
virtual void copyPrimitive(const GEO_Primitive *src)=0
void setHasLocalTransform(bool x)
Set whether the primitive is has a transform associated with it.
Used to pass options and map offset values during saving.
Definition: GA_SaveMap.h:48
SYS_FORCE_INLINE GA_Size getVertexCount() const
Return the number of vertices used by this primitive.
Definition: GA_Primitive.h:224
Iteration over a range of elements.
Definition: GA_Iterator.h:28
virtual fpreal calcArea() const
virtual const UT_StringHolder & getKeyword(int i) const
virtual bool isEqual(int i, const GA_Primitive *p0, const GA_Primitive *p1) const
GA_ElementWranglerCache & getGroupWranglers()
const GLdouble * v
Definition: glcorearb.h:836
#define PT_PER_TET
Definition: GEO_PrimTetra.C:73
bool blockAdvance(GA_Offset &start, GA_Offset &end)
GLuint start
Definition: glcorearb.h:474
UT_Vector3T< float > UT_Vector3
bool deletePrimitive(GA_Primitive &prim, bool and_points=false)
Definition: GEO_Detail.h:1164
The merge map keeps track of information when merging details.
Definition: GA_MergeMap.h:53
SYS_FORCE_INLINE void setPointOffset(GA_Size i, GA_Offset ptoff)
Definition: GA_Primitive.h:252
void setTrivial(ToType startvalue, GA_Size size)
Makes the list a trivial list with the specified start value and size.
T * array()
Definition: UT_Array.h:614
virtual GEO_Primitive * copy(int preserve_shared_pts=0) const
virtual bool loadField(GA_Primitive *pr, int i, UT_JSONParser &p, const UT_JSONValue &v, const GA_LoadMap &map) const
JSON reader class which handles parsing of JSON or bJSON files.
Definition: UT_JSONParser.h:75
SYS_FORCE_INLINE GEO_Detail * getParent() const
virtual int getBBox(UT_BoundingBox *bbox) const
Class which writes ASCII or binary JSON streams.
Definition: UT_JSONWriter.h:32
Abstract base class for a range membership query object.
GLfloat GLfloat GLfloat v2
Definition: glcorearb.h:817
GEO_PrimTetra * tet(GA_Primitive *p) const
GLfloat GLfloat GLfloat GLfloat v3
Definition: glcorearb.h:818
png_uint_32 i
Definition: png.h:2877
#define GA_INTRINSIC_I(CLASS, ID, NAME, EVAL)
exint GA_Size
Defines the bit width for index and offset types in GA.
Definition: GA_Types.h:211
SYS_FORCE_INLINE int64 getBaseMemoryUsage() const
Report approximate memory usage for myVertexList for subclasses.
Definition: GA_Primitive.h:750
virtual bool evaluatePointRefMap(GA_Offset result_vtx, GA_AttributeRefMap &hlist, fpreal u, fpreal v, uint du, uint dv) const
Evalaute a point given a u,v coordinate (with derivatives)
#define GA_INVALID_OFFSET
Definition: GA_Types.h:654
GA_OffsetList myVertexList
Definition: GA_Primitive.h:791
A range of elements in an index-map.
Definition: GA_Range.h:42
void set(FromType index, ToType value)
Set the index to the value.
GA_Size GA_Offset
Definition: GA_Types.h:617
long long int64
Definition: SYS_Types.h:107
static GA_Offset buildBlock(GA_Detail *detail, const GA_Offset startpt, const GA_Size npoints, const GA_Size ntets, const int *tetpointnumbers)
virtual bool saveField(const GA_Primitive *pr, int i, UT_JSONWriter &w, const GA_SaveMap &map) const
SYS_FORCE_INLINE UT_Vector3 getPos3(GA_Size i) const
Definition: GA_Primitive.h:266
void setCapacity(exint newcapacity)
Definition: UT_ArrayImpl.h:751
GA_PrimitiveDefinition * registerDefinition(const UT_StringHolder &name, GA_PrimitiveBlockConstructor construct, GA_PrimitiveFamilyMask mask=GA_FAMILY_NONE, const UT_StringHolder &label=UT_StringHolder(), const UT_StringHolder &icon=UT_StringHolder())
static DM_RenderTable * getTable()
virtual UT_Vector3 baryCenter() const
Hook has no special behaviour.
const GA_IndexMap & getPointMap() const
Definition: GA_Detail.h:677
virtual UT_Vector3 computeNormal() const
virtual fpreal calcVolume(const UT_Vector3 &refpt) const
virtual GEO_Primitive * convertNew(GEO_ConvertParms &parms)
The primitive render hook which creates GR_PrimTetra objects.
Definition: GR_PrimTetra.h:28
GA_Iterator begin() const
void newGeometryPrim(GA_PrimitiveFactory *factory)
#define GA_INTRINSIC_S(CLASS, ID, NAME, EVAL)
SIM_DerScalar length() const
GA_Offset appendPrimitiveBlock(const GA_PrimitiveTypeId &type, GA_Size nprimitives)
Append a contiguous block of primitives by GA_PrimitiveTypeId.
virtual void copyPrimitive(const GEO_Primitive *src)
T distance(const UT_Vector4T< T > &v1, const UT_Vector4T< T > &v2)
Definition: UT_Vector4.h:698
SYS_FORCE_INLINE GA_Offset appendPointBlock(GA_Size npoints)
Append new points, returning the first offset of the contiguous block.
Definition: GA_Detail.h:281
virtual int intersectRay(const UT_Vector3 &o, const UT_Vector3 &d, float tmax=1E17F, float tol=1E-12F, float *distance=0, UT_Vector3 *pos=0, UT_Vector3 *nml=0, int accurate=0, float *u=0, float *v=0, int ignoretrim=1) const
SYS_FORCE_INLINE const GA_ATITopology * getVertexNextRef() const
Definition: GA_Topology.h:229
GT_API const UT_StringHolder topology
static const UT_StringHolder theEmptyString
fpreal64 dot(const CE_VectorT< T > &a, const CE_VectorT< T > &b)
Definition: CE_Vector.h:218
GLuint GLuint end
Definition: glcorearb.h:474
GLintptr offset
Definition: glcorearb.h:664
GEO_PrimTetra(GA_Detail &d, GA_Offset offset)
Definition: GEO_PrimTetra.C:75
Provide a JSON interface to a primitive.
template void UTparallelForLightItems(const UT_BlockedRange< GA_Size > &, const GEO_PrimTetra::geo_SetVertexListsParallel &)
virtual GEO_Primitive * convert(GEO_ConvertParms &parms, GA_PointGroup *usedpts=0)
A handle to simplify manipulation of multiple attributes.
virtual void normal(NormalComp &output) const
virtual int64 getMemoryUsage() const
Report approximate memory usage.
Options during loading.
Definition: GA_LoadMap.h:42
GA_Offset getVertexOffset(GA_Size load_index) const
Map the load_index to the actual vertex number in the detail.
Definition: GA_LoadMap.h:134
const GA_IndexMap & getVertexMap() const
Definition: GA_Detail.h:678
virtual fpreal calcPerimeter() const
static const GA_PrimitiveTypeId & theTypeId()
Allows you to find out what this primitive type was named.
virtual bool loadField(GA_Primitive *pr, int i, UT_JSONParser &p, const GA_LoadMap &map) const
void addPointRefToGroup(GA_PointGroup &grp) const
virtual void stashed(bool beingstashed, GA_Offset offset=GA_INVALID_OFFSET)
Definition: GEO_PrimTetra.C:94
GA_ElementWranglerCache & getWranglers()
Returns a GA_ElementWranglerCache using mySourceDetail and myDestDetail.
static void registerPrimitive(const GA_PrimitiveTypeId &id)
Register the GT collector.
Definition: GT_PrimTetra.C:30
void enlargeBounds(const UT_Vector3T< T > &min, const UT_Vector3T< T > &max)
SYS_FORCE_INLINE const GA_ATITopology * getPrimitiveRef() const
Definition: GA_Topology.h:223
GA_PrimCompat::TypeMask toType() const
const GEO_PrimTetra * tet(const GA_Primitive *p) const
virtual int detachPoints(GA_PointGroup &grp)
void copyVertex(GEO_Vertex dest, const GEO_Vertex &src, int shallow=0) const
#define GA_PAGE_SIZE
Definition: GA_Types.h:200
#define TIMING_DEF
Definition: GEO_PrimTetra.C:64
void add(const GA_Primitive *prim)
GLint GLsizei count
Definition: glcorearb.h:404
GA_Topology & getTopology()
Definition: GA_Detail.h:734
GLfloat v0
Definition: glcorearb.h:815
int64 parseUniformArray(T *data, int64 len)
SYS_FORCE_INLINE bool containsOffset(GA_Offset offset) const
void countUnshared(size_t size)
SYS_FORCE_INLINE const GA_PrimitiveTypeId & getId() const
The unique ID assigned by the GA_PrimitiveFactory.
SYS_FORCE_INLINE const GA_ATITopology * getVertexPrevRef() const
Definition: GA_Topology.h:227
double fpreal
Definition: SYS_Types.h:270
virtual GA_Offset getVertexOffset(GA_Size index) const final
Definition: GEO_TriMesh.h:149
GA_Primitive * appendPrimitive(const GA_PrimitiveTypeId &type)
Append a primitive by GA_PrimitiveTypeId.
virtual bool saveField(const GA_Primitive *pr, int i, UT_JSONValue &v, const GA_SaveMap &map) const
SYS_FORCE_INLINE const GA_ATITopology * getVertexRef() const
Definition: GA_Topology.h:225
SYS_FORCE_INLINE GA_Offset getMapOffset() const
Gets the offset of this primitive in the detail containing it.
Definition: GA_Primitive.h:138
void zeroElement(GA_AttributeOwner downer, GA_Offset dest) const
Zero an attribute. This is equivalent to a weighted sum of 0 elements.
GLfloat GLfloat v1
Definition: glcorearb.h:816
SYS_FORCE_INLINE void initBounds()
#define TIMING_LOG(msg)
Definition: GEO_PrimTetra.C:65
SYS_FORCE_INLINE GA_Offset getVertexOffset(GA_Size primvertexnum) const
Definition: GA_Primitive.h:232
Class to store JSON objects as C++ objects.
Definition: UT_JSONValue.h:75
virtual GA_DereferenceStatus dereferencePoints(const GA_RangeMemberQuery &pt_q, bool dry_run=false)
bool registerGEOHook(GUI_PrimitiveHook *hook, GA_PrimitiveTypeId geo_type, int priority, GUI_PrimitiveHookFlags flags=GUI_HOOK_FLAG_NONE, int hook_ver=GUI_PRIMITIVE_HOOK_VERSION)
Register a geometry primitive render hook Register a primitive hook that uses a GEO_Primitive as its ...
SYS_FORCE_INLINE ToType get(FromType index) const
Get the the value at the index.
Container class for all geometry.
Definition: GA_Detail.h:95
bool jsonVertexArray(UT_JSONWriter &w, const GA_SaveMap &save) const
Save the offsets by doing the mapping to the vertices in the save map.
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:856
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:126
Definition of a geometric primitive.
GLboolean r
Definition: glcorearb.h:1221
virtual int getEntries() const
Return the number of data fields in the primitive private schema.
bool loadVertexArray(UT_JSONParser &p, const GA_LoadMap &map)
GA_PrimitiveGroup * getDeletePrimitives(GEO_Detail *gdp=nullptr)
virtual bool contains(GA_Offset) const =0
GEO_API const TypeMask GEOPRIMPOLY
static GA_IntrinsicManager::Registrar registerIntrinsics(GA_PrimitiveDefinition &defn)
void copyValue(GA_AttributeOwner downer, GA_Offset doffset, GA_AttributeOwner sowner, GA_Offset soffset) const
Automatically expand attribute data pages for threading.
void countBaseMemory(UT_MemoryCounter &counter) const
Declare prior to use.
SYS_FORCE_INLINE const GA_ATITopology * getPointRef() const
Definition: GA_Topology.h:221
GA_PrimitiveWrangler & getPrimitive()
virtual void countMemory(UT_MemoryCounter &counter) const
SIM_DerVector3 cross(const SIM_DerVector3 &lhs, const SIM_DerVector3 &rhs)
virtual bool isDegenerate() const
virtual void stashed(bool beingstashed, GA_Offset offset=GA_INVALID_OFFSET)
#define GA_END_INTRINSIC_DEF(CLASS, BASECLASS)
virtual GA_DereferenceStatus dereferencePoint(GA_Offset point, bool dry_run=false)
GA_API const UT_StringHolder area
SYS_FORCE_INLINE GA_Offset appendVertexBlock(GA_Size nvertices)
Append new vertices, returning the first offset of the contiguous block.
Definition: GA_Detail.h:444
static GEO_PrimPoly * build(GA_Detail *gdp, GA_Size nvertices, bool open=false, bool appendpts=true)
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:794
SYS_FORCE_INLINE void setLink(GA_Offset ai, GA_Offset v)