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