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) 2022
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_Vector3D(0, 0, 0);
160 }
161 
164 {
165  return UT_Vector3(0, 0, 0);
166 }
167 
168 fpreal
170 {
171  UT_Vector3 v0 = getPos3(0);
172  UT_Vector3 v1 = getPos3(1);
173  UT_Vector3 v2 = getPos3(2);
174  UT_Vector3 v3 = getPos3(3);
175 
176  // Measure signed volume of pyramid (v0,v1,v2,v3)
177  float signedvol = -(v3-v0).dot(cross(v1-v0, v2-v0));
178 
179  signedvol /= 6;
180 
181  return signedvol;
182 }
183 
184 fpreal
186 {
187  fpreal area = 0; // Signed area
188 
189  UT_Vector3 v0 = getPos3(0);
190  UT_Vector3 v1 = getPos3(1);
191  UT_Vector3 v2 = getPos3(2);
192  UT_Vector3 v3 = getPos3(3);
193 
194  area += cross((v1 - v0), (v2 - v0)).length();
195  area += cross((v3 - v1), (v2 - v1)).length();
196  area += cross((v3 - v0), (v1 - v0)).length();
197  area += cross((v2 - v0), (v3 - v0)).length();
198 
199  area = area / 2;
200 
201  return area;
202 }
203 
204 fpreal
206 {
207  fpreal length = 0;
208 
209  UT_Vector3 v0 = getPos3(0);
210  UT_Vector3 v1 = getPos3(1);
211  UT_Vector3 v2 = getPos3(2);
212  UT_Vector3 v3 = getPos3(3);
213 
214  length += (v1-v0).length();
215  length += (v2-v0).length();
216  length += (v3-v0).length();
217  length += (v2-v1).length();
218  length += (v3-v1).length();
219  length += (v3-v2).length();
220 
221  return length;
222 }
223 
224 int
226 {
227  GA_Size count = 0;
228  for (GA_Size i = 0; i < PT_PER_TET; ++i)
229  if (grp.containsOffset(getPointOffset(i)))
230  count++;
231 
232  if (count == 0)
233  return 0;
234 
235  if (count == PT_PER_TET)
236  return -2;
237 
238  return -1;
239 }
240 
243 {
244  for (GA_Size i = 0; i < PT_PER_TET; ++i)
245  {
246  if (getPointOffset(i) == point)
247  {
249  }
250  }
251  return GA_DEREFERENCE_OK;
252 }
253 
255 GEO_PrimTetra::dereferencePoints(const GA_RangeMemberQuery &point_query, bool dry_run)
256 {
257  int count = 0;
258  for (GA_Size i = 0; i < PT_PER_TET; ++i)
259  {
260  if (point_query.contains(getPointOffset(i)))
261  {
262  count++;
263  }
264  }
265 
266  if (count == PT_PER_TET)
267  return GA_DEREFERENCE_DESTROY;
268  if (count == 0)
269  return GA_DEREFERENCE_OK;
270 
271  if (isDegenerate())
273  return GA_DEREFERENCE_FAIL;
274 }
275 
276 ///
277 /// JSON methods
278 ///
279 
280 namespace HDK_Sample {
281 
282 using namespace UT::Literal;
283 
284 static UT_StringHolder theKWVertex = "vertex"_sh;
285 
287 {
288 public:
290  {
291  }
292  ~geo_PrimTetraJSON() override {}
293 
294  enum
295  {
297  geo_TBJ_ENTRIES
298  };
299 
300  const GEO_PrimTetra *tet(const GA_Primitive *p) const
301  { return static_cast<const GEO_PrimTetra *>(p); }
303  { return static_cast<GEO_PrimTetra *>(p); }
304 
305  int getEntries() const override { return geo_TBJ_ENTRIES; }
306 
307  const UT_StringHolder &getKeyword(int i) const override
308  {
309  switch (i)
310  {
311  case geo_TBJ_VERTEX: return theKWVertex;
312  case geo_TBJ_ENTRIES: break;
313  }
314  UT_ASSERT(0);
316  }
317  bool saveField(const GA_Primitive *pr, int i,
318  UT_JSONWriter &w, const GA_SaveMap &map) const override
319  {
320  switch (i)
321  {
322  case geo_TBJ_VERTEX:
323  return tet(pr)->saveVertexArray(w, map);
324  case geo_TBJ_ENTRIES:
325  break;
326  }
327  return false;
328  }
329  bool saveField(const GA_Primitive *pr, int i,
330  UT_JSONValue &v, const GA_SaveMap &map) const override
331  {
332  switch (i)
333  {
334  case geo_TBJ_VERTEX:
335  return false;
336  case geo_TBJ_ENTRIES:
337  break;
338  }
339  UT_ASSERT(0);
340  return false;
341  }
343  const GA_LoadMap &map) const override
344  {
345  switch (i)
346  {
347  case geo_TBJ_VERTEX:
348  return tet(pr)->loadVertexArray(p, map);
349  case geo_TBJ_ENTRIES:
350  break;
351  }
352  UT_ASSERT(0);
353  return false;
354  }
356  const UT_JSONValue &v, const GA_LoadMap &map) const override
357  {
358  switch (i)
359  {
360  case geo_TBJ_VERTEX:
361  return false;
362  case geo_TBJ_ENTRIES:
363  break;
364  }
365  UT_ASSERT(0);
366  return false;
367  }
368  bool isEqual(int i, const GA_Primitive *p0,
369  const GA_Primitive *p1) const override
370  {
371  switch (i)
372  {
373  case geo_TBJ_VERTEX:
374  return false;
375  case geo_TBJ_ENTRIES:
376  break;
377  }
378  UT_ASSERT(0);
379  return false;
380  }
381 private:
382 };
383 }
384 
385 static const GA_PrimitiveJSON *
386 tetrahedronJSON()
387 {
388  static GA_PrimitiveJSON *theJSON = NULL;
389 
390  if (!theJSON)
391  theJSON = new geo_PrimTetraJSON();
392  return theJSON;
393 }
394 
395 const GA_PrimitiveJSON *
397 {
398  return tetrahedronJSON();
399 }
400 
401 
402 
403 bool
405  const GA_SaveMap &map) const
406 {
407  return myVertexList.jsonVertexArray(w, map);
408 }
409 
410 bool
412 {
413  GA_Offset startvtxoff = map.getVertexOffset();
414 
415  int64 vtxoffs[PT_PER_TET];
416  int nvertex = p.parseUniformArray(vtxoffs, PT_PER_TET);
417  if (startvtxoff != GA_Offset(0))
418  {
419  for (int i = 0; i < nvertex; i++)
420  {
421  if (vtxoffs[i] >= 0)
422  vtxoffs[i] += GA_Size(startvtxoff);
423  }
424  }
425  for (int i = nvertex; i < PT_PER_TET; ++i)
426  vtxoffs[i] = GA_INVALID_OFFSET;
427  myVertexList.set(vtxoffs, PT_PER_TET, GA_Offset(0));
428  if (nvertex < PT_PER_TET)
429  return false;
430  return true;
431 }
432 
433 
434 bool
436 {
437  bbox->initBounds(getPos3(0));
438  bbox->enlargeBounds(getPos3(1));
439  bbox->enlargeBounds(getPos3(2));
440  bbox->enlargeBounds(getPos3(3));
441  return true;
442 }
443 
446 {
447  UT_Vector3 sum(0,0,0);
448 
449  for (int i = 0; i < PT_PER_TET; ++i)
450  sum += getPos3(i);
451 
452  sum /= PT_PER_TET;
453 
454  return sum;
455 }
456 
457 bool
459 {
460  // Duplicate points means degenerate.
461  for (int i = 0; i < PT_PER_TET; i++)
462  {
463  for (int j = i+1; j < PT_PER_TET; j++)
464  {
465  if (getPointOffset(i) == getPointOffset(j))
466  return true;
467  }
468  }
469  return false;
470 }
471 
472 void
474 {
475  if (psrc == this)
476  return;
477 
478  // This sets the number of vertices to be the same as psrc, and wires
479  // the corresponding vertices to the corresponding points.
480  // This class doesn't have any more data, so we didn't need to
481  // override copyPrimitive, but if you add any more data, copy it
482  // below.
484 
485  // Uncomment this to access other data
486  //const GEO_PrimTetra *src = (const GEO_PrimTetra *)psrc;
487 }
488 
490 GEO_PrimTetra::copy(int preserve_shared_pts) const
491 {
492  GEO_Primitive *clone = GEO_Primitive::copy(preserve_shared_pts);
493 
494  if (!clone)
495  return nullptr;
496 
497  // This class doesn't have any more data to copy, so we didn't need
498  // to override this function, but if you add any, copy them here.
499 
500  // Uncomment this to access other data
501  //GEO_PrimTetra *tet = (GEO_PrimTetra*)clone;
502 
503  return clone;
504 }
505 
506 void
508 {
509  UT_ASSERT( source != this );
510 
511  // The superclass' implementation in this case doesn't do anything,
512  // but if you have a superclass with member data, it's important
513  // to call this here.
515 
516  // If you add any data that must be copyied from src in order for this
517  // to be a separate but identical copy of src, copy it here,
518  // but make sure it's safe to call copySubclassData on multiple
519  // primitives at the same time.
520 
521  // Uncomment this to access other data
522  //const GEO_PrimTetra *src = static_cast<const GEO_PrimTetra *>(prim_src);
523 }
524 
526 GEO_PrimTetra::build(GA_Detail *gdp, bool appendPoints)
527 {
529 
530  // Add 4 vertices. The constructor did not add any.
531  GA_Offset vtxoff = gdp->appendVertexBlock(PT_PER_TET);
532  tet->myVertexList.setTrivial(vtxoff, PT_PER_TET);
533  GA_ATITopology *vtx_to_prim = gdp->getTopology().getPrimitiveRef();
534  if (vtx_to_prim)
535  {
536  GA_Offset primoff = tet->getMapOffset();
537  for (GA_Size i = 0; i < PT_PER_TET; i++)
538  vtx_to_prim->setLink(vtxoff+i, primoff);
539  }
540 
541  // NOTE: By design, npts will always be 4 (i.e. PT_PER_TET) for a tetrahedron.
542  // The call to getVertexCount() is just as an example.
543  const GA_Size npts = tet->getVertexCount();
544  if (appendPoints)
545  {
546  GEO_Primitive *prim = tet;
547  const GA_Offset startptoff = gdp->appendPointBlock(npts);
548  for (GA_Size i = 0; i < npts; i++)
549  {
550  prim->setPointOffset(i, startptoff+i);
551  }
552  }
553  return tet;
554 }
555 
556 namespace {
557 
558 class geo_SetTopoPrimsParallel
559 {
560 public:
561  geo_SetTopoPrimsParallel(
563  const GA_Offset startprim,
564  const GA_Offset startvtx)
565  : myTopology(topology)
566  , myStartPrim(startprim)
567  , myStartVtx(startvtx)
568  {}
569 
570  void operator()(const GA_SplittableRange &r) const
571  {
573  GA_Offset end;
574  for (GA_Iterator it = r.begin(); it.blockAdvance(start, end); )
575  {
576  GA_Size relativestart = start - myStartVtx;
577  GA_Size relativeend = end - myStartVtx;
578  GA_Offset tet = (relativestart / PT_PER_TET) + myStartPrim;
579  GA_Size vert = relativestart % PT_PER_TET;
580  GA_Offset endtet = (relativeend / PT_PER_TET) + myStartPrim;
581 
582  // The range may start after the beginning of the first tet
583  if (vert != 0)
584  {
585  for (; vert < PT_PER_TET; ++vert)
586  myTopology->setLink(start++, tet);
587  ++tet;
588  }
589 
590  // Full tets in the middle
591  for (; tet != endtet; ++tet)
592  {
593  for (GA_Size i = 0; i < PT_PER_TET; ++i)
594  myTopology->setLink(start++, tet);
595  }
596 
597  // The range may end before the end of the last tet
598  if (start < end)
599  {
600  while (start < end)
601  myTopology->setLink(start++, tet);
602  }
603  }
604  }
605 
606 private:
607  GA_ATITopology *myTopology;
608  const GA_Offset myStartPrim;
609  const GA_Offset myStartVtx;
610 };
611 
612 }
613 
614 // Instantiation here, because GCC can't figure out templates, even in header files
616 
617 GA_Offset
619  const GA_Offset startpt,
620  const GA_Size npoints,
621  const GA_Size ntets,
622  const int *tetpointnumbers)
623 {
624  if (ntets == 0)
625  return GA_INVALID_OFFSET;
626 
627  TIMING_DEF;
628 
629  const GA_Offset endpt = startpt + npoints;
630  const GA_Size nvertices = ntets * PT_PER_TET;
631 
632  // Create the empty primitives
633  const GA_Offset startprim = detail->appendPrimitiveBlock(GEO_PrimTetra::theTypeId(), ntets);
634 
635  TIMING_LOG("Creating primitives");
636 
637  // Create the uninitialized vertices
638  const GA_Offset startvtx = detail->appendVertexBlock(nvertices);
639  const GA_Offset endvtx = startvtx + nvertices;
640 
641  TIMING_LOG("Appending vertices");
642 
643  // Set the vertex-to-point mapping
644  GA_ATITopology *vertexToPoint = detail->getTopology().getPointRef();
645  if (vertexToPoint)
646  {
647  UTparallelForLightItems(GA_SplittableRange(GA_Range(detail->getVertexMap(), startvtx, endvtx)),
648  geo_SetTopoMappedParallel<int>(vertexToPoint, startpt, startvtx, tetpointnumbers));
649 
650  TIMING_LOG("Setting vtx->pt");
651  }
652 
653  // Set the vertex-to-primitive mapping
654  GA_ATITopology *vertexToPrim = detail->getTopology().getPrimitiveRef();
655  if (vertexToPrim)
656  {
657  UTparallelForLightItems(GA_SplittableRange(GA_Range(detail->getVertexMap(), startvtx, endvtx)),
658  geo_SetTopoPrimsParallel(vertexToPrim, startprim, startvtx));
659 
660  TIMING_LOG("Setting vtx->prm");
661  }
662 
663  // Set the vertex lists of the tets
665  geo_SetVertexListsParallel(detail, startprim, startvtx));
666 
667  TIMING_LOG("Setting vertex lists");
668 
669  // Check whether the linked list topologies need to be set
670  GA_ATITopology *pointToVertex = detail->getTopology().getVertexRef();
671  GA_ATITopology *vertexToNext = detail->getTopology().getVertexNextRef();
672  GA_ATITopology *vertexToPrev = detail->getTopology().getVertexPrevRef();
673  if (pointToVertex && vertexToNext && vertexToPrev)
674  {
675  // Create a trivial map from 0 to nvertices
676  UT_IntArray map(nvertices, nvertices);
677 
678  TIMING_LOG("Allocating map");
679 
680  UTparallelForLightItems(UT_BlockedRange<GA_Size>(0, nvertices), geo_TrivialArrayParallel<int>(map));
681 
682  TIMING_LOG("Creating trivial map");
683 
684  // Sort the map in parallel according to the point offsets of the vertices
685  UTparallelSort(map.array(), map.array() + nvertices, geo_VerticesByPointCompare<int,true>(tetpointnumbers));
686 
687  TIMING_LOG("Sorting array map");
688 
689  // Create arrays for the next vertex and prev vertex in parallel
690  // If we wanted to do this in geo_LinkToposParallel, we would first
691  // have to create an inverse map anyway to find out where vertices
692  // are in map, so this saves re-traversing things.
693  UT_IntArray nextvtxarray(nvertices, nvertices);
694  UT_IntArray prevvtxarray(nvertices, nvertices);
695  UT_Lock lock;
697  geo_NextPrevParallel<int>(map.getArray(), map.size(), tetpointnumbers, nextvtxarray.getArray(), prevvtxarray.getArray(), startvtx, startpt, pointToVertex, vertexToPrev, lock));
698 
699  TIMING_LOG("Finding next/prev");
700 
701  // Set the point-to-vertex topology in parallel
702  // This needs to be done after constructing the next/prev array,
703  // because it checks for existing vertices using the points.
705  geo_Pt2VtxTopoParallel<int>(pointToVertex, map.getArray(), map.size(), tetpointnumbers, startvtx, startpt));
706 
707  TIMING_LOG("Setting pt->vtx");
708 
709  // Clear up some memory before filling up the linked list topologies
710  map.setCapacity(0);
711 
712  TIMING_LOG("Clearing map");
713 
714  // Fill in the linked list topologies
715  UTparallelForLightItems(GA_SplittableRange(GA_Range(detail->getVertexMap(), startvtx, endvtx)),
716  geo_LinkToposParallel<int>(vertexToNext, vertexToPrev, nextvtxarray.getArray(), prevvtxarray.getArray(), startvtx));
717 
718  TIMING_LOG("Setting links");
719  }
720 
721  return startprim;
722 }
723 
724 // Static callback for our factory.
725 static void
726 geoNewPrimTetraBlock(
727  GA_Primitive **new_prims,
728  GA_Size nprimitives,
729  GA_Detail &gdp,
730  GA_Offset start_offset,
731  const GA_PrimitiveDefinition &def,
732  bool allowed_to_parallelize)
733 {
734  if (allowed_to_parallelize && nprimitives >= 4*GA_PAGE_SIZE)
735  {
736  // Allocate them in parallel if we're allocating many.
737  // This is using the C++11 lambda syntax to make a functor.
738  UTparallelForLightItems(UT_BlockedRange<GA_Offset>(start_offset, start_offset+nprimitives),
739  [new_prims,&gdp,start_offset](const UT_BlockedRange<GA_Offset> &r){
740  GA_Offset primoff(r.begin());
741  GA_Primitive **pprims = new_prims+(primoff-start_offset);
742  GA_Offset endprimoff(r.end());
743  for ( ; primoff != endprimoff; ++primoff, ++pprims)
744  *pprims = new GEO_PrimTetra(gdp, primoff);
745  });
746  }
747  else
748  {
749  // Allocate them serially if we're only allocating a few.
750  GA_Offset endprimoff(start_offset + nprimitives);
751  for (GA_Offset primoff(start_offset); primoff != endprimoff; ++primoff, ++new_prims)
752  *new_prims = new GEO_PrimTetra(gdp, primoff);
753  }
754 }
755 
756 void
758 {
759  // Ignore double registration
760  if (theDefinition)
761  return;
762 
763  theDefinition = factory->registerDefinition(
764  "HDK_Tetrahedron",
765  geoNewPrimTetraBlock,
767  "hdk_tetrahedron");
768 
769  // NOTE: Calling setHasLocalTransform(false) is redundant,
770  // but if your custom primitive has a local transform,
771  // it must call setHasLocalTransform(true).
772  theDefinition->setHasLocalTransform(false);
773  registerIntrinsics(*theDefinition);
774 
775 #ifndef TETRA_GR_PRIMITIVE
776 
777  // Register the GT tesselation too (now we know what type id we have)
779 
780 #else
781 
782  // Since we're only registering one hook, the priority does not matter.
783  const int hook_priority = 0;
784 
786  new GR_PrimTetraHook,
787  theDefinition->getId(),
788  hook_priority,
790 #endif
791 
792 }
793 
794 int64
796 {
797  // NOTE: The only memory owned by this primitive is itself
798  // and its base class.
799  int64 mem = sizeof(*this) + getBaseMemoryUsage();
800  return mem;
801 }
802 
803 void
805 {
806  // NOTE: There's no shared memory in this primitive,
807  // apart from possibly in the case class.
808  counter.countUnshared(sizeof(*this));
809  countBaseMemory(counter);
810 }
811 
812 static GEO_Primitive *
813 geo_buildPoly(GEO_PrimTetra *tet, GEO_Detail *gdp, int v1, int v2, int v3,
814  GEO_ConvertParms &parms)
815 {
816  GEO_PrimPoly *poly = GEO_PrimPoly::build(gdp, 3, false, false);
817 
819  if (parms.preserveGroups)
821 
822  GA_VertexWrangler &wrangler = parms.getWranglers().getVertex();
823  gdp->copyVertex(poly->getVertexOffset(0), tet->getVertexOffset(v1), wrangler, NULL);
824  gdp->copyVertex(poly->getVertexOffset(1), tet->getVertexOffset(v2), wrangler, NULL);
825  gdp->copyVertex(poly->getVertexOffset(2), tet->getVertexOffset(v3), wrangler, NULL);
826 
827  return poly;
828 }
829 
832 {
833  GEO_Primitive *prim = NULL;
834  GEO_Detail *gdp = getParent();
835 
837  {
838  geo_buildPoly(this, gdp, 0, 1, 2, parms);
839  geo_buildPoly(this, gdp, 1, 3, 2, parms);
840  geo_buildPoly(this, gdp, 1, 0, 3, parms);
841  prim = geo_buildPoly(this, gdp, 0, 2, 3, parms);
842  }
843 
844  return prim;
845 }
846 
849 {
850  GEO_Primitive *prim = convertNew(parms);
851  GEO_Detail *gdp = getParent();
853 
854  if (prim)
855  {
856  if (usedpts) addPointRefToGroup(*usedpts);
857  if ((group = parms.getDeletePrimitives()))
858  group->add(this);
859  else gdp->deletePrimitive(*this, !usedpts);
860  }
861  return prim;
862 }
863 
864 void
866 {
867  // No need here.
868 }
869 
870 void
872 {
873  // No need here.
874 }
875 
876 int
878  float tmax, float , float *distance,
879  UT_Vector3 *pos, UT_Vector3 *nml,
880  int, float *, float *, int) const
881 {
882  // TODO: Check each of the 4 triangles for intersection,
883  // instead of just checking the bounding box.
884 
885  UT_BoundingBox bbox;
886  getBBox(&bbox);
887 
888  float dist;
889  int result = bbox.intersectRay(org, dir, tmax, &dist, nml);
890  if (result)
891  {
892  if (distance) *distance = dist;
893  if (pos) *pos = org + dist * dir;
894  }
895  return result;
896 }
897 
898 // This is the usual DSO hook.
899 extern "C" {
900 void
902 {
904 }
905 }
906 
907 // Implement intrinsic attributes
908 enum
909 {
910  geo_INTRINSIC_ADDRESS, // Return the address of the primitive
911  geo_INTRINSIC_AUTHOR, // Developer's name
912  geo_NUM_INTRINSICS // Number of intrinsics
913 };
914 
915 namespace
916 {
917  static int64
918  intrinsicAddress(const GEO_PrimTetra *prim)
919  {
920  // An intrinsic attribute which returns the address of the primitive
921  return (int64)prim;
922  }
923  static const char *
924  intrinsicAuthor(const GEO_PrimTetra *)
925  {
926  // An intrinsic attribute which returns the HDK author's name
927  return "My Name";
928  }
929 };
930 
931 // Start defining intrinsic attributes, we pass our class name and the number
932 // of intrinsic attributes.
934 
935  // See GA_IntrinsicMacros.h for further information on how to define
936  // intrinsic attribute evaluators.
938  intrinsicAddress)
939  GA_INTRINSIC_S(GEO_PrimTetra, geo_INTRINSIC_AUTHOR, "author",
940  intrinsicAuthor)
941 
942 // End intrinsic definitions (our class and our base class)
943 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
GLuint counter
Definition: glew.h:2745
UT_Vector3D computeNormalD() const override
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
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:499
bool blockAdvance(GA_Offset &start, GA_Offset &end)
GLuint start
Definition: glcorearb.h:475
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:1209
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:782
int detachPoints(GA_PointGroup &grp) override
JSON reader class which handles parsing of JSON or bJSON files.
Definition: UT_JSONParser.h:88
SYS_FORCE_INLINE GEO_Detail * getParent() const
Class which writes ASCII or binary JSON streams.
Definition: UT_JSONWriter.h:35
GA_DereferenceStatus dereferencePoint(GA_Offset point, bool dry_run=false) override
Abstract base class for a range membership query object.
void normal(NormalComp &output) const override
GEO_PrimTetra * tet(GA_Primitive *p) const
bool getBBox(UT_BoundingBox *bbox) const override
exint size() const
Definition: UT_Array.h:609
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:234
SYS_FORCE_INLINE int64 getBaseMemoryUsage() const
Report approximate memory usage for myVertexList for subclasses.
Definition: GA_Primitive.h:831
void copySubclassData(const GA_Primitive *source) override
#define GA_INVALID_OFFSET
Definition: GA_Types.h:677
GA_OffsetList myVertexList
Definition: GA_Primitive.h:872
A range of elements in an index-map.
Definition: GA_Range.h:42
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:857
void set(FromType index, ToType value)
Set the index to the value.
GA_Size GA_Offset
Definition: GA_Types.h:640
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
void setCapacity(exint newcapacity)
Definition: UT_ArrayImpl.h:756
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.
GLuint64EXT * result
Definition: glew.h:14311
const GA_IndexMap & getPointMap() const
Definition: GA_Detail.h:740
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
GLfloat GLfloat GLfloat v2
Definition: glcorearb.h:818
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:329
GLsizei GLsizei GLfloat distance
Definition: glew.h:13923
SYS_FORCE_INLINE const GA_ATITopology * getVertexNextRef() const
Definition: GA_Topology.h:229
GT_API const UT_StringHolder topology
static const UT_StringHolder theEmptyString
const GLdouble * v
Definition: glcorearb.h:837
GLsizei GLsizei GLchar * source
Definition: glcorearb.h:803
fpreal64 dot(const CE_VectorT< T > &a, const CE_VectorT< T > &b)
Definition: CE_Vector.h:130
bool loadField(GA_Primitive *pr, int i, UT_JSONParser &p, const UT_JSONValue &v, const GA_LoadMap &map) const override
GLuint GLuint end
Definition: glcorearb.h:475
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 &)
long long int64
Definition: SYS_Types.h:116
A handle to simplify manipulation of multiple attributes.
GLfloat GLfloat p
Definition: glew.h:16656
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
UT_Vector3T< fpreal64 > UT_Vector3D
const GA_IndexMap & getVertexMap() const
Definition: GA_Detail.h:741
static const GA_PrimitiveTypeId & theTypeId()
Allows you to find out what this primitive type was named.
void addPointRefToGroup(GA_PointGroup &grp) const
GLint GLsizei count
Definition: glcorearb.h:405
GLuint GLuint64EXT address
Definition: glew.h:14913
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
GLfloat GLfloat GLfloat GLfloat v3
Definition: glcorearb.h:819
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
GLfloat v0
Definition: glcorearb.h:816
void copyVertex(GEO_Vertex dest, const GEO_Vertex &src, int shallow=0) const
#define GA_PAGE_SIZE
Definition: GA_Types.h:223
#define TIMING_DEF
Definition: GEO_PrimTetra.C:75
void add(const GA_Primitive *prim)
GA_Topology & getTopology()
Definition: GA_Detail.h:797
fpreal calcArea() const override
int64 parseUniformArray(T *data, int64 len)
SYS_FORCE_INLINE bool containsOffset(GA_Offset offset) const
void countUnshared(size_t size)
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:795
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
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
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
GLboolean GLuint group
Definition: glew.h:2750
SYS_FORCE_INLINE GA_Offset getVertexOffset(GA_Size primvertexnum) const
Definition: GA_Primitive.h:240
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.
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:153
GLintptr offset
Definition: glcorearb.h:665
Definition of a geometric primitive.
bool loadVertexArray(UT_JSONParser &p, const GA_LoadMap &map)
GLfloat GLfloat v1
Definition: glcorearb.h:817
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.
GLboolean r
Definition: glcorearb.h:1222
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:779
SIM_DerVector3 cross(const SIM_DerVector3 &lhs, const SIM_DerVector3 &rhs)
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:499
static GEO_PrimPoly * build(GA_Detail *gdp, GA_Size nvertices, bool open=false, bool appendpts=true)
fpreal calcVolume(const UT_Vector3 &refpt) const override
SYS_FORCE_INLINE void setLink(GA_Offset ai, GA_Offset v)