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  * @since 1.10.0
220  */
221 INLINE PT(Geom) Geom::
222 make_adjacency() const {
223  PT(Geom) new_geom = make_copy();
224  new_geom->make_adjacency_in_place();
225  return new_geom;
226 }
227 
228 /**
229  * Returns a sequence number which is guaranteed to change at least every time
230  * any of the primitives in the Geom is modified, or the set of primitives is
231  * modified. However, this does not include modifications to the vertex data,
232  * which should be tested separately.
233  */
234 INLINE UpdateSeq Geom::
235 get_modified(Thread *current_thread) const {
236  CDReader cdata(_cycler, current_thread);
237  return cdata->_modified;
238 }
239 
240 /**
241  * Marks the bounding volume of the Geom as stale so that it should be
242  * recomputed. Usually it is not necessary to call this explicitly.
243  */
244 INLINE void Geom::
245 mark_bounds_stale() const {
246  CDWriter cdata(((Geom *)this)->_cycler, false);
247  ((Geom *)this)->mark_internal_bounds_stale(cdata);
248 }
249 
250 /**
251  * Specifies the desired type of bounding volume that will be created for this
252  * Geom. This is normally BoundingVolume::BT_default, which means to set the
253  * type according to the config variable "bounds-type".
254  *
255  * If this is BT_sphere or BT_box, a BoundingSphere or BoundingBox is
256  * explicitly created. If it is BT_best, a BoundingBox is created.
257  *
258  * This affects the implicit bounding volume only. If an explicit bounding
259  * volume is set on the Geom with set_bounds(), that bounding volume type is
260  * used. (This is different behavior from the similar method on PandaNode.)
261  */
262 INLINE void Geom::
263 set_bounds_type(BoundingVolume::BoundsType bounds_type) {
264  CDWriter cdata(_cycler, true);
265  cdata->_bounds_type = bounds_type;
266  mark_internal_bounds_stale(cdata);
267 }
268 
269 /**
270  * Returns the bounding volume type set with set_bounds_type().
271  */
272 INLINE BoundingVolume::BoundsType Geom::
273 get_bounds_type() const {
274  CDReader cdata(_cycler);
275  return cdata->_bounds_type;
276 }
277 
278 /**
279  * Resets the bounding volume so that it is the indicated volume. When it is
280  * explicitly set, the bounding volume will no longer be automatically
281  * computed; call clear_bounds() if you would like to return the bounding
282  * volume to its default behavior.
283  *
284  * Don't call this in a downstream thread unless you don't mind it blowing
285  * away other changes you might have recently made in an upstream thread.
286  */
287 INLINE void Geom::
288 set_bounds(const BoundingVolume *volume) {
289  CDWriter cdata(_cycler, true);
290  if (volume == nullptr) {
291  cdata->_user_bounds = nullptr;
292  } else {
293  cdata->_user_bounds = volume->make_copy();
294  }
295 }
296 
297 /**
298  * Reverses the effect of a previous call to set_bounds(), and allows the
299  * bounding volume to be automatically computed once more based on the
300  * vertices.
301  *
302  * Don't call this in a downstream thread unless you don't mind it blowing
303  * away other changes you might have recently made in an upstream thread.
304  */
305 INLINE void Geom::
307  CDWriter cdata(_cycler, true);
308  cdata->_user_bounds = nullptr;
309  mark_internal_bounds_stale(cdata);
310 }
311 
312 /**
313  * Expands min_point and max_point to include all of the vertices in the Geom,
314  * if any. found_any is set true if any points are found. It is the caller's
315  * responsibility to initialize min_point, max_point, and found_any before
316  * calling this function.
317  *
318  * This version of the method allows the Geom to specify an alternate vertex
319  * data table (for instance, if the vertex data has already been munged), and
320  * also allows the result to be computed in any coordinate space by specifying
321  * a transform matrix.
322  */
323 INLINE void Geom::
324 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
325  bool &found_any,
326  const GeomVertexData *vertex_data,
327  bool got_mat, const LMatrix4 &mat,
328  Thread *current_thread) const {
329  CDReader cdata(_cycler, current_thread);
330 
331  PN_stdfloat sq_radius;
332  do_calc_tight_bounds(min_point, max_point, sq_radius, found_any,
333  vertex_data, got_mat, mat,
334  InternalName::get_vertex(),
335  cdata, current_thread);
336 }
337 
338 /**
339  * Expands min_point and max_point to include all of the vertices in the Geom,
340  * if any. found_any is set true if any points are found. It is the caller's
341  * responsibility to initialize min_point, max_point, and found_any before
342  * calling this function.
343  *
344  * This version of the method assumes the Geom will use its own vertex data,
345  * and the results are computed in the Geom's own coordinate space.
346  */
347 INLINE void Geom::
348 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
349  bool &found_any, Thread *current_thread) const {
350 
351  calc_tight_bounds(min_point, max_point, found_any,
352  get_vertex_data(current_thread), false,
353  LMatrix4::ident_mat(),
354  current_thread);
355 }
356 
357 /**
358  * Similar to calc_tight_bounds(), for UV coordinates or other named columns.
359  */
360 INLINE void Geom::
361 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
362  bool &found_any,
363  const GeomVertexData *vertex_data,
364  bool got_mat, const LMatrix4 &mat,
365  const InternalName *column_name,
366  Thread *current_thread) const {
367  CDReader cdata(_cycler, current_thread);
368 
369  PN_stdfloat sq_radius;
370  do_calc_tight_bounds(min_point, max_point, sq_radius, found_any,
371  vertex_data, got_mat, mat,
372  column_name, cdata, current_thread);
373 }
374 
375 /**
376  * Should be called to mark the internal bounding volume stale, so that
377  * recompute_internal_bounds() will be called when the bounding volume is next
378  * requested.
379  */
380 INLINE void Geom::
381 mark_internal_bounds_stale(CData *cdata) {
382  cdata->_internal_bounds_stale = true;
383 }
384 
385 /**
386  *
387  */
388 INLINE Geom::CDataCache::
389 CDataCache() :
390  _source(nullptr),
391  _geom_result(nullptr),
392  _data_result(nullptr)
393 {
394 }
395 
396 /**
397  *
398  */
399 INLINE Geom::CDataCache::
400 CDataCache(const Geom::CDataCache &copy) :
401  _source(copy._source),
402  _geom_result(copy._geom_result),
403  _data_result(copy._data_result)
404 {
405  if (_geom_result != _source && _geom_result != nullptr) {
406  _geom_result->ref();
407  }
408 }
409 
410 /**
411  * Stores the geom_result and data_result on the cache, upping and/or dropping
412  * the reference count appropriately.
413  */
414 INLINE void Geom::CDataCache::
415 set_result(const Geom *geom_result, const GeomVertexData *data_result) {
416  if (geom_result != _geom_result) {
417  if (_geom_result != _source && _geom_result != nullptr) {
418  unref_delete(_geom_result);
419  }
420  _geom_result = geom_result;
421  if (_geom_result != _source && _geom_result != nullptr) {
422  _geom_result->ref();
423  }
424  }
425  _data_result = data_result;
426 }
427 
428 /**
429  *
430  */
431 INLINE Geom::CacheKey::
432 CacheKey(const GeomVertexData *source_data, const GeomMunger *modifier) :
433  _source_data(source_data),
434  _modifier(modifier)
435 {
436 }
437 
438 /**
439  *
440  */
441 INLINE Geom::CacheKey::
442 CacheKey(const CacheKey &copy) :
443  _source_data(copy._source_data),
444  _modifier(copy._modifier)
445 {
446 }
447 
448 /**
449  *
450  */
451 INLINE Geom::CacheKey::
452 CacheKey(CacheKey &&from) noexcept :
453  _source_data(std::move(from._source_data)),
454  _modifier(std::move(from._modifier))
455 {
456 }
457 
458 /**
459  * Provides a unique ordering within the map.
460  */
461 INLINE bool Geom::CacheKey::
462 operator < (const CacheKey &other) const {
463  if (_modifier != other._modifier) {
464  int compare = _modifier->geom_compare_to(*other._modifier);
465  if (compare != 0) {
466  return (compare < 0);
467  }
468  }
469  if (_source_data != other._source_data) {
470  return (_source_data < other._source_data);
471  }
472  return 0;
473 }
474 
475 /**
476  *
477  */
478 INLINE Geom::CacheEntry::
479 CacheEntry(Geom *source, const GeomVertexData *source_data,
480  const GeomMunger *modifier) :
481  _source(source),
482  _key(source_data, modifier)
483 {
484 }
485 
486 /**
487  *
488  */
489 INLINE Geom::CacheEntry::
490 CacheEntry(Geom *source, const Geom::CacheKey &key) :
491  _source(source),
492  _key(key)
493 {
494 }
495 
496 /**
497  *
498  */
499 INLINE Geom::CacheEntry::
500 CacheEntry(Geom *source, Geom::CacheKey &&key) noexcept :
501  _source(source),
502  _key(std::move(key))
503 {
504 }
505 
506 /**
507  *
508  */
509 INLINE Geom::CData::
510 CData() :
511  _primitive_type(PT_none),
512  _shade_model(SM_uniform),
513  _geom_rendering(0),
514  _nested_vertices(0),
515  _internal_bounds_stale(true),
516  _bounds_type(BoundingVolume::BT_default)
517 {
518 }
519 
520 /**
521  *
522  */
523 INLINE Geom::CData::
524 CData(GeomVertexData *data) :
525  _data(data),
526  _primitive_type(PT_none),
527  _shade_model(SM_uniform),
528  _geom_rendering(0),
529  _nested_vertices(0),
530  _internal_bounds_stale(true),
531  _bounds_type(BoundingVolume::BT_default)
532 {
533 }
534 
535 /**
536  *
537  */
538 INLINE GeomPipelineReader::
539 GeomPipelineReader(Thread *current_thread) :
540  _object(nullptr),
541  _current_thread(current_thread),
542  _cdata(nullptr)
543 {
544 }
545 
546 /**
547  *
548  */
549 INLINE GeomPipelineReader::
550 GeomPipelineReader(const Geom *object, Thread *current_thread) :
551  _object(object),
552  _current_thread(current_thread),
553  _cdata(object->_cycler.read_unlocked(current_thread))
554 {
555 #ifdef _DEBUG
556  nassertv(_object->test_ref_count_nonzero());
557 #endif // _DEBUG
558 #ifdef DO_PIPELINING
559  _cdata->ref();
560 #endif // DO_PIPELINING
561 }
562 
563 /**
564  *
565  */
566 INLINE GeomPipelineReader::
567 ~GeomPipelineReader() {
568 #ifdef _DEBUG
569  if (_object != nullptr) {
570  nassertv(_object->test_ref_count_nonzero());
571  }
572 #endif // _DEBUG
573  // _object->_cycler.release_read(_cdata);
574 
575 #ifdef DO_PIPELINING
576  if (_cdata != nullptr) {
577  unref_delete((CycleData *)_cdata);
578  }
579 #endif // DO_PIPELINING
580 
581 #ifdef _DEBUG
582  _object = nullptr;
583  _cdata = nullptr;
584 #endif // _DEBUG
585 }
586 
587 /**
588  *
589  */
590 INLINE void GeomPipelineReader::
591 set_object(const Geom *object) {
592  if (object != _object) {
593  // _object->_cycler.release_read(_cdata);
594 
595 #ifdef DO_PIPELINING
596  if (_cdata != nullptr) {
597  unref_delete((CycleData *)_cdata);
598  }
599 #endif // DO_PIPELINING
600 
601  _cdata = object->_cycler.read_unlocked(_current_thread);
602 
603 #ifdef DO_PIPELINING
604  _cdata->ref();
605 #endif // DO_PIPELINING
606 
607  _object = object;
608  }
609 }
610 
611 /**
612  *
613  */
614 INLINE const Geom *GeomPipelineReader::
615 get_object() const {
616  return _object;
617 }
618 
619 /**
620  *
621  */
622 INLINE Thread *GeomPipelineReader::
623 get_current_thread() const {
624  return _current_thread;
625 }
626 
627 /**
628  *
629  */
630 INLINE GeomPipelineReader::PrimitiveType GeomPipelineReader::
631 get_primitive_type() const {
632  return _cdata->_primitive_type;
633 }
634 
635 /**
636  *
637  */
638 INLINE GeomPipelineReader::ShadeModel GeomPipelineReader::
639 get_shade_model() const {
640  return _cdata->_shade_model;
641 }
642 
643 /**
644  *
645  */
646 INLINE int GeomPipelineReader::
647 get_geom_rendering() const {
648  return _cdata->_geom_rendering;
649 }
650 
651 /**
652  *
653  */
654 INLINE CPT(GeomVertexData) GeomPipelineReader::
655 get_vertex_data() const {
656  return _cdata->_data.get_read_pointer();
657 }
658 
659 /**
660  *
661  */
662 INLINE int GeomPipelineReader::
663 get_num_primitives() const {
664  return _cdata->_primitives.size();
665 }
666 
667 /**
668  *
669  */
670 INLINE CPT(GeomPrimitive) GeomPipelineReader::
671 get_primitive(int i) const {
672  nassertr(i >= 0 && i < (int)_cdata->_primitives.size(), nullptr);
673  return _cdata->_primitives[i].get_read_pointer();
674 }
675 
676 /**
677  *
678  */
679 INLINE UpdateSeq GeomPipelineReader::
680 get_modified() const {
681  return _cdata->_modified;
682 }
683 
684 /**
685  * Creates a context for the geom on the particular GSG, if it does not
686  * already exist. Returns the new (or old) GeomContext. This assumes that
687  * the GraphicsStateGuardian is the currently active rendering context and
688  * that it is ready to accept new geoms. If this is not necessarily the case,
689  * you should use prepare() instead.
690  *
691  * Normally, this is not called directly except by the GraphicsStateGuardian;
692  * a geom does not need to be explicitly prepared by the user before it may be
693  * rendered.
694  */
695 INLINE GeomContext *GeomPipelineReader::
696 prepare_now(PreparedGraphicsObjects *prepared_objects,
697  GraphicsStateGuardianBase *gsg) const {
698  return ((Geom *)_object)->prepare_now(prepared_objects, gsg);
699 }
700 
701 INLINE std::ostream &
702 operator << (std::ostream &out, const Geom &obj) {
703  obj.output(out);
704  return out;
705 }
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:288
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:306
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:1186
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:462
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:1324
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:324
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...