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 */
21INLINE Geom::PrimitiveType Geom::
22get_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 */
31INLINE Geom::ShadeModel Geom::
32get_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 */
41INLINE int Geom::
42get_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 */
51INLINE CPT(GeomVertexData) Geom::
52get_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 */
61INLINE bool Geom::
62is_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 */
71INLINE size_t Geom::
72get_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 */
82INLINE CPT(GeomPrimitive) Geom::
83get_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 */
97INLINE PT(GeomPrimitive) Geom::
98modify_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 */
115INLINE void Geom::
116add_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 */
124INLINE PT(Geom) Geom::
125decompose() 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 */
135INLINE PT(Geom) Geom::
136doubleside() 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 */
146INLINE PT(Geom) Geom::
147reverse() 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 */
157INLINE PT(Geom) Geom::
158rotate() 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 */
175INLINE PT(Geom) Geom::
176unify(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 */
186INLINE PT(Geom) Geom::
187make_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 */
197INLINE PT(Geom) Geom::
198make_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 */
208INLINE PT(Geom) Geom::
209make_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 */
221INLINE PT(Geom) Geom::
222make_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 */
234INLINE UpdateSeq Geom::
235get_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 */
244INLINE void Geom::
245mark_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 */
262INLINE void Geom::
263set_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 */
272INLINE BoundingVolume::BoundsType Geom::
273get_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 */
287INLINE void Geom::
288set_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 */
305INLINE void Geom::
306clear_bounds() {
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 */
323INLINE void Geom::
324calc_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 */
347INLINE void Geom::
348calc_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 */
360INLINE void Geom::
361calc_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 */
380INLINE void Geom::
381mark_internal_bounds_stale(CData *cdata) {
382 cdata->_internal_bounds_stale = true;
383}
384
385/**
386 *
387 */
388INLINE Geom::CDataCache::
389CDataCache() :
390 _source(nullptr),
391 _geom_result(nullptr),
392 _data_result(nullptr)
393{
394}
395
396/**
397 *
398 */
399INLINE Geom::CDataCache::
400CDataCache(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 */
414INLINE void Geom::CDataCache::
415set_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 */
431INLINE Geom::CacheKey::
432CacheKey(const GeomVertexData *source_data, const GeomMunger *modifier) :
433 _source_data(source_data),
434 _modifier(modifier)
435{
436}
437
438/**
439 *
440 */
441INLINE Geom::CacheKey::
442CacheKey(const CacheKey &copy) :
443 _source_data(copy._source_data),
444 _modifier(copy._modifier)
445{
446}
447
448/**
449 *
450 */
451INLINE Geom::CacheKey::
452CacheKey(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 */
462operator < (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 */
478INLINE Geom::CacheEntry::
479CacheEntry(Geom *source, const GeomVertexData *source_data,
480 const GeomMunger *modifier) :
481 _source(source),
482 _key(source_data, modifier)
483{
484}
485
486/**
487 *
488 */
489INLINE Geom::CacheEntry::
490CacheEntry(Geom *source, const Geom::CacheKey &key) :
491 _source(source),
492 _key(key)
493{
494}
495
496/**
497 *
498 */
499INLINE Geom::CacheEntry::
500CacheEntry(Geom *source, Geom::CacheKey &&key) noexcept :
501 _source(source),
502 _key(std::move(key))
503{
504}
505
506/**
507 *
508 */
509INLINE Geom::CData::
510CData() :
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 */
523INLINE Geom::CData::
524CData(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 */
538INLINE GeomPipelineReader::
539GeomPipelineReader(Thread *current_thread) :
540 _object(nullptr),
541 _current_thread(current_thread),
542 _cdata(nullptr)
543{
544}
545
546/**
547 *
548 */
549INLINE GeomPipelineReader::
550GeomPipelineReader(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 */
566INLINE 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 */
590INLINE void GeomPipelineReader::
591set_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 */
614INLINE const Geom *GeomPipelineReader::
615get_object() const {
616 return _object;
617}
618
619/**
620 *
621 */
622INLINE Thread *GeomPipelineReader::
623get_current_thread() const {
624 return _current_thread;
625}
626
627/**
628 *
629 */
630INLINE GeomPipelineReader::PrimitiveType GeomPipelineReader::
631get_primitive_type() const {
632 return _cdata->_primitive_type;
633}
634
635/**
636 *
637 */
638INLINE GeomPipelineReader::ShadeModel GeomPipelineReader::
639get_shade_model() const {
640 return _cdata->_shade_model;
641}
642
643/**
644 *
645 */
646INLINE int GeomPipelineReader::
647get_geom_rendering() const {
648 return _cdata->_geom_rendering;
649}
650
651/**
652 *
653 */
654INLINE CPT(GeomVertexData) GeomPipelineReader::
655get_vertex_data() const {
656 return _cdata->_data.get_read_pointer();
657}
658
659/**
660 *
661 */
662INLINE int GeomPipelineReader::
663get_num_primitives() const {
664 return _cdata->_primitives.size();
665}
666
667/**
668 *
669 */
670INLINE CPT(GeomPrimitive) GeomPipelineReader::
671get_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 */
679INLINE UpdateSeq GeomPipelineReader::
680get_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 */
695INLINE GeomContext *GeomPipelineReader::
696prepare_now(PreparedGraphicsObjects *prepared_objects,
697 GraphicsStateGuardianBase *gsg) const {
698 return ((Geom *)_object)->prepare_now(prepared_objects, gsg);
699}
700
701INLINE std::ostream &
702operator << (std::ostream &out, const Geom &obj) {
703 obj.output(out);
704 return out;
705}
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:50
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
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
bool operator<(const CacheKey &other) const
Provides a unique ordering within the map.
Definition: geom.I:462
A container for geometry primitives.
Definition: geom.h:54
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
insert_primitive
Inserts a new GeomPrimitive structure to the Geom object.
Definition: geom.h:101
void set_bounds(const BoundingVolume *volume)
Resets the bounding volume so that it is the indicated volume.
Definition: geom.I:288
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
void add_primitive(const GeomPrimitive *primitive)
Inserts a new GeomPrimitive structure to the Geom object.
Definition: geom.I:116
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:1199
get_bounds_type
Returns the bounding volume type set with set_bounds_type().
Definition: geom.h:143
get_shade_model
Returns the shade model common to all of the individual GeomPrimitives that have been added to the ge...
Definition: geom.h:75
static UpdateSeq get_next_modified()
Returns a monotonically increasing sequence.
Definition: geom.cxx:1337
virtual Geom * make_copy() const
Returns a newly-allocated Geom that is a shallow copy of this one.
Definition: geom.cxx:100
get_primitive_type
Returns the fundamental primitive type that is common to all GeomPrimitives added within the Geom.
Definition: geom.h:74
get_geom_rendering
Returns the set of GeomRendering bits that represent the rendering properties required to properly re...
Definition: geom.h:76
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
A table of objects that are saved within the graphics context for reference by handle later.
void ref() const
Explicitly increments the reference count.
A thread; that is, a lightweight process.
Definition: thread.h:46
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
This is a sequence number that increments monotonically.
Definition: updateSeq.h:37
CPT(GeomVertexData) Geom
Returns a const pointer to the GeomVertexData, for application code to directly examine (but not modi...
Definition: geom.I:51
PT(Geom) Geom
Decomposes all of the primitives within this Geom, returning the result.
Definition: geom.I:124
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...