Panda3D
Loading...
Searching...
No Matches
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->_nested_vertices = 0;
383 cdata->_internal_bounds_stale = true;
384}
385
386/**
387 *
388 */
389INLINE Geom::CDataCache::
390CDataCache() :
391 _source(nullptr),
392 _geom_result(nullptr),
393 _data_result(nullptr)
394{
395}
396
397/**
398 *
399 */
400INLINE Geom::CDataCache::
401CDataCache(const Geom::CDataCache &copy) :
402 _source(copy._source),
403 _geom_result(copy._geom_result),
404 _data_result(copy._data_result)
405{
406 if (_geom_result != _source && _geom_result != nullptr) {
407 _geom_result->ref();
408 }
409}
410
411/**
412 * Stores the geom_result and data_result on the cache, upping and/or dropping
413 * the reference count appropriately.
414 */
415INLINE void Geom::CDataCache::
416set_result(const Geom *geom_result, const GeomVertexData *data_result) {
417 if (geom_result != _geom_result) {
418 if (_geom_result != _source && _geom_result != nullptr) {
419 unref_delete(_geom_result);
420 }
421 _geom_result = geom_result;
422 if (_geom_result != _source && _geom_result != nullptr) {
423 _geom_result->ref();
424 }
425 }
426 _data_result = data_result;
427}
428
429/**
430 *
431 */
432INLINE Geom::CacheKey::
433CacheKey(const GeomVertexData *source_data, const GeomMunger *modifier) :
434 _source_data(source_data),
435 _modifier(modifier)
436{
437}
438
439/**
440 *
441 */
442INLINE Geom::CacheKey::
443CacheKey(const CacheKey &copy) :
444 _source_data(copy._source_data),
445 _modifier(copy._modifier)
446{
447}
448
449/**
450 *
451 */
452INLINE Geom::CacheKey::
453CacheKey(CacheKey &&from) noexcept :
454 _source_data(std::move(from._source_data)),
455 _modifier(std::move(from._modifier))
456{
457}
458
459/**
460 * Provides a unique ordering within the map.
461 */
463operator < (const CacheKey &other) const {
464 if (_modifier != other._modifier) {
465 int compare = _modifier->geom_compare_to(*other._modifier);
466 if (compare != 0) {
467 return (compare < 0);
468 }
469 }
470 if (_source_data != other._source_data) {
471 return (_source_data < other._source_data);
472 }
473 return 0;
474}
475
476/**
477 *
478 */
479INLINE Geom::CacheEntry::
480CacheEntry(Geom *source, const GeomVertexData *source_data,
481 const GeomMunger *modifier) :
482 _source(source),
483 _key(source_data, modifier)
484{
485}
486
487/**
488 *
489 */
490INLINE Geom::CacheEntry::
491CacheEntry(Geom *source, const Geom::CacheKey &key) :
492 _source(source),
493 _key(key)
494{
495}
496
497/**
498 *
499 */
500INLINE Geom::CacheEntry::
501CacheEntry(Geom *source, Geom::CacheKey &&key) noexcept :
502 _source(source),
503 _key(std::move(key))
504{
505}
506
507/**
508 *
509 */
510INLINE Geom::CData::
511CData() :
512 _primitive_type(PT_none),
513 _shade_model(SM_uniform),
514 _geom_rendering(0),
515 _nested_vertices(0),
516 _internal_bounds_stale(true),
517 _bounds_type(BoundingVolume::BT_default)
518{
519}
520
521/**
522 *
523 */
524INLINE Geom::CData::
525CData(GeomVertexData *data) :
526 _data(data),
527 _primitive_type(PT_none),
528 _shade_model(SM_uniform),
529 _geom_rendering(0),
530 _nested_vertices(0),
531 _internal_bounds_stale(true),
532 _bounds_type(BoundingVolume::BT_default)
533{
534}
535
536/**
537 *
538 */
539INLINE GeomPipelineReader::
540GeomPipelineReader(Thread *current_thread) :
541 _object(nullptr),
542 _current_thread(current_thread),
543 _cdata(nullptr)
544{
545}
546
547/**
548 *
549 */
550INLINE GeomPipelineReader::
551GeomPipelineReader(const Geom *object, Thread *current_thread) :
552 _object(object),
553 _current_thread(current_thread),
554 _cdata(object->_cycler.read_unlocked(current_thread))
555{
556#ifdef _DEBUG
557 nassertv(_object->test_ref_count_nonzero());
558#endif // _DEBUG
559#ifdef DO_PIPELINING
560 _cdata->ref();
561#endif // DO_PIPELINING
562}
563
564/**
565 *
566 */
567INLINE GeomPipelineReader::
568~GeomPipelineReader() {
569#ifdef _DEBUG
570 if (_object != nullptr) {
571 nassertv(_object->test_ref_count_nonzero());
572 }
573#endif // _DEBUG
574 // _object->_cycler.release_read(_cdata);
575
576#ifdef DO_PIPELINING
577 if (_cdata != nullptr) {
578 unref_delete((CycleData *)_cdata);
579 }
580#endif // DO_PIPELINING
581
582#ifdef _DEBUG
583 _object = nullptr;
584 _cdata = nullptr;
585#endif // _DEBUG
586}
587
588/**
589 *
590 */
591INLINE void GeomPipelineReader::
592set_object(const Geom *object) {
593 if (object != _object) {
594 // _object->_cycler.release_read(_cdata);
595
596#ifdef DO_PIPELINING
597 if (_cdata != nullptr) {
598 unref_delete((CycleData *)_cdata);
599 }
600#endif // DO_PIPELINING
601
602 _cdata = object->_cycler.read_unlocked(_current_thread);
603
604#ifdef DO_PIPELINING
605 _cdata->ref();
606#endif // DO_PIPELINING
607
608 _object = object;
609 }
610}
611
612/**
613 *
614 */
615INLINE const Geom *GeomPipelineReader::
616get_object() const {
617 return _object;
618}
619
620/**
621 *
622 */
623INLINE Thread *GeomPipelineReader::
624get_current_thread() const {
625 return _current_thread;
626}
627
628/**
629 *
630 */
631INLINE GeomPipelineReader::PrimitiveType GeomPipelineReader::
632get_primitive_type() const {
633 return _cdata->_primitive_type;
634}
635
636/**
637 *
638 */
639INLINE GeomPipelineReader::ShadeModel GeomPipelineReader::
640get_shade_model() const {
641 return _cdata->_shade_model;
642}
643
644/**
645 *
646 */
647INLINE int GeomPipelineReader::
648get_geom_rendering() const {
649 return _cdata->_geom_rendering;
650}
651
652/**
653 *
654 */
655INLINE CPT(GeomVertexData) GeomPipelineReader::
656get_vertex_data() const {
657 return _cdata->_data.get_read_pointer();
658}
659
660/**
661 *
662 */
663INLINE int GeomPipelineReader::
664get_num_primitives() const {
665 return _cdata->_primitives.size();
666}
667
668/**
669 *
670 */
671INLINE CPT(GeomPrimitive) GeomPipelineReader::
672get_primitive(int i) const {
673 nassertr(i >= 0 && i < (int)_cdata->_primitives.size(), nullptr);
674 return _cdata->_primitives[i].get_read_pointer();
675}
676
677/**
678 *
679 */
680INLINE UpdateSeq GeomPipelineReader::
681get_modified() const {
682 return _cdata->_modified;
683}
684
685/**
686 * Creates a context for the geom on the particular GSG, if it does not
687 * already exist. Returns the new (or old) GeomContext. This assumes that
688 * the GraphicsStateGuardian is the currently active rendering context and
689 * that it is ready to accept new geoms. If this is not necessarily the case,
690 * you should use prepare() instead.
691 *
692 * Normally, this is not called directly except by the GraphicsStateGuardian;
693 * a geom does not need to be explicitly prepared by the user before it may be
694 * rendered.
695 */
696INLINE GeomContext *GeomPipelineReader::
697prepare_now(PreparedGraphicsObjects *prepared_objects,
698 GraphicsStateGuardianBase *gsg) const {
699 return ((Geom *)_object)->prepare_now(prepared_objects, gsg);
700}
701
702INLINE std::ostream &
703operator << (std::ostream &out, const Geom &obj) {
704 obj.output(out);
705 return out;
706}
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...
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:463
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:1218
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:1356
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.
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
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...