Panda3D
geom.I
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file geom.I
10  * @author drose
11  * @date 2005-03-06
12  */
13 
14 /**
15  * Returns the fundamental primitive type that is common to all GeomPrimitives
16  * added within the Geom. All nested primitives within a particular Geom must
17  * be the same type (that is, you can mix triangles and tristrips, because
18  * they are both the same fundamental type PT_polygons, but you cannot mix
19  * triangles and points withn the same Geom).
20  */
21 INLINE Geom::PrimitiveType Geom::
22 get_primitive_type() const {
23  CDReader cdata(_cycler);
24  return cdata->_primitive_type;
25 }
26 
27 /**
28  * Returns the shade model common to all of the individual GeomPrimitives that
29  * have been added to the geom.
30  */
31 INLINE Geom::ShadeModel Geom::
32 get_shade_model() const {
33  CDReader cdata(_cycler);
34  return cdata->_shade_model;
35 }
36 
37 /**
38  * Returns the set of GeomRendering bits that represent the rendering
39  * properties required to properly render this Geom.
40  */
41 INLINE int Geom::
42 get_geom_rendering() const {
43  CDReader cdata(_cycler);
44  return cdata->_geom_rendering;
45 }
46 
47 /**
48  * Returns a const pointer to the GeomVertexData, for application code to
49  * directly examine (but not modify) the geom's underlying data.
50  */
51 INLINE CPT(GeomVertexData) Geom::
52 get_vertex_data(Thread *current_thread) const {
53  CDReader cdata(_cycler, current_thread);
54  return cdata->_data.get_read_pointer(current_thread);
55 }
56 
57 /**
58  * Returns true if there appear to be no vertices to be rendered by this Geom,
59  * false if has some actual data.
60  */
61 INLINE bool Geom::
62 is_empty() const {
63  CDReader cdata(_cycler);
64  return cdata->_primitives.empty();
65 }
66 
67 /**
68  * Returns the number of GeomPrimitive objects stored within the Geom, each of
69  * which represents a number of primitives of a particular type.
70  */
71 INLINE size_t Geom::
72 get_num_primitives() const {
73  CDReader cdata(_cycler);
74  return cdata->_primitives.size();
75 }
76 
77 /**
78  * Returns a const pointer to the ith GeomPrimitive object stored within the
79  * Geom. Use this call only to inspect the ith object; use modify_primitive()
80  * or set_primitive() if you want to modify it.
81  */
82 INLINE CPT(GeomPrimitive) Geom::
83 get_primitive(size_t i) const {
84  CDReader cdata(_cycler);
85  nassertr(i < cdata->_primitives.size(), nullptr);
86  return cdata->_primitives[i].get_read_pointer();
87 }
88 
89 /**
90  * Returns a modifiable pointer to the ith GeomPrimitive object stored within
91  * the Geom, so application code can directly manipulate the properties of
92  * this primitive.
93  *
94  * Don't call this in a downstream thread unless you don't mind it blowing
95  * away other changes you might have recently made in an upstream thread.
96  */
97 INLINE PT(GeomPrimitive) Geom::
98 modify_primitive(size_t i) {
99  Thread *current_thread = Thread::get_current_thread();
100  CDWriter cdata(_cycler, true, current_thread);
101  nassertr(i < cdata->_primitives.size(), nullptr);
102  cdata->_modified = Geom::get_next_modified();
103  clear_cache_stage(current_thread);
104  return cdata->_primitives[i].get_write_pointer();
105 }
106 
107 /**
108  * Inserts a new GeomPrimitive structure to the Geom object. This specifies a
109  * particular subset of vertices that are used to define geometric primitives
110  * of the indicated type.
111  *
112  * Don't call this in a downstream thread unless you don't mind it blowing
113  * away other changes you might have recently made in an upstream thread.
114  */
115 INLINE void Geom::
116 add_primitive(const GeomPrimitive *primitive) {
117  insert_primitive((size_t)-1, primitive);
118 }
119 
120 /**
121  * Decomposes all of the primitives within this Geom, returning the result.
122  * See GeomPrimitive::decompose().
123  */
124 INLINE PT(Geom) Geom::
125 decompose() const {
126  PT(Geom) new_geom = make_copy();
127  new_geom->decompose_in_place();
128  return new_geom;
129 }
130 
131 /**
132  * Doublesides all of the primitives within this Geom, returning the result.
133  * See GeomPrimitive::doubleside().
134  */
135 INLINE PT(Geom) Geom::
136 doubleside() const {
137  PT(Geom) new_geom = make_copy();
138  new_geom->doubleside_in_place();
139  return new_geom;
140 }
141 
142 /**
143  * Reverses all of the primitives within this Geom, returning the result. See
144  * GeomPrimitive::reverse().
145  */
146 INLINE PT(Geom) Geom::
147 reverse() const {
148  PT(Geom) new_geom = make_copy();
149  new_geom->reverse_in_place();
150  return new_geom;
151 }
152 
153 /**
154  * Rotates all of the primitives within this Geom, returning the result. See
155  * GeomPrimitive::rotate().
156  */
157 INLINE PT(Geom) Geom::
158 rotate() const {
159  PT(Geom) new_geom = make_copy();
160  new_geom->rotate_in_place();
161  return new_geom;
162 }
163 
164 /**
165  * Unifies all of the primitives contained within this Geom into a single (or
166  * as few as possible, within the constraints of max_indices) primitive
167  * objects. This may require decomposing the primitives if, for instance, the
168  * Geom contains both triangle strips and triangle fans.
169  *
170  * max_indices represents the maximum number of indices that will be put in
171  * any one GeomPrimitive. If preserve_order is true, then the primitives will
172  * not be reordered during the operation, even if this results in a suboptimal
173  * result.
174  */
175 INLINE PT(Geom) Geom::
176 unify(int max_indices, bool preserve_order) const {
177  PT(Geom) new_geom = make_copy();
178  new_geom->unify_in_place(max_indices, preserve_order);
179  return new_geom;
180 }
181 
182 /**
183  * Returns a new Geom with points at all the vertices. See
184  * GeomPrimitive::make_points().
185  */
186 INLINE PT(Geom) Geom::
187 make_points() const {
188  PT(Geom) new_geom = make_copy();
189  new_geom->make_points_in_place();
190  return new_geom;
191 }
192 
193 /**
194  * Returns a new Geom with lines at all the edges. See
195  * GeomPrimitive::make_lines().
196  */
197 INLINE PT(Geom) Geom::
198 make_lines() const {
199  PT(Geom) new_geom = make_copy();
200  new_geom->make_lines_in_place();
201  return new_geom;
202 }
203 
204 /**
205  * Returns a new Geom with each primitive converted into a patch. Calls
206  * decompose() first.
207  */
208 INLINE PT(Geom) Geom::
209 make_patches() const {
210  PT(Geom) new_geom = make_copy();
211  new_geom->make_patches_in_place();
212  return new_geom;
213 }
214 
215 /**
216  * Returns a new Geom with each primitive converted into a corresponding
217  * version with adjacency information.
218  */
219 INLINE PT(Geom) Geom::
220 make_adjacency() const {
221  PT(Geom) new_geom = make_copy();
222  new_geom->make_adjacency_in_place();
223  return new_geom;
224 }
225 
226 /**
227  * Returns a sequence number which is guaranteed to change at least every time
228  * any of the primitives in the Geom is modified, or the set of primitives is
229  * modified. However, this does not include modifications to the vertex data,
230  * which should be tested separately.
231  */
232 INLINE UpdateSeq Geom::
233 get_modified(Thread *current_thread) const {
234  CDReader cdata(_cycler, current_thread);
235  return cdata->_modified;
236 }
237 
238 /**
239  * Marks the bounding volume of the Geom as stale so that it should be
240  * recomputed. Usually it is not necessary to call this explicitly.
241  */
242 INLINE void Geom::
243 mark_bounds_stale() const {
244  CDWriter cdata(((Geom *)this)->_cycler, false);
245  ((Geom *)this)->mark_internal_bounds_stale(cdata);
246 }
247 
248 /**
249  * Specifies the desired type of bounding volume that will be created for this
250  * Geom. This is normally BoundingVolume::BT_default, which means to set the
251  * type according to the config variable "bounds-type".
252  *
253  * If this is BT_sphere or BT_box, a BoundingSphere or BoundingBox is
254  * explicitly created. If it is BT_best, a BoundingBox is created.
255  *
256  * This affects the implicit bounding volume only. If an explicit bounding
257  * volume is set on the Geom with set_bounds(), that bounding volume type is
258  * used. (This is different behavior from the similar method on PandaNode.)
259  */
260 INLINE void Geom::
261 set_bounds_type(BoundingVolume::BoundsType bounds_type) {
262  CDWriter cdata(_cycler, true);
263  cdata->_bounds_type = bounds_type;
264  mark_internal_bounds_stale(cdata);
265 }
266 
267 /**
268  * Returns the bounding volume type set with set_bounds_type().
269  */
270 INLINE BoundingVolume::BoundsType Geom::
271 get_bounds_type() const {
272  CDReader cdata(_cycler);
273  return cdata->_bounds_type;
274 }
275 
276 /**
277  * Resets the bounding volume so that it is the indicated volume. When it is
278  * explicitly set, the bounding volume will no longer be automatically
279  * computed; call clear_bounds() if you would like to return the bounding
280  * volume to its default behavior.
281  *
282  * Don't call this in a downstream thread unless you don't mind it blowing
283  * away other changes you might have recently made in an upstream thread.
284  */
285 INLINE void Geom::
286 set_bounds(const BoundingVolume *volume) {
287  CDWriter cdata(_cycler, true);
288  if (volume == nullptr) {
289  cdata->_user_bounds = nullptr;
290  } else {
291  cdata->_user_bounds = volume->make_copy();
292  }
293 }
294 
295 /**
296  * Reverses the effect of a previous call to set_bounds(), and allows the
297  * bounding volume to be automatically computed once more based on the
298  * vertices.
299  *
300  * Don't call this in a downstream thread unless you don't mind it blowing
301  * away other changes you might have recently made in an upstream thread.
302  */
303 INLINE void Geom::
305  CDWriter cdata(_cycler, true);
306  cdata->_user_bounds = nullptr;
307  mark_internal_bounds_stale(cdata);
308 }
309 
310 /**
311  * Expands min_point and max_point to include all of the vertices in the Geom,
312  * if any. found_any is set true if any points are found. It is the caller's
313  * responsibility to initialize min_point, max_point, and found_any before
314  * calling this function.
315  *
316  * This version of the method allows the Geom to specify an alternate vertex
317  * data table (for instance, if the vertex data has already been munged), and
318  * also allows the result to be computed in any coordinate space by specifying
319  * a transform matrix.
320  */
321 INLINE void Geom::
322 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
323  bool &found_any,
324  const GeomVertexData *vertex_data,
325  bool got_mat, const LMatrix4 &mat,
326  Thread *current_thread) const {
327  CDReader cdata(_cycler, current_thread);
328 
329  PN_stdfloat sq_radius;
330  do_calc_tight_bounds(min_point, max_point, sq_radius, found_any,
331  vertex_data, got_mat, mat,
332  InternalName::get_vertex(),
333  cdata, current_thread);
334 }
335 
336 /**
337  * Expands min_point and max_point to include all of the vertices in the Geom,
338  * if any. found_any is set true if any points are found. It is the caller's
339  * responsibility to initialize min_point, max_point, and found_any before
340  * calling this function.
341  *
342  * This version of the method assumes the Geom will use its own vertex data,
343  * and the results are computed in the Geom's own coordinate space.
344  */
345 INLINE void Geom::
346 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
347  bool &found_any, Thread *current_thread) const {
348 
349  calc_tight_bounds(min_point, max_point, found_any,
350  get_vertex_data(current_thread), false,
351  LMatrix4::ident_mat(),
352  current_thread);
353 }
354 
355 /**
356  * Similar to calc_tight_bounds(), for UV coordinates or other named columns.
357  */
358 INLINE void Geom::
359 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
360  bool &found_any,
361  const GeomVertexData *vertex_data,
362  bool got_mat, const LMatrix4 &mat,
363  const InternalName *column_name,
364  Thread *current_thread) const {
365  CDReader cdata(_cycler, current_thread);
366 
367  PN_stdfloat sq_radius;
368  do_calc_tight_bounds(min_point, max_point, sq_radius, found_any,
369  vertex_data, got_mat, mat,
370  column_name, cdata, current_thread);
371 }
372 
373 /**
374  * Should be called to mark the internal bounding volume stale, so that
375  * recompute_internal_bounds() will be called when the bounding volume is next
376  * requested.
377  */
378 INLINE void Geom::
379 mark_internal_bounds_stale(CData *cdata) {
380  cdata->_internal_bounds_stale = true;
381 }
382 
383 /**
384  *
385  */
386 INLINE Geom::CDataCache::
387 CDataCache() :
388  _source(nullptr),
389  _geom_result(nullptr),
390  _data_result(nullptr)
391 {
392 }
393 
394 /**
395  *
396  */
397 INLINE Geom::CDataCache::
398 CDataCache(const Geom::CDataCache &copy) :
399  _source(copy._source),
400  _geom_result(copy._geom_result),
401  _data_result(copy._data_result)
402 {
403  if (_geom_result != _source && _geom_result != nullptr) {
404  _geom_result->ref();
405  }
406 }
407 
408 /**
409  * Stores the geom_result and data_result on the cache, upping and/or dropping
410  * the reference count appropriately.
411  */
412 INLINE void Geom::CDataCache::
413 set_result(const Geom *geom_result, const GeomVertexData *data_result) {
414  if (geom_result != _geom_result) {
415  if (_geom_result != _source && _geom_result != nullptr) {
416  unref_delete(_geom_result);
417  }
418  _geom_result = geom_result;
419  if (_geom_result != _source && _geom_result != nullptr) {
420  _geom_result->ref();
421  }
422  }
423  _data_result = data_result;
424 }
425 
426 /**
427  *
428  */
429 INLINE Geom::CacheKey::
430 CacheKey(const GeomVertexData *source_data, const GeomMunger *modifier) :
431  _source_data(source_data),
432  _modifier(modifier)
433 {
434 }
435 
436 /**
437  *
438  */
439 INLINE Geom::CacheKey::
440 CacheKey(const CacheKey &copy) :
441  _source_data(copy._source_data),
442  _modifier(copy._modifier)
443 {
444 }
445 
446 /**
447  *
448  */
449 INLINE Geom::CacheKey::
450 CacheKey(CacheKey &&from) noexcept :
451  _source_data(std::move(from._source_data)),
452  _modifier(std::move(from._modifier))
453 {
454 }
455 
456 /**
457  * Provides a unique ordering within the map.
458  */
459 INLINE bool Geom::CacheKey::
460 operator < (const CacheKey &other) const {
461  if (_modifier != other._modifier) {
462  int compare = _modifier->geom_compare_to(*other._modifier);
463  if (compare != 0) {
464  return (compare < 0);
465  }
466  }
467  if (_source_data != other._source_data) {
468  return (_source_data < other._source_data);
469  }
470  return 0;
471 }
472 
473 /**
474  *
475  */
476 INLINE Geom::CacheEntry::
477 CacheEntry(Geom *source, const GeomVertexData *source_data,
478  const GeomMunger *modifier) :
479  _source(source),
480  _key(source_data, modifier)
481 {
482 }
483 
484 /**
485  *
486  */
487 INLINE Geom::CacheEntry::
488 CacheEntry(Geom *source, const Geom::CacheKey &key) :
489  _source(source),
490  _key(key)
491 {
492 }
493 
494 /**
495  *
496  */
497 INLINE Geom::CacheEntry::
498 CacheEntry(Geom *source, Geom::CacheKey &&key) noexcept :
499  _source(source),
500  _key(std::move(key))
501 {
502 }
503 
504 /**
505  *
506  */
507 INLINE Geom::CData::
508 CData() :
509  _primitive_type(PT_none),
510  _shade_model(SM_uniform),
511  _geom_rendering(0),
512  _nested_vertices(0),
513  _internal_bounds_stale(true),
514  _bounds_type(BoundingVolume::BT_default)
515 {
516 }
517 
518 /**
519  *
520  */
521 INLINE Geom::CData::
522 CData(GeomVertexData *data) :
523  _data(data),
524  _primitive_type(PT_none),
525  _shade_model(SM_uniform),
526  _geom_rendering(0),
527  _nested_vertices(0),
528  _internal_bounds_stale(true),
529  _bounds_type(BoundingVolume::BT_default)
530 {
531 }
532 
533 /**
534  *
535  */
536 INLINE GeomPipelineReader::
537 GeomPipelineReader(Thread *current_thread) :
538  _object(nullptr),
539  _current_thread(current_thread),
540  _cdata(nullptr)
541 {
542 }
543 
544 /**
545  *
546  */
547 INLINE GeomPipelineReader::
548 GeomPipelineReader(const Geom *object, Thread *current_thread) :
549  _object(object),
550  _current_thread(current_thread),
551  _cdata(object->_cycler.read_unlocked(current_thread))
552 {
553 #ifdef _DEBUG
554  nassertv(_object->test_ref_count_nonzero());
555 #endif // _DEBUG
556 #ifdef DO_PIPELINING
557  _cdata->ref();
558 #endif // DO_PIPELINING
559 }
560 
561 /**
562  *
563  */
564 INLINE GeomPipelineReader::
565 ~GeomPipelineReader() {
566 #ifdef _DEBUG
567  if (_object != nullptr) {
568  nassertv(_object->test_ref_count_nonzero());
569  }
570 #endif // _DEBUG
571  // _object->_cycler.release_read(_cdata);
572 
573 #ifdef DO_PIPELINING
574  if (_cdata != nullptr) {
575  unref_delete((CycleData *)_cdata);
576  }
577 #endif // DO_PIPELINING
578 
579 #ifdef _DEBUG
580  _object = nullptr;
581  _cdata = nullptr;
582 #endif // _DEBUG
583 }
584 
585 /**
586  *
587  */
588 INLINE void GeomPipelineReader::
589 set_object(const Geom *object) {
590  if (object != _object) {
591  // _object->_cycler.release_read(_cdata);
592 
593 #ifdef DO_PIPELINING
594  if (_cdata != nullptr) {
595  unref_delete((CycleData *)_cdata);
596  }
597 #endif // DO_PIPELINING
598 
599  _cdata = object->_cycler.read_unlocked(_current_thread);
600 
601 #ifdef DO_PIPELINING
602  _cdata->ref();
603 #endif // DO_PIPELINING
604 
605  _object = object;
606  }
607 }
608 
609 /**
610  *
611  */
612 INLINE const Geom *GeomPipelineReader::
613 get_object() const {
614  return _object;
615 }
616 
617 /**
618  *
619  */
620 INLINE Thread *GeomPipelineReader::
621 get_current_thread() const {
622  return _current_thread;
623 }
624 
625 /**
626  *
627  */
628 INLINE GeomPipelineReader::PrimitiveType GeomPipelineReader::
629 get_primitive_type() const {
630  return _cdata->_primitive_type;
631 }
632 
633 /**
634  *
635  */
636 INLINE GeomPipelineReader::ShadeModel GeomPipelineReader::
637 get_shade_model() const {
638  return _cdata->_shade_model;
639 }
640 
641 /**
642  *
643  */
644 INLINE int GeomPipelineReader::
645 get_geom_rendering() const {
646  return _cdata->_geom_rendering;
647 }
648 
649 /**
650  *
651  */
652 INLINE CPT(GeomVertexData) GeomPipelineReader::
653 get_vertex_data() const {
654  return _cdata->_data.get_read_pointer();
655 }
656 
657 /**
658  *
659  */
660 INLINE int GeomPipelineReader::
661 get_num_primitives() const {
662  return _cdata->_primitives.size();
663 }
664 
665 /**
666  *
667  */
668 INLINE CPT(GeomPrimitive) GeomPipelineReader::
669 get_primitive(int i) const {
670  nassertr(i >= 0 && i < (int)_cdata->_primitives.size(), nullptr);
671  return _cdata->_primitives[i].get_read_pointer();
672 }
673 
674 /**
675  *
676  */
677 INLINE UpdateSeq GeomPipelineReader::
678 get_modified() const {
679  return _cdata->_modified;
680 }
681 
682 /**
683  * Creates a context for the geom on the particular GSG, if it does not
684  * already exist. Returns the new (or old) GeomContext. This assumes that
685  * the GraphicsStateGuardian is the currently active rendering context and
686  * that it is ready to accept new geoms. If this is not necessarily the case,
687  * you should use prepare() instead.
688  *
689  * Normally, this is not called directly except by the GraphicsStateGuardian;
690  * a geom does not need to be explicitly prepared by the user before it may be
691  * rendered.
692  */
693 INLINE GeomContext *GeomPipelineReader::
694 prepare_now(PreparedGraphicsObjects *prepared_objects,
695  GraphicsStateGuardianBase *gsg) const {
696  return ((Geom *)_object)->prepare_now(prepared_objects, gsg);
697 }
698 
699 INLINE std::ostream &
700 operator << (std::ostream &out, const Geom &obj) {
701  obj.output(out);
702  return out;
703 }
This is a special class object that holds all the information returned by a particular GSG to indicat...
Definition: geomContext.h:34
Objects of this class are used to convert vertex data from a Geom into a format suitable for passing ...
Definition: geomMunger.h:50
void set_bounds(const BoundingVolume *volume)
Resets the bounding volume so that it is the indicated volume.
Definition: geom.I:286
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:47
insert_primitive
Inserts a new GeomPrimitive structure to the Geom object.
Definition: geom.h:101
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
void add_primitive(const GeomPrimitive *primitive)
Inserts a new GeomPrimitive structure to the Geom object.
Definition: geom.I:116
void clear_bounds()
Reverses the effect of a previous call to set_bounds(), and allows the bounding volume to be automati...
Definition: geom.I:304
A table of objects that are saved within the graphics context for reference by handle later...
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
void clear_cache_stage(Thread *current_thread)
Removes all of the previously-cached results of munge_geom(), at the current pipeline stage and upstr...
Definition: geom.cxx:1184
virtual Geom * make_copy() const
Returns a newly-allocated Geom that is a shallow copy of this one.
Definition: geom.cxx:100
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
Definition: geom.h:54
bool operator<(const CacheKey &other) const
Provides a unique ordering within the map.
Definition: geom.I:460
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
PT(Geom) Geom
Decomposes all of the primitives within this Geom, returning the result.
Definition: geom.I:124
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
void ref() const
Explicitly increments the reference count.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
A thread; that is, a lightweight process.
Definition: thread.h:46
static UpdateSeq get_next_modified()
Returns a monotonically increasing sequence.
Definition: geom.cxx:1322
CPT(GeomVertexData) Geom
Returns a const pointer to the GeomVertexData, for application code to directly examine (but not modi...
Definition: geom.I:51
This is a sequence number that increments monotonically.
Definition: updateSeq.h:37
void calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, bool &found_any, const GeomVertexData *vertex_data, bool got_mat, const LMatrix4 &mat, Thread *current_thread) const
Expands min_point and max_point to include all of the vertices in the Geom, if any.
Definition: geom.I:322
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...