HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros 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 
266 {
267 public:
269  {
270  }
271  virtual ~geo_PrimTetraJSON() {}
272 
273  enum
274  {
277  };
278 
279  const GEO_PrimTetra *tet(const GA_Primitive *p) const
280  { return static_cast<const GEO_PrimTetra *>(p); }
282  { return static_cast<GEO_PrimTetra *>(p); }
283 
284  virtual int getEntries() const { return geo_TBJ_ENTRIES; }
285  virtual const char *getKeyword(int i) const
286  {
287  switch (i)
288  {
289  case geo_TBJ_VERTEX: return "vertex";
290  case geo_TBJ_ENTRIES: break;
291  }
292  UT_ASSERT(0);
293  return NULL;
294  }
295  virtual bool saveField(const GA_Primitive *pr, int i,
296  UT_JSONWriter &w, const GA_SaveMap &map) const
297  {
298  switch (i)
299  {
300  case geo_TBJ_VERTEX:
301  return tet(pr)->saveVertexArray(w, map);
302  case geo_TBJ_ENTRIES:
303  break;
304  }
305  return false;
306  }
307  virtual bool saveField(const GA_Primitive *pr, int i,
308  UT_JSONValue &v, const GA_SaveMap &map) const
309  {
310  switch (i)
311  {
312  case geo_TBJ_VERTEX:
313  return false;
314  case geo_TBJ_ENTRIES:
315  break;
316  }
317  UT_ASSERT(0);
318  return false;
319  }
320  virtual bool loadField(GA_Primitive *pr, int i, UT_JSONParser &p,
321  const GA_LoadMap &map) const
322  {
323  switch (i)
324  {
325  case geo_TBJ_VERTEX:
326  return tet(pr)->loadVertexArray(p, map);
327  case geo_TBJ_ENTRIES:
328  break;
329  }
330  UT_ASSERT(0);
331  return false;
332  }
333  virtual bool loadField(GA_Primitive *pr, int i, UT_JSONParser &p,
334  const UT_JSONValue &v, const GA_LoadMap &map) const
335  {
336  switch (i)
337  {
338  case geo_TBJ_VERTEX:
339  return false;
340  case geo_TBJ_ENTRIES:
341  break;
342  }
343  UT_ASSERT(0);
344  return false;
345  }
346  virtual bool isEqual(int i, const GA_Primitive *p0,
347  const GA_Primitive *p1) const
348  {
349  switch (i)
350  {
351  case geo_TBJ_VERTEX:
352  return false;
353  case geo_TBJ_ENTRIES:
354  break;
355  }
356  UT_ASSERT(0);
357  return false;
358  }
359 private:
360 };
361 }
362 
363 static const GA_PrimitiveJSON *
364 tetrahedronJSON()
365 {
366  static GA_PrimitiveJSON *theJSON = NULL;
367 
368  if (!theJSON)
369  theJSON = new geo_PrimTetraJSON();
370  return theJSON;
371 }
372 
373 const GA_PrimitiveJSON *
375 {
376  return tetrahedronJSON();
377 }
378 
379 
380 
381 bool
383  const GA_SaveMap &map) const
384 {
385  return myVertexList.jsonVertexArray(w, map);
386 }
387 
388 bool
390 {
391  GA_Offset startvtxoff = map.getVertexOffset();
392 
393  int64 vtxoffs[PT_PER_TET];
394  int nvertex = p.parseUniformArray(vtxoffs, PT_PER_TET);
395  if (startvtxoff != GA_Offset(0))
396  {
397  for (int i = 0; i < nvertex; i++)
398  {
399  if (vtxoffs[i] >= 0)
400  vtxoffs[i] += GA_Size(startvtxoff);
401  }
402  }
403  for (int i = nvertex; i < PT_PER_TET; ++i)
404  vtxoffs[i] = GA_INVALID_OFFSET;
405  myVertexList.set(vtxoffs, PT_PER_TET, GA_Offset(0));
406  if (nvertex < PT_PER_TET)
407  return false;
408  return true;
409 }
410 
411 
412 int
414 {
415  bbox->initBounds(getPos3(0));
416  bbox->enlargeBounds(getPos3(1));
417  bbox->enlargeBounds(getPos3(2));
418  bbox->enlargeBounds(getPos3(3));
419  return 1;
420 }
421 
424 {
425  UT_Vector3 sum(0,0,0);
426 
427  for (int i = 0; i < PT_PER_TET; ++i)
428  sum += getPos3(i);
429 
430  sum /= PT_PER_TET;
431 
432  return sum;
433 }
434 
435 bool
437 {
438  // Duplicate points means degenerate.
439  for (int i = 0; i < PT_PER_TET; i++)
440  {
441  for (int j = i+1; j < PT_PER_TET; j++)
442  {
443  if (getPointOffset(i) == getPointOffset(j))
444  return true;
445  }
446  }
447  return false;
448 }
449 
450 void
452 {
453  if (psrc == this)
454  return;
455 
456  // This sets the number of vertices to be the same as psrc, and wires
457  // the corresponding vertices to the corresponding points.
458  // This class doesn't have any more data, so we didn't need to
459  // override copyPrimitive, but if you add any more data, copy it
460  // below.
462 
463  // Uncomment this to access other data
464  //const GEO_PrimTetra *src = (const GEO_PrimTetra *)psrc;
465 }
466 
468 GEO_PrimTetra::copy(int preserve_shared_pts) const
469 {
470  GEO_Primitive *clone = GEO_Primitive::copy(preserve_shared_pts);
471 
472  if (!clone)
473  return nullptr;
474 
475  // This class doesn't have any more data to copy, so we didn't need
476  // to override this function, but if you add any, copy them here.
477 
478  // Uncomment this to access other data
479  //GEO_PrimTetra *tet = (GEO_PrimTetra*)clone;
480 
481  return clone;
482 }
483 
484 void
486  const GA_Primitive *prim_src,
487  const GA_MergeMap &map)
488 {
489  UT_ASSERT( prim_src != this );
490 
491  // This copies the vertex list, with offsets mapped using map.
492  GEO_Primitive::copyUnwiredForMerge(prim_src, map);
493 
494  // If you add any data that must be copyied from src in order for this
495  // to be a separate but identical copy of src, copy it here,
496  // but make sure it's safe to call copyUnwiredForMerge on multiple
497  // primitives at the same time.
498 
499  // Uncomment this to access other data
500  //const GEO_PrimTetra *src = static_cast<const GEO_PrimTetra *>(prim_src);
501 }
502 
504 GEO_PrimTetra::build(GA_Detail *gdp, bool appendPoints)
505 {
507 
508  // Add 4 vertices. The constructor did not add any.
509  GA_Offset vtxoff = gdp->appendVertexBlock(PT_PER_TET);
510  tet->myVertexList.setTrivial(vtxoff, PT_PER_TET);
511  GA_ATITopology *vtx_to_prim = gdp->getTopology().getPrimitiveRef();
512  if (vtx_to_prim)
513  {
514  GA_Offset primoff = tet->getMapOffset();
515  for (GA_Size i = 0; i < PT_PER_TET; i++)
516  vtx_to_prim->setLink(vtxoff+i, primoff);
517  }
518 
519  // NOTE: By design, npts will always be 4 (i.e. PT_PER_TET) for a tetrahedron.
520  // The call to getVertexCount() is just as an example.
521  const GA_Size npts = tet->getVertexCount();
522  if (appendPoints)
523  {
524  GEO_Primitive *prim = tet;
525  const GA_Offset startptoff = gdp->appendPointBlock(npts);
526  for (GA_Size i = 0; i < npts; i++)
527  {
528  prim->setPointOffset(i, startptoff+i);
529  }
530  }
531  return tet;
532 }
533 
534 namespace {
535 
536 class geo_SetTopoPrimsParallel
537 {
538 public:
539  geo_SetTopoPrimsParallel(GA_ATITopology *topology, const GA_Offset startprim,
540  const GA_Offset startvtx, const GA_Size ntets)
541  : myTopology(topology)
542  , myStartPrim(startprim)
543  , myStartVtx(startvtx)
544  , myNumTets(ntets)
545  {}
546 
547  void operator()(const GA_SplittableRange &r) const
548  {
550  GA_Offset end;
551  for (GA_Iterator it = r.begin(); it.blockAdvance(start, end); )
552  {
553  GA_Size relativestart = start - myStartVtx;
554  GA_Size relativeend = end - myStartVtx;
555  GA_Offset tet = (relativestart / PT_PER_TET) + myStartPrim;
556  GA_Size vert = relativestart % PT_PER_TET;
557  GA_Offset endtet = (relativeend / PT_PER_TET) + myStartPrim;
558 
559  // The range may start after the beginning of the first tet
560  if (vert != 0)
561  {
562  for (; vert < PT_PER_TET; ++vert)
563  myTopology->setLink(start++, tet);
564  ++tet;
565  }
566 
567  // Full tets in the middle
568  for (; tet != endtet; ++tet)
569  {
570  for (GA_Size i = 0; i < PT_PER_TET; ++i)
571  myTopology->setLink(start++, tet);
572  }
573 
574  // The range may end before the end of the last tet
575  if (start < end)
576  {
577  while (start < end)
578  myTopology->setLink(start++, tet);
579  }
580  }
581  }
582 
583 private:
584  GA_ATITopology *myTopology;
585  const GA_Offset myStartPrim;
586  const GA_Offset myStartVtx;
587  const GA_Size myNumTets;
588 };
589 
590 }
591 
592 // Instantiation here, because GCC can't figure out templates, even in header files
594 
595 GA_Offset
597  const GA_Offset startpt,
598  const GA_Size npoints,
599  const GA_Size ntets,
600  const int *tetpointnumbers)
601 {
602  if (ntets == 0)
603  return GA_INVALID_OFFSET;
604 
605  TIMING_DEF;
606 
607  const GA_Offset endpt = startpt + npoints;
608  const GA_Size nvertices = ntets * PT_PER_TET;
609 
610  // Create the empty primitives
611  const GA_Offset startprim = detail->appendPrimitiveBlock(GEO_PrimTetra::theTypeId(), ntets);
612 
613  TIMING_LOG("Creating primitives");
614 
615  // Create the uninitialized vertices
616  const GA_Offset startvtx = detail->appendVertexBlock(nvertices);
617  const GA_Offset endvtx = startvtx + nvertices;
618 
619  TIMING_LOG("Appending vertices");
620 
621  // Set the vertex-to-point mapping
622  GA_ATITopology *vertexToPoint = detail->getTopology().getPointRef();
623  if (vertexToPoint)
624  {
625  UTparallelForLightItems(GA_SplittableRange(GA_Range(detail->getVertexMap(), startvtx, endvtx)),
626  geo_SetTopoMappedParallel(vertexToPoint, startpt, startvtx, tetpointnumbers));
627 
628  TIMING_LOG("Setting vtx->pt");
629  }
630 
631  // Set the vertex-to-primitive mapping
632  GA_ATITopology *vertexToPrim = detail->getTopology().getPrimitiveRef();
633  if (vertexToPrim)
634  {
635  UTparallelForLightItems(GA_SplittableRange(GA_Range(detail->getVertexMap(), startvtx, endvtx)),
636  geo_SetTopoPrimsParallel(vertexToPrim, startprim, startvtx, ntets));
637 
638  TIMING_LOG("Setting vtx->prm");
639  }
640 
641  // Set the vertex lists of the tets
643  geo_SetVertexListsParallel(detail, startprim, startvtx));
644 
645  TIMING_LOG("Setting vertex lists");
646 
647  // Check whether the linked list topologies need to be set
648  GA_ATITopology *pointToVertex = detail->getTopology().getVertexRef();
649  GA_ATITopology *vertexToNext = detail->getTopology().getVertexNextRef();
650  GA_ATITopology *vertexToPrev = detail->getTopology().getVertexPrevRef();
651  if (pointToVertex && vertexToNext && vertexToPrev)
652  {
653  // Create a trivial map from 0 to nvertices
654  UT_IntArray map(nvertices, nvertices);
655 
656  TIMING_LOG("Allocating map");
657 
658  UTparallelForLightItems(UT_BlockedRange<GA_Size>(0, nvertices), geo_TrivialArrayParallel(map));
659 
660  TIMING_LOG("Creating trivial map");
661 
662  // Sort the map in parallel according to the point offsets of the vertices
663  UTparallelSort(map.array(), map.array() + nvertices, geo_VerticesByPointCompare<true>(tetpointnumbers));
664 
665  TIMING_LOG("Sorting array map");
666 
667  // Create arrays for the next vertex and prev vertex in parallel
668  // If we wanted to do this in geo_LinkToposParallel, we would first
669  // have to create an inverse map anyway to find out where vertices
670  // are in map, so this saves re-traversing things.
671  UT_IntArray nextvtxarray(nvertices, nvertices);
672  UT_IntArray prevvtxarray(nvertices, nvertices);
673  UT_Lock lock;
675  geo_NextPrevParallel(map, tetpointnumbers, nextvtxarray, prevvtxarray, startvtx, startpt, pointToVertex, vertexToPrev, lock));
676 
677  TIMING_LOG("Finding next/prev");
678 
679  // Set the point-to-vertex topology in parallel
680  // This needs to be done after constructing the next/prev array,
681  // because it checks for existing vertices using the points.
683  geo_Pt2VtxTopoParallel(pointToVertex, map, tetpointnumbers, startvtx, startpt));
684 
685  TIMING_LOG("Setting pt->vtx");
686 
687  // Clear up some memory before filling up the linked list topologies
688  map.setCapacity(0);
689 
690  TIMING_LOG("Clearing map");
691 
692  // Fill in the linked list topologies
693  UTparallelForLightItems(GA_SplittableRange(GA_Range(detail->getVertexMap(), startvtx, endvtx)),
694  geo_LinkToposParallel(vertexToNext, vertexToPrev, nextvtxarray, prevvtxarray, startvtx));
695 
696  TIMING_LOG("Setting links");
697  }
698 
699  return startprim;
700 }
701 
702 // Static callback for our factory.
703 static void
704 geoNewPrimTetraBlock(
705  GA_Primitive **new_prims,
706  GA_Size nprimitives,
707  GA_Detail &gdp,
708  GA_Offset start_offset,
709  const GA_PrimitiveDefinition &def,
710  bool allowed_to_parallelize)
711 {
712  if (allowed_to_parallelize && nprimitives >= 4*GA_PAGE_SIZE)
713  {
714  // Allocate them in parallel if we're allocating many.
715  // This is using the C++11 lambda syntax to make a functor.
716  UTparallelForLightItems(UT_BlockedRange<GA_Offset>(start_offset, start_offset+nprimitives),
717  [new_prims,&gdp,start_offset](const UT_BlockedRange<GA_Offset> &r){
718  GA_Offset primoff(r.begin());
719  GA_Primitive **pprims = new_prims+(primoff-start_offset);
720  GA_Offset endprimoff(r.end());
721  for ( ; primoff != endprimoff; ++primoff, ++pprims)
722  *pprims = new GEO_PrimTetra(gdp, primoff);
723  });
724  }
725  else
726  {
727  // Allocate them serially if we're only allocating a few.
728  GA_Offset endprimoff(start_offset + nprimitives);
729  for (GA_Offset primoff(start_offset); primoff != endprimoff; ++primoff, ++new_prims)
730  *new_prims = new GEO_PrimTetra(gdp, primoff);
731  }
732 }
733 
734 void
736 {
737  // Ignore double registration
738  if (theDefinition)
739  return;
740 
741  theDefinition = factory->registerDefinition(
742  "HDK_Tetrahedron",
743  geoNewPrimTetraBlock,
745  "hdk_tetrahedron");
746 
747  // NOTE: Calling setHasLocalTransform(false) is redundant,
748  // but if your custom primitive has a local transform,
749  // it must call setHasLocalTransform(true).
750  theDefinition->setHasLocalTransform(false);
751  registerIntrinsics(*theDefinition);
752 
753 #ifndef TETRA_GR_PRIMITIVE
754 
755  // Register the GT tesselation too (now we know what type id we have)
757 
758 #else
759 
760 #ifdef TETRA_GR_PRIM_COLLECTION
762 #else
764 #endif
765 
766  // Since we're only registering one hook, the priority does not matter.
767  const int hook_priority = 0;
768 
770  new GR_PrimTetraHook,
771  theDefinition->getId(),
772  hook_priority,
773  collect_type);
774 #endif
775 
776 }
777 
778 int64
780 {
781  // NOTE: The only memory owned by this primitive is itself
782  // and its base class.
783  int64 mem = sizeof(*this) + getBaseMemoryUsage();
784  return mem;
785 }
786 
787 void
789 {
790  // NOTE: There's no shared memory in this primitive,
791  // apart from possibly in the case class.
792  counter.countUnshared(sizeof(*this));
793  countBaseMemory(counter);
794 }
795 
796 static GEO_Primitive *
797 geo_buildPoly(GEO_PrimTetra *tet, GEO_Detail *gdp, int v1, int v2, int v3,
798  GEO_ConvertParms &parms)
799 {
800  GEO_PrimPoly *poly = GEO_PrimPoly::build(gdp, 3, false, false);
801 
803  if (parms.preserveGroups)
805 
806  GA_VertexWrangler &wrangler = parms.getWranglers().getVertex();
807  gdp->copyVertex(poly->getVertexOffset(0), tet->getVertexOffset(v1), wrangler, NULL);
808  gdp->copyVertex(poly->getVertexOffset(1), tet->getVertexOffset(v2), wrangler, NULL);
809  gdp->copyVertex(poly->getVertexOffset(2), tet->getVertexOffset(v3), wrangler, NULL);
810 
811  return poly;
812 }
813 
816 {
817  GEO_Primitive *prim = NULL;
818  GEO_Detail *gdp = getParent();
819 
821  {
822  geo_buildPoly(this, gdp, 0, 1, 2, parms);
823  geo_buildPoly(this, gdp, 1, 3, 2, parms);
824  geo_buildPoly(this, gdp, 1, 0, 3, parms);
825  prim = geo_buildPoly(this, gdp, 0, 2, 3, parms);
826  }
827 
828  return prim;
829 }
830 
833 {
834  GEO_Primitive *prim = convertNew(parms);
835  GEO_Detail *gdp = getParent();
836  GA_PrimitiveGroup *group;
837 
838  if (prim)
839  {
840  if (usedpts) addPointRefToGroup(*usedpts);
841  if ((group = parms.getDeletePrimitives()))
842  group->add(this);
843  else gdp->deletePrimitive(*this, !usedpts);
844  }
845  return prim;
846 }
847 
848 void
850 {
851  // No need here.
852 }
853 
854 int
856  float tmax, float , float *distance,
857  UT_Vector3 *pos, UT_Vector3 *nml,
858  int, float *, float *, int) const
859 {
860  // TODO: Check each of the 4 triangles for intersection,
861  // instead of just checking the bounding box.
862 
863  UT_BoundingBox bbox;
864  getBBox(&bbox);
865 
866  float dist;
867  int result = bbox.intersectRay(org, dir, tmax, &dist, nml);
868  if (result)
869  {
870  if (distance) *distance = dist;
871  if (pos) *pos = org + dist * dir;
872  }
873  return result;
874 }
875 
876 // This is the usual DSO hook.
877 extern "C" {
878 void
880 {
882 }
883 }
884 
885 // Implement intrinsic attributes
886 enum
887 {
888  geo_INTRINSIC_ADDRESS, // Return the address of the primitive
889  geo_INTRINSIC_AUTHOR, // Developer's name
890  geo_NUM_INTRINSICS // Number of intrinsics
891 };
892 
893 namespace
894 {
895  static int64
896  intrinsicAddress(const GEO_PrimTetra *prim)
897  {
898  // An intrinsic attribute which returns the address of the primitive
899  return (int64)prim;
900  }
901  static const char *
902  intrinsicAuthor(const GEO_PrimTetra *)
903  {
904  // An intrinsic attribute which returns the HDK author's name
905  return "My Name";
906  }
907 };
908 
909 // Start defining intrinsic attributes, we pass our class name and the number
910 // of intrinsic attributes.
912 
913  // See GA_IntrinsicMacros.h for further information on how to define
914  // intrinsic attribute evaluators.
916  intrinsicAddress)
917  GA_INTRINSIC_S(GEO_PrimTetra, geo_INTRINSIC_AUTHOR, "author",
918  intrinsicAuthor)
919 
920 // End intrinsic definitions (our class and our base class)
921 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:249
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:227
Iteration over a range of elements.
Definition: GA_Iterator.h:28
virtual fpreal calcArea() 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:1134
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:255
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:607
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:72
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:753
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:794
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:100
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:269
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:664
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)
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:102
T distance(const UT_Vector4T< T > &v1, const UT_Vector4T< T > &v2)
Definition: UT_Vector4.h:634
SYS_FORCE_INLINE GA_Offset appendPointBlock(GA_Size npoints)
Append new points, returning the first offset of the contiguous block.
Definition: GA_Detail.h:277
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
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:665
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
virtual const char * getKeyword(int i) const
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:721
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:263
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:137
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:235
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:96
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
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.
GUI_PrimitiveHookFlags
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:440
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)