Panda3D
geom.cxx
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.cxx
10 * @author drose
11 * @date 2005-03-06
12 */
13
14#include "geom.h"
15#include "geomPoints.h"
16#include "geomVertexReader.h"
17#include "geomVertexRewriter.h"
20#include "pStatTimer.h"
21#include "bamReader.h"
22#include "bamWriter.h"
23#include "boundingSphere.h"
24#include "boundingBox.h"
25#include "lightMutexHolder.h"
26#include "config_mathutil.h"
27
28using std::max;
29using std::min;
30
31UpdateSeq Geom::_next_modified;
32PStatCollector Geom::_draw_primitive_setup_pcollector("Draw:Primitive:Setup");
33
34TypeHandle Geom::_type_handle;
35TypeHandle Geom::CDataCache::_type_handle;
36TypeHandle Geom::CacheEntry::_type_handle;
37TypeHandle Geom::CData::_type_handle;
38TypeHandle GeomPipelineReader::_type_handle;
39
40/**
41 * Required to implement CopyOnWriteObject.
42 */
44make_cow_copy() {
45 return make_copy();
46}
47
48/**
49 *
50 */
51Geom::
52Geom(const GeomVertexData *data) : _cycler(CData((GeomVertexData *)data)) {
53}
54
55/**
56 * Use make_copy() to duplicate a Geom.
57 */
58Geom::
59Geom(const Geom &copy) :
61 _cycler(copy._cycler)
62{
63}
64
65/**
66 * The copy assignment operator is not pipeline-safe. This will completely
67 * obliterate all stages of the pipeline, so don't do it for a Geom that is
68 * actively being used for rendering.
69 */
71operator = (const Geom &copy) {
72 CopyOnWriteObject::operator = (copy);
73
74 clear_cache();
75
76 _cycler = copy._cycler;
77
78 OPEN_ITERATE_ALL_STAGES(_cycler) {
79 CDStageWriter cdata(_cycler, pipeline_stage);
80 mark_internal_bounds_stale(cdata);
81 }
82 CLOSE_ITERATE_ALL_STAGES(_cycler);
83}
84
85/**
86 *
87 */
88Geom::
89~Geom() {
90 clear_cache();
92}
93
94/**
95 * Returns a newly-allocated Geom that is a shallow copy of this one. It will
96 * be a different Geom pointer, but its internal data may or may not be shared
97 * with that of the original Geom.
98 */
100make_copy() const {
101 return new Geom(*this);
102}
103
104/**
105 * Returns the minimum (i.e. most dynamic) usage_hint among all of the
106 * individual GeomPrimitives that have been added to the geom.
107 * @deprecated This is no longer very useful.
108 */
109Geom::UsageHint Geom::
110get_usage_hint() const {
111 CDReader cdata(_cycler);
112 GeomEnums::UsageHint hint = UH_unspecified;
113 Primitives::const_iterator pi;
114 for (pi = cdata->_primitives.begin();
115 pi != cdata->_primitives.end();
116 ++pi) {
117 hint = min(hint, (*pi).get_read_pointer()->get_usage_hint());
118 }
119 return hint;
120}
121
122/**
123 * Changes the UsageHint hint for all of the primitives on this Geom to the
124 * same value. See get_usage_hint().
125 *
126 * Don't call this in a downstream thread unless you don't mind it blowing
127 * away other changes you might have recently made in an upstream thread.
128 */
130set_usage_hint(Geom::UsageHint usage_hint) {
131 Thread *current_thread = Thread::get_current_thread();
132 CDWriter cdata(_cycler, true, current_thread);
133
134 Primitives::iterator pi;
135 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
136 PT(GeomPrimitive) prim = (*pi).get_write_pointer();
137 prim->set_usage_hint(usage_hint);
138 }
139
140 clear_cache_stage(current_thread);
141 cdata->_modified = Geom::get_next_modified();
142}
143
144/**
145 * Returns a modifiable pointer to the GeomVertexData, so that application
146 * code may directly maniuplate the geom's underlying data.
147 *
148 * Don't call this in a downstream thread unless you don't mind it blowing
149 * away other changes you might have recently made in an upstream thread.
150 */
152modify_vertex_data() {
153 Thread *current_thread = Thread::get_current_thread();
154 // Perform copy-on-write: if the reference count on the vertex data is
155 // greater than 1, assume some other Geom has the same pointer, so make a
156 // copy of it first.
157 CDWriter cdata(_cycler, true, current_thread);
158 clear_cache_stage(current_thread);
159 mark_internal_bounds_stale(cdata);
160 return cdata->_data.get_write_pointer();
161}
162
163/**
164 * Replaces the Geom's underlying vertex data table with a completely new
165 * table.
166 *
167 * Don't call this in a downstream thread unless you don't mind it blowing
168 * away other changes you might have recently made in an upstream thread.
169 */
171set_vertex_data(const GeomVertexData *data) {
172 Thread *current_thread = Thread::get_current_thread();
173 nassertv(check_will_be_valid(data));
174 CDWriter cdata(_cycler, true, current_thread);
175 cdata->_data = (GeomVertexData *)data;
176 clear_cache_stage(current_thread);
177 mark_internal_bounds_stale(cdata);
178 reset_geom_rendering(cdata);
179}
180
181/**
182 * Replaces a Geom's vertex table with a new table, and simultaneously adds
183 * the indicated offset to all vertex references within the Geom's primitives.
184 * This is intended to be used to combine multiple GeomVertexDatas from
185 * different Geoms into a single big buffer, with each Geom referencing a
186 * subset of the vertices in the buffer.
187 *
188 * Don't call this in a downstream thread unless you don't mind it blowing
189 * away other changes you might have recently made in an upstream thread.
190 */
192offset_vertices(const GeomVertexData *data, int offset) {
193 Thread *current_thread = Thread::get_current_thread();
194 CDWriter cdata(_cycler, true, current_thread);
195 cdata->_data = (GeomVertexData *)data;
196
197#ifndef NDEBUG
198 GeomVertexDataPipelineReader data_reader(data, current_thread);
199 data_reader.check_array_readers();
200
201 bool all_is_valid = true;
202#endif
203 Primitives::iterator pi;
204 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
205 PT(GeomPrimitive) prim = (*pi).get_write_pointer();
206 prim->offset_vertices(offset);
207
208#ifndef NDEBUG
209 if (!prim->check_valid(&data_reader)) {
210 gobj_cat.warning()
211 << *prim << " is invalid for " << *data << ":\n";
212 prim->write(gobj_cat.warning(false), 4);
213
214 all_is_valid = false;
215 }
216#endif
217 }
218
219 cdata->_modified = Geom::get_next_modified();
220 clear_cache_stage(current_thread);
221 nassertv(all_is_valid);
222}
223
224/**
225 * Converts the geom from indexed to nonindexed by duplicating vertices as
226 * necessary. If composite_only is true, then only composite primitives such
227 * as trifans and tristrips are converted. Returns the number of
228 * GeomPrimitive objects converted.
229 *
230 * Don't call this in a downstream thread unless you don't mind it blowing
231 * away other changes you might have recently made in an upstream thread.
232 */
234make_nonindexed(bool composite_only) {
235 Thread *current_thread = Thread::get_current_thread();
236 int num_changed = 0;
237
238 CDWriter cdata(_cycler, true, current_thread);
239 CPT(GeomVertexData) orig_data = cdata->_data.get_read_pointer(current_thread);
240 PT(GeomVertexData) new_data = new GeomVertexData(*orig_data);
241 new_data->clear_rows();
242
243#ifndef NDEBUG
244 bool all_is_valid = true;
245#endif
246 Primitives::iterator pi;
247 Primitives new_prims;
248 new_prims.reserve(cdata->_primitives.size());
249 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
250 PT(GeomPrimitive) primitive = (*pi).get_read_pointer(current_thread)->make_copy();
251 new_prims.push_back(primitive.p());
252
253 // GeomPoints are considered "composite" for the purposes of making
254 // nonindexed, since there's no particular advantage to having indexed
255 // points (as opposed to, say, indexed triangles or indexed lines).
256 if (primitive->is_indexed() &&
257 (primitive->is_composite() ||
258 primitive->is_exact_type(GeomPoints::get_class_type()) ||
259 !composite_only)) {
260 primitive->make_nonindexed(new_data, orig_data);
261 ++num_changed;
262 } else {
263 // If it's a simple primitive, pack it anyway, so it can share the same
264 // GeomVertexData.
265 primitive->pack_vertices(new_data, orig_data);
266 }
267
268#ifndef NDEBUG
269 if (!primitive->check_valid(new_data)) {
270 all_is_valid = false;
271 }
272#endif
273 }
274
275 nassertr(all_is_valid, 0);
276
277 if (num_changed != 0) {
278 // If any at all were changed, then keep the result (otherwise, discard
279 // it, since we might have de-optimized the indexed geometry a bit).
280 cdata->_data = new_data;
281 cdata->_primitives.swap(new_prims);
282 cdata->_modified = Geom::get_next_modified();
283 clear_cache_stage(current_thread);
284 }
285
286 return num_changed;
287}
288
289/**
290 * Returns a GeomVertexData that represents the results of computing the
291 * vertex animation on the CPU for this Geom's vertex data.
292 *
293 * If there is no CPU-defined vertex animation on this object, this just
294 * returns the original object.
295 *
296 * If there is vertex animation, but the VertexTransform values have not
297 * changed since last time, this may return the same pointer it returned
298 * previously. Even if the VertexTransform values have changed, it may still
299 * return the same pointer, but with its contents modified (this is preferred,
300 * since it allows the graphics backend to update vertex buffers optimally).
301 *
302 * If force is false, this method may return immediately with stale data, if
303 * the vertex data is not completely resident. If force is true, this method
304 * will never return stale data, but may block until the data is available.
305 */
307get_animated_vertex_data(bool force, Thread *current_thread) const {
308 return get_vertex_data()->animate_vertices(force, current_thread);
309}
310
311/**
312 * Replaces the ith GeomPrimitive object stored within the Geom with the new
313 * object.
314 *
315 * Don't call this in a downstream thread unless you don't mind it blowing
316 * away other changes you might have recently made in an upstream thread.
317 */
318void Geom::
319set_primitive(size_t i, const GeomPrimitive *primitive) {
320 Thread *current_thread = Thread::get_current_thread();
321 CDWriter cdata(_cycler, true, current_thread);
322 nassertv(i < cdata->_primitives.size());
323 nassertv(primitive->check_valid(cdata->_data.get_read_pointer(current_thread)));
324
325 // All primitives within a particular Geom must have the same fundamental
326 // primitive type (triangles, points, or lines).
327 nassertv(cdata->_primitive_type == PT_none ||
328 cdata->_primitive_type == primitive->get_primitive_type());
329
330 // They also should have a compatible shade model.
331 CPT(GeomPrimitive) compat = primitive->match_shade_model(cdata->_shade_model);
332 nassertv_always(compat != nullptr);
333
334 cdata->_primitives[i] = (GeomPrimitive *)compat.p();
335 PrimitiveType new_primitive_type = compat->get_primitive_type();
336 if (new_primitive_type != cdata->_primitive_type) {
337 cdata->_primitive_type = new_primitive_type;
338 }
339 ShadeModel new_shade_model = compat->get_shade_model();
340 if (new_shade_model != cdata->_shade_model &&
341 new_shade_model != SM_uniform) {
342 cdata->_shade_model = new_shade_model;
343 }
344
345 reset_geom_rendering(cdata);
346 cdata->_modified = Geom::get_next_modified();
347 clear_cache_stage(current_thread);
348 mark_internal_bounds_stale(cdata);
349}
350
351/**
352 * Inserts a new GeomPrimitive structure to the Geom object. This specifies a
353 * particular subset of vertices that are used to define geometric primitives
354 * of the indicated type.
355 *
356 * Don't call this in a downstream thread unless you don't mind it blowing
357 * away other changes you might have recently made in an upstream thread.
358 */
359void Geom::
360insert_primitive(size_t i, const GeomPrimitive *primitive) {
361 Thread *current_thread = Thread::get_current_thread();
362 CDWriter cdata(_cycler, true, current_thread);
363
364 nassertv(primitive->check_valid(cdata->_data.get_read_pointer(current_thread)));
365
366 // All primitives within a particular Geom must have the same fundamental
367 // primitive type (triangles, points, or lines).
368 nassertv(cdata->_primitive_type == PT_none ||
369 cdata->_primitive_type == primitive->get_primitive_type());
370
371 // They also should have a compatible shade model.
372 CPT(GeomPrimitive) compat = primitive->match_shade_model(cdata->_shade_model);
373 nassertv_always(compat != nullptr);
374
375 if (i >= cdata->_primitives.size()) {
376 cdata->_primitives.push_back((GeomPrimitive *)compat.p());
377 } else {
378 cdata->_primitives.insert(cdata->_primitives.begin() + i, (GeomPrimitive *)compat.p());
379 }
380 PrimitiveType new_primitive_type = compat->get_primitive_type();
381 if (new_primitive_type != cdata->_primitive_type) {
382 cdata->_primitive_type = new_primitive_type;
383 }
384 ShadeModel new_shade_model = compat->get_shade_model();
385 if (new_shade_model != cdata->_shade_model &&
386 new_shade_model != SM_uniform) {
387 cdata->_shade_model = new_shade_model;
388 }
389
390 reset_geom_rendering(cdata);
391 cdata->_modified = Geom::get_next_modified();
392 clear_cache_stage(current_thread);
393 mark_internal_bounds_stale(cdata);
394}
395
396/**
397 * Removes the ith primitive from the list.
398 *
399 * Don't call this in a downstream thread unless you don't mind it blowing
400 * away other changes you might have recently made in an upstream thread.
401 */
402void Geom::
403remove_primitive(size_t i) {
404 Thread *current_thread = Thread::get_current_thread();
405 CDWriter cdata(_cycler, true, current_thread);
406 nassertv(i < cdata->_primitives.size());
407 cdata->_primitives.erase(cdata->_primitives.begin() + i);
408 if (cdata->_primitives.empty()) {
409 cdata->_primitive_type = PT_none;
410 cdata->_shade_model = SM_uniform;
411 }
412 reset_geom_rendering(cdata);
413 cdata->_modified = Geom::get_next_modified();
414 clear_cache_stage(current_thread);
415 mark_internal_bounds_stale(cdata);
416}
417
418/**
419 * Removes all the primitives from the Geom object (but keeps the same table
420 * of vertices). You may then re-add primitives one at a time via calls to
421 * add_primitive().
422 *
423 * Don't call this in a downstream thread unless you don't mind it blowing
424 * away other changes you might have recently made in an upstream thread.
425 */
428 Thread *current_thread = Thread::get_current_thread();
429 CDWriter cdata(_cycler, true, current_thread);
430 cdata->_primitives.clear();
431 cdata->_primitive_type = PT_none;
432 cdata->_shade_model = SM_uniform;
433 reset_geom_rendering(cdata);
434 clear_cache_stage(current_thread);
435 mark_internal_bounds_stale(cdata);
436}
437
438/**
439 * Decomposes all of the primitives within this Geom, leaving the results in
440 * place. See GeomPrimitive::decompose().
441 *
442 * Don't call this in a downstream thread unless you don't mind it blowing
443 * away other changes you might have recently made in an upstream thread.
444 */
447 Thread *current_thread = Thread::get_current_thread();
448 CDWriter cdata(_cycler, true, current_thread);
449
450#ifndef NDEBUG
451 GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
452 data_reader.check_array_readers();
453
454 bool all_is_valid = true;
455#endif
456 Primitives::iterator pi;
457 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
458 CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->decompose();
459 (*pi) = (GeomPrimitive *)new_prim.p();
460
461#ifndef NDEBUG
462 if (!new_prim->check_valid(&data_reader)) {
463 all_is_valid = false;
464 }
465#endif
466 }
467
468 cdata->_modified = Geom::get_next_modified();
469 reset_geom_rendering(cdata);
470 clear_cache_stage(current_thread);
471
472 nassertv(all_is_valid);
473}
474
475/**
476 * Doublesides all of the primitives within this Geom, leaving the results in
477 * place. See GeomPrimitive::doubleside().
478 *
479 * Don't call this in a downstream thread unless you don't mind it blowing
480 * away other changes you might have recently made in an upstream thread.
481 */
484 Thread *current_thread = Thread::get_current_thread();
485 CDWriter cdata(_cycler, true, current_thread);
486
487#ifndef NDEBUG
488 GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
489 data_reader.check_array_readers();
490
491 bool all_is_valid = true;
492#endif
493 Primitives::iterator pi;
494 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
495 CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->doubleside();
496 (*pi) = (GeomPrimitive *)new_prim.p();
497
498#ifndef NDEBUG
499 if (!new_prim->check_valid(&data_reader)) {
500 all_is_valid = false;
501 }
502#endif
503 }
504
505 cdata->_modified = Geom::get_next_modified();
506 reset_geom_rendering(cdata);
507 clear_cache_stage(current_thread);
508
509 nassertv(all_is_valid);
510}
511
512/**
513 * Reverses all of the primitives within this Geom, leaving the results in
514 * place. See GeomPrimitive::reverse().
515 *
516 * Don't call this in a downstream thread unless you don't mind it blowing
517 * away other changes you might have recently made in an upstream thread.
518 */
521 Thread *current_thread = Thread::get_current_thread();
522 CDWriter cdata(_cycler, true, current_thread);
523
524#ifndef NDEBUG
525 GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
526 data_reader.check_array_readers();
527
528 bool all_is_valid = true;
529#endif
530 Primitives::iterator pi;
531 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
532 CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->reverse();
533 (*pi) = (GeomPrimitive *)new_prim.p();
534
535#ifndef NDEBUG
536 if (!new_prim->check_valid(&data_reader)) {
537 all_is_valid = false;
538 }
539#endif
540 }
541
542 cdata->_modified = Geom::get_next_modified();
543 reset_geom_rendering(cdata);
544 clear_cache_stage(current_thread);
545
546 nassertv(all_is_valid);
547}
548
549/**
550 * Rotates all of the primitives within this Geom, leaving the results in
551 * place. See GeomPrimitive::rotate().
552 *
553 * Don't call this in a downstream thread unless you don't mind it blowing
554 * away other changes you might have recently made in an upstream thread.
555 */
558 Thread *current_thread = Thread::get_current_thread();
559 CDWriter cdata(_cycler, true, current_thread);
560
561#ifndef NDEBUG
562 GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
563 data_reader.check_array_readers();
564
565 bool all_is_valid = true;
566#endif
567 Primitives::iterator pi;
568 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
569 CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->rotate();
570 (*pi) = (GeomPrimitive *)new_prim.p();
571
572#ifndef NDEBUG
573 if (!new_prim->check_valid(&data_reader)) {
574 all_is_valid = false;
575 }
576#endif
577 }
578
579 switch (cdata->_shade_model) {
580 case SM_flat_first_vertex:
581 cdata->_shade_model = SM_flat_last_vertex;
582 break;
583
584 case SM_flat_last_vertex:
585 cdata->_shade_model = SM_flat_first_vertex;
586 break;
587
588 default:
589 break;
590 }
591
592 cdata->_modified = Geom::get_next_modified();
593 clear_cache_stage(current_thread);
594
595 nassertv(all_is_valid);
596}
597
598/**
599 * Unifies all of the primitives contained within this Geom into a single (or
600 * as few as possible, within the constraints of max_indices) primitive
601 * objects. This may require decomposing the primitives if, for instance, the
602 * Geom contains both triangle strips and triangle fans.
603 *
604 * max_indices represents the maximum number of indices that will be put in
605 * any one GeomPrimitive. If preserve_order is true, then the primitives will
606 * not be reordered during the operation, even if this results in a suboptimal
607 * result.
608 *
609 * Don't call this in a downstream thread unless you don't mind it blowing
610 * away other changes you might have recently made in an upstream thread.
611 */
613unify_in_place(int max_indices, bool preserve_order) {
614 if (gobj_cat.is_debug()) {
615 gobj_cat.debug()
616 << "unify_in_place(" << max_indices << ", " << preserve_order
617 << "): " << *this << "\n";
618 }
619
620 Thread *current_thread = Thread::get_current_thread();
621 if (get_num_primitives() <= 1) {
622 // If we don't have more than one primitive to start with, no need to do
623 // anything.
624 return;
625 }
626
627 CDWriter cdata(_cycler, true, current_thread);
628
629 typedef pmap<TypeHandle, PT(GeomPrimitive) > NewPrims;
630
631 NewPrims new_prims;
632
633 bool keep_different_types = preserve_triangle_strips && !preserve_order;
634
635 Primitives::const_iterator pi;
636 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
637 CPT(GeomPrimitive) primitive = (*pi).get_read_pointer(current_thread);
638 NewPrims::iterator npi = new_prims.find(primitive->get_type());
639 if (npi == new_prims.end()) {
640 // This is the first primitive of this type.
641 if (!keep_different_types && !new_prims.empty()) {
642 // Actually, since we aren't trying to keep the different types of
643 // primitives, we should try to combine this type and the other type
644 // by decomposing them both (into triangles, segments, or whatever).
645
646 // First, decompose the incoming one.
647 primitive = primitive->decompose();
648 npi = new_prims.find(primitive->get_type());
649 if (npi == new_prims.end()) {
650 // That didn't help, so decompose the one already in the table.
651 nassertv(new_prims.size() == 1);
652 npi = new_prims.begin();
653 CPT(GeomPrimitive) np = (*npi).second->decompose();
654 new_prims.clear();
655 new_prims.insert(NewPrims::value_type(np->get_type(), np->make_copy()));
656 npi = new_prims.find(primitive->get_type());
657 }
658 }
659 }
660
661 if (npi == new_prims.end()) {
662 // This is the first primitive of this type. Just store it.
663 new_prims.insert(NewPrims::value_type(primitive->get_type(), primitive->make_copy()));
664
665 } else {
666 // We have already encountered another primitive of this type. Combine
667 // them.
668 combine_primitives((*npi).second, std::move(primitive), current_thread);
669 }
670 }
671
672 // Now, we have one or more primitives, but only one of each type.
673#ifndef NDEBUG
674 if (!keep_different_types && new_prims.size() > 1) {
675 // This shouldn't be possible, because we decompose as we go, in the loop
676 // above. (We have to decompose as we go to preserve the ordering of the
677 // primitives.)
678 nassertv(false);
679 }
680
681 GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
682 data_reader.check_array_readers();
683#endif
684
685 // Finally, iterate through the remaining primitives, and copy them to the
686 // output list.
687 cdata->_primitives.clear();
688 NewPrims::iterator npi;
689 for (npi = new_prims.begin(); npi != new_prims.end(); ++npi) {
690 GeomPrimitive *prim = (*npi).second;
691
692 nassertv(prim->check_valid(&data_reader));
693
694 // Each new primitive, naturally, inherits the Geom's overall shade model.
695 prim->set_shade_model(cdata->_shade_model);
696
697 // Should we split it up again to satisfy max_indices?
698 if (prim->get_num_vertices() > max_indices) {
699 // Copy prim into smaller prims, no one of which has more than
700 // max_indices vertices.
701 GeomPrimitivePipelineReader reader(prim, current_thread);
702
703 // Copy prim into smaller prims, no one of which has more than
704 // max_indices vertices.
705 int i = 0;
706 int num_primitives = reader.get_num_primitives();
707 int num_vertices_per_primitive = prim->get_num_vertices_per_primitive();
708 int num_unused_vertices_per_primitive = prim->get_num_unused_vertices_per_primitive();
709 if (num_vertices_per_primitive != 0) {
710 // This is a simple primitive type like a triangle, where all the
711 // primitives share the same number of vertices.
712 int total_vertices_per_primitive = num_vertices_per_primitive + num_unused_vertices_per_primitive;
713 int max_primitives = max_indices / total_vertices_per_primitive;
714 const unsigned char *ptr = reader.get_read_pointer(true);
715 size_t stride = reader.get_index_stride();
716
717 while (i < num_primitives) {
718 PT(GeomPrimitive) smaller = prim->make_copy();
719 smaller->clear_vertices();
720
721 // Since the number of vertices is consistent, we can calculate how
722 // many primitives will fit, and copy them all in one go.
723 int copy_primitives = min((num_primitives - i), max_primitives);
724 int num_vertices = copy_primitives * total_vertices_per_primitive;
725 nassertv(num_vertices > 0);
726 {
727 smaller->set_index_type(reader.get_index_type());
728 GeomVertexArrayDataHandle writer(smaller->modify_vertices(), current_thread);
729 writer.unclean_set_num_rows(num_vertices);
730 memcpy(writer.get_write_pointer(), ptr, stride * (size_t)(num_vertices - num_unused_vertices_per_primitive));
731 }
732
733 cdata->_primitives.push_back(smaller.p());
734
735 ptr += stride * (size_t)num_vertices;
736 i += copy_primitives;
737 }
738 } else {
739 // This is a complex primitive type like a triangle strip.
740 CPTA_int ends = reader.get_ends();
741 int start = 0;
742 int end = ends[0];
743
744 while (i < num_primitives) {
745 PT(GeomPrimitive) smaller = prim->make_copy();
746 smaller->clear_vertices();
747
748 while (smaller->get_num_vertices() + (end - start) < max_indices) {
749 for (int n = start; n < end; ++n) {
750 smaller->add_vertex(reader.get_vertex(n));
751 }
752 smaller->close_primitive();
753
754 ++i;
755 if (i >= num_primitives) {
756 break;
757 }
758
759 start = end + num_unused_vertices_per_primitive;
760 end = ends[i];
761 }
762
763 cdata->_primitives.push_back(smaller.p());
764 }
765 }
766 } else {
767 // The prim has few enough vertices; keep it.
768 cdata->_primitives.push_back(prim);
769 }
770 }
771
772 cdata->_modified = Geom::get_next_modified();
773 clear_cache_stage(current_thread);
774 reset_geom_rendering(cdata);
775}
776
777/**
778 * Replaces the GeomPrimitives within this Geom with corresponding GeomLines,
779 * representing a wireframe of the primitives. See
780 * GeomPrimitive::make_lines().
781 *
782 * Don't call this in a downstream thread unless you don't mind it blowing
783 * away other changes you might have recently made in an upstream thread.
784 */
787 Thread *current_thread = Thread::get_current_thread();
788 CDWriter cdata(_cycler, true, current_thread);
789
790#ifndef NDEBUG
791 GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
792 data_reader.check_array_readers();
793
794 bool all_is_valid = true;
795#endif
796 Primitives::iterator pi;
797 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
798 CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_lines();
799 (*pi) = (GeomPrimitive *)new_prim.p();
800
801#ifndef NDEBUG
802 if (!new_prim->check_valid(&data_reader)) {
803 all_is_valid = false;
804 }
805#endif
806 }
807
808 if (cdata->_primitive_type == PT_polygons ||
809 cdata->_primitive_type == PT_patches) {
810 cdata->_primitive_type = PT_lines;
811 }
812
813 cdata->_modified = Geom::get_next_modified();
814 reset_geom_rendering(cdata);
815 clear_cache_stage(current_thread);
816
817 nassertv(all_is_valid);
818}
819
820/**
821 * Replaces the GeomPrimitives within this Geom with corresponding GeomPoints.
822 * See GeomPrimitive::make_points().
823 *
824 * Don't call this in a downstream thread unless you don't mind it blowing
825 * away other changes you might have recently made in an upstream thread.
826 */
829 Thread *current_thread = Thread::get_current_thread();
830 CDWriter cdata(_cycler, true, current_thread);
831
832#ifndef NDEBUG
833 GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
834 data_reader.check_array_readers();
835
836 bool all_is_valid = true;
837#endif
838 Primitives::iterator pi;
839 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
840 CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_points();
841 (*pi) = (GeomPrimitive *)new_prim.p();
842
843#ifndef NDEBUG
844 if (!new_prim->check_valid(&data_reader)) {
845 all_is_valid = false;
846 }
847#endif
848 }
849
850 if (cdata->_primitive_type != PT_none) {
851 cdata->_primitive_type = PT_points;
852 }
853
854 cdata->_modified = Geom::get_next_modified();
855 reset_geom_rendering(cdata);
856 clear_cache_stage(current_thread);
857
858 nassertv(all_is_valid);
859}
860
861/**
862 * Replaces the GeomPrimitives within this Geom with corresponding
863 * GeomPatches. See GeomPrimitive::make_patches().
864 *
865 * Don't call this in a downstream thread unless you don't mind it blowing
866 * away other changes you might have recently made in an upstream thread.
867 */
870 Thread *current_thread = Thread::get_current_thread();
871 CDWriter cdata(_cycler, true, current_thread);
872
873#ifndef NDEBUG
874 GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
875 data_reader.check_array_readers();
876
877 bool all_is_valid = true;
878#endif
879 Primitives::iterator pi;
880 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
881 CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_patches();
882 (*pi) = (GeomPrimitive *)new_prim.p();
883
884#ifndef NDEBUG
885 if (!new_prim->check_valid(&data_reader)) {
886 all_is_valid = false;
887 }
888#endif
889 }
890
891 if (cdata->_primitive_type != PT_none) {
892 cdata->_primitive_type = PT_patches;
893 }
894
895 cdata->_modified = Geom::get_next_modified();
896 reset_geom_rendering(cdata);
897 clear_cache_stage(current_thread);
898
899 nassertv(all_is_valid);
900}
901
902/**
903 * Replaces the GeomPrimitives within this Geom with corresponding versions
904 * with adjacency information. See GeomPrimitive::make_adjacency().
905 *
906 * Don't call this in a downstream thread unless you don't mind it blowing
907 * away other changes you might have recently made in an upstream thread.
908 *
909 * @since 1.10.0
910 */
913 Thread *current_thread = Thread::get_current_thread();
914 CDWriter cdata(_cycler, true, current_thread);
915
916#ifndef NDEBUG
917 GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
918 data_reader.check_array_readers();
919
920 bool all_is_valid = true;
921#endif
922 Primitives::iterator pi;
923 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
924 CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_adjacency();
925 if (new_prim != nullptr) {
926 (*pi) = (GeomPrimitive *)new_prim.p();
927
928#ifndef NDEBUG
929 if (!new_prim->check_valid(&data_reader)) {
930 all_is_valid = false;
931 }
932#endif
933 }
934 }
935
936 cdata->_modified = Geom::get_next_modified();
937 reset_geom_rendering(cdata);
938 clear_cache_stage(current_thread);
939
940 nassertv(all_is_valid);
941}
942
943/**
944 * Copies the primitives from the indicated Geom into this one. This does
945 * require that both Geoms contain the same fundamental type primitives, both
946 * have a compatible shade model, and both use the same GeomVertexData. Both
947 * Geoms must also be the same specific class type (i.e. if one is a
948 * GeomTextGlyph, they both must be.)
949 *
950 * Returns true if the copy is successful, or false otherwise (because the
951 * Geoms were mismatched).
952 */
954copy_primitives_from(const Geom *other) {
955 if (get_primitive_type() != PT_none &&
957 return false;
958 }
959 if (get_vertex_data() != other->get_vertex_data()) {
960 return false;
961 }
962 if (get_type() != other->get_type()) {
963 return false;
964 }
965
966 ShadeModel this_shade_model = get_shade_model();
967 ShadeModel other_shade_model = other->get_shade_model();
968 if (this_shade_model != SM_uniform && other_shade_model != SM_uniform &&
969 this_shade_model != other_shade_model) {
970 if ((this_shade_model == SM_flat_first_vertex && other_shade_model == SM_flat_last_vertex) ||
971 (this_shade_model == SM_flat_last_vertex && other_shade_model == SM_flat_first_vertex)) {
972 // This is acceptable; we can rotate the primitives to match.
973
974 } else {
975 // Otherwise, we have incompatible shade models.
976 return false;
977 }
978 }
979
980 int num_primitives = other->get_num_primitives();
981 for (int i = 0; i < num_primitives; i++) {
982 add_primitive(other->get_primitive(i));
983 }
984
985 return true;
986}
987
988/**
989 * Returns the number of bytes consumed by the geom and its primitives (but
990 * not including its vertex table).
991 */
992int Geom::
993get_num_bytes() const {
994 CDReader cdata(_cycler);
995
996 int num_bytes = sizeof(Geom);
997 Primitives::const_iterator pi;
998 for (pi = cdata->_primitives.begin();
999 pi != cdata->_primitives.end();
1000 ++pi) {
1001 num_bytes += (*pi).get_read_pointer()->get_num_bytes();
1002 }
1003
1004 return num_bytes;
1005}
1006
1007/**
1008 * Returns true if all the primitive arrays are currently resident in memory.
1009 * If this returns false, the data will be brought back into memory shortly;
1010 * try again later.
1011 *
1012 * This does not also test the Geom's associated GeomVertexData. That must be
1013 * tested separately.
1014 */
1016request_resident() const {
1017 Thread *current_thread = Thread::get_current_thread();
1018
1019 CDReader cdata(_cycler, current_thread);
1020
1021 bool resident = true;
1022
1023 Primitives::const_iterator pi;
1024 for (pi = cdata->_primitives.begin();
1025 pi != cdata->_primitives.end();
1026 ++pi) {
1027 if (!(*pi).get_read_pointer(current_thread)->request_resident()) {
1028 resident = false;
1029 }
1030 }
1031
1032 return resident;
1033}
1034
1035/**
1036 * Applies the indicated transform to all of the vertices in the Geom. If the
1037 * Geom happens to share a vertex table with another Geom, this operation will
1038 * duplicate the vertex table instead of breaking the other Geom; however, if
1039 * multiple Geoms with shared tables are transformed by the same matrix, they
1040 * will no longer share tables after the operation. Consider using the
1041 * GeomTransformer if you will be applying the same transform to multiple
1042 * Geoms.
1043 */
1045transform_vertices(const LMatrix4 &mat) {
1046 PT(GeomVertexData) new_data = modify_vertex_data();
1047 CPT(GeomVertexFormat) format = new_data->get_format();
1048
1049 size_t ci;
1050 for (ci = 0; ci < format->get_num_points(); ci++) {
1051 GeomVertexRewriter data(new_data, format->get_point(ci));
1052
1053 while (!data.is_at_end()) {
1054 const LPoint3 &point = data.get_data3();
1055 data.set_data3(point * mat);
1056 }
1057 }
1058 for (ci = 0; ci < format->get_num_vectors(); ci++) {
1059 GeomVertexRewriter data(new_data, format->get_vector(ci));
1060
1061 while (!data.is_at_end()) {
1062 const LVector3 &vector = data.get_data3();
1063 data.set_data3(normalize(vector * mat));
1064 }
1065 }
1066}
1067
1068/**
1069 * Verifies that the all of the primitives within the geom reference vertices
1070 * that actually exist within the geom's GeomVertexData. Returns true if the
1071 * geom appears to be valid, false otherwise.
1072 */
1074check_valid() const {
1075 Thread *current_thread = Thread::get_current_thread();
1076 GeomPipelineReader geom_reader(this, current_thread);
1077 CPT(GeomVertexData) vertex_data = geom_reader.get_vertex_data();
1078 GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1079 data_reader.check_array_readers();
1080 return geom_reader.check_valid(&data_reader);
1081}
1082
1083/**
1084 * Verifies that the all of the primitives within the geom reference vertices
1085 * that actually exist within the indicated GeomVertexData. Returns true if
1086 * the geom appears to be valid, false otherwise.
1087 */
1089check_valid(const GeomVertexData *vertex_data) const {
1090 Thread *current_thread = Thread::get_current_thread();
1091 GeomPipelineReader geom_reader(this, current_thread);
1092 GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1093 data_reader.check_array_readers();
1094 return geom_reader.check_valid(&data_reader);
1095}
1096
1097/**
1098 * Returns the bounding volume for the Geom.
1099 */
1101get_bounds(Thread *current_thread) const {
1102 CDLockedReader cdata(_cycler, current_thread);
1103 if (cdata->_user_bounds != nullptr) {
1104 return cdata->_user_bounds;
1105 }
1106
1107 if (cdata->_internal_bounds_stale) {
1108 CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
1109 compute_internal_bounds(cdataw, current_thread);
1110 return cdataw->_internal_bounds;
1111 }
1112 return cdata->_internal_bounds;
1113}
1114
1115/**
1116 * Returns the number of vertices rendered by all primitives within the Geom.
1117 */
1118int Geom::
1119get_nested_vertices(Thread *current_thread) const {
1120 CDLockedReader cdata(_cycler, current_thread);
1121 if (cdata->_internal_bounds_stale) {
1122 CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
1123 compute_internal_bounds(cdataw, current_thread);
1124 return cdataw->_nested_vertices;
1125 }
1126 return cdata->_nested_vertices;
1127}
1128
1129/**
1130 *
1131 */
1132void Geom::
1133output(std::ostream &out) const {
1134 CDReader cdata(_cycler);
1135
1136 // Get a list of the primitive types contained within this object.
1137 int num_faces = 0;
1138 pset<TypeHandle> types;
1139 Primitives::const_iterator pi;
1140 for (pi = cdata->_primitives.begin();
1141 pi != cdata->_primitives.end();
1142 ++pi) {
1143 CPT(GeomPrimitive) prim = (*pi).get_read_pointer();
1144 num_faces += prim->get_num_faces();
1145 types.insert(prim->get_type());
1146 }
1147
1148 out << get_type() << " [";
1150 for (ti = types.begin(); ti != types.end(); ++ti) {
1151 out << " " << (*ti);
1152 }
1153 out << " ], " << num_faces << " faces";
1154}
1155
1156/**
1157 *
1158 */
1159void Geom::
1160write(std::ostream &out, int indent_level) const {
1161 CDReader cdata(_cycler);
1162
1163 // Get a list of the primitive types contained within this object.
1164 Primitives::const_iterator pi;
1165 for (pi = cdata->_primitives.begin();
1166 pi != cdata->_primitives.end();
1167 ++pi) {
1168 (*pi).get_read_pointer()->write(out, indent_level);
1169 }
1170}
1171
1172/**
1173 * Removes all of the previously-cached results of munge_geom().
1174 *
1175 * This blows away the entire cache, upstream and downstream the pipeline.
1176 * Use clear_cache_stage() instead if you only want to blow away the cache at
1177 * the current stage and upstream.
1178 */
1179void Geom::
1180clear_cache() {
1181 LightMutexHolder holder(_cache_lock);
1182 for (Cache::iterator ci = _cache.begin();
1183 ci != _cache.end();
1184 ++ci) {
1185 CacheEntry *entry = (*ci).second;
1186 entry->erase();
1187 }
1188 _cache.clear();
1189}
1190
1191/**
1192 * Removes all of the previously-cached results of munge_geom(), at the
1193 * current pipeline stage and upstream. Does not affect the downstream cache.
1194 *
1195 * Don't call this in a downstream thread unless you don't mind it blowing
1196 * away other changes you might have recently made in an upstream thread.
1197 */
1199clear_cache_stage(Thread *current_thread) {
1200 LightMutexHolder holder(_cache_lock);
1201 for (Cache::iterator ci = _cache.begin();
1202 ci != _cache.end();
1203 ++ci) {
1204 CacheEntry *entry = (*ci).second;
1205 CDCacheWriter cdata(entry->_cycler, current_thread);
1206 cdata->set_result(nullptr, nullptr);
1207 }
1208}
1209
1210/**
1211 * Indicates that the geom should be enqueued to be prepared in the indicated
1212 * prepared_objects at the beginning of the next frame. This will ensure the
1213 * geom is already loaded into geom memory if it is expected to be rendered
1214 * soon.
1215 *
1216 * Use this function instead of prepare_now() to preload geoms from a user
1217 * interface standpoint.
1218 */
1220prepare(PreparedGraphicsObjects *prepared_objects) {
1221 prepared_objects->enqueue_geom(this);
1222}
1223
1224/**
1225 * Returns true if the geom has already been prepared or enqueued for
1226 * preparation on the indicated GSG, false otherwise.
1227 */
1229is_prepared(PreparedGraphicsObjects *prepared_objects) const {
1230 Contexts::const_iterator ci;
1231 ci = _contexts.find(prepared_objects);
1232 if (ci != _contexts.end()) {
1233 return true;
1234 }
1235 return prepared_objects->is_geom_queued(this);
1236}
1237
1238/**
1239 * Frees the geom context only on the indicated object, if it exists there.
1240 * Returns true if it was released, false if it had not been prepared.
1241 */
1243release(PreparedGraphicsObjects *prepared_objects) {
1244 Contexts::iterator ci;
1245 ci = _contexts.find(prepared_objects);
1246 if (ci != _contexts.end()) {
1247 GeomContext *gc = (*ci).second;
1248 prepared_objects->release_geom(gc);
1249 return true;
1250 }
1251
1252 // Maybe it wasn't prepared yet, but it's about to be.
1253 return prepared_objects->dequeue_geom(this);
1254}
1255
1256/**
1257 * Frees the context allocated on all objects for which the geom has been
1258 * declared. Returns the number of contexts which have been freed.
1259 */
1261release_all() {
1262 // We have to traverse a copy of the _contexts list, because the
1263 // PreparedGraphicsObjects object will call clear_prepared() in response to
1264 // each release_geom(), and we don't want to be modifying the _contexts list
1265 // while we're traversing it.
1266 Contexts temp = _contexts;
1267 int num_freed = (int)_contexts.size();
1268
1269 Contexts::const_iterator ci;
1270 for (ci = temp.begin(); ci != temp.end(); ++ci) {
1271 PreparedGraphicsObjects *prepared_objects = (*ci).first;
1272 GeomContext *gc = (*ci).second;
1273 prepared_objects->release_geom(gc);
1274 }
1275
1276 // Now that we've called release_geom() on every known context, the
1277 // _contexts list should have completely emptied itself.
1278 nassertr(_contexts.empty(), num_freed);
1279
1280 return num_freed;
1281}
1282
1283/**
1284 * Creates a context for the geom on the particular GSG, if it does not
1285 * already exist. Returns the new (or old) GeomContext. This assumes that
1286 * the GraphicsStateGuardian is the currently active rendering context and
1287 * that it is ready to accept new geoms. If this is not necessarily the case,
1288 * you should use prepare() instead.
1289 *
1290 * Normally, this is not called directly except by the GraphicsStateGuardian;
1291 * a geom does not need to be explicitly prepared by the user before it may be
1292 * rendered.
1293 */
1295prepare_now(PreparedGraphicsObjects *prepared_objects,
1297 Contexts::const_iterator ci;
1298 ci = _contexts.find(prepared_objects);
1299 if (ci != _contexts.end()) {
1300 return (*ci).second;
1301 }
1302
1303 GeomContext *gc = prepared_objects->prepare_geom_now(this, gsg);
1304 if (gc != nullptr) {
1305 _contexts[prepared_objects] = gc;
1306 }
1307 return gc;
1308}
1309
1310/**
1311 * Actually draws the Geom with the indicated GSG, using the indicated vertex
1312 * data (which might have been pre-munged to support the GSG's needs).
1313 *
1314 * Returns true if all of the primitives were drawn normally, false if there
1315 * was a problem (for instance, some of the data was nonresident). If force
1316 * is passed true, it will wait for the data to become resident if necessary.
1317 */
1319draw(GraphicsStateGuardianBase *gsg, const GeomVertexData *vertex_data,
1320 bool force, Thread *current_thread) const {
1321 GeomPipelineReader geom_reader(this, current_thread);
1322 GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1323 data_reader.check_array_readers();
1324
1325 return geom_reader.draw(gsg, &data_reader, force);
1326}
1327
1328/**
1329 * Returns a monotonically increasing sequence. Each time this is called, a
1330 * new sequence number is returned, higher than the previous value.
1331 *
1332 * This is used to ensure that GeomVertexArrayData::get_modified() and
1333 * GeomPrimitive::get_modified() update from the same space, so that
1334 * Geom::get_modified() returns a meaningful value.
1335 */
1338 ++_next_modified;
1339 return _next_modified;
1340}
1341
1342/**
1343 * Recomputes the dynamic bounding volume for this Geom. This includes all of
1344 * the vertices.
1345 */
1346void Geom::
1347compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
1348 int num_vertices = 0;
1349
1350 // Get the vertex data, after animation.
1351 CPT(GeomVertexData) vertex_data = get_animated_vertex_data(true, current_thread);
1352
1353 // Now actually compute the bounding volume. We do this by using
1354 // calc_tight_bounds to determine our box first.
1355 LPoint3 pmin, pmax;
1356 PN_stdfloat sq_center_dist = 0.0f;
1357 bool found_any = false;
1358 do_calc_tight_bounds(pmin, pmax, sq_center_dist, found_any,
1359 vertex_data, false, LMatrix4::ident_mat(),
1360 InternalName::get_vertex(),
1361 cdata, current_thread);
1362
1363 BoundingVolume::BoundsType btype = cdata->_bounds_type;
1364 if (btype == BoundingVolume::BT_default) {
1365 btype = bounds_type;
1366 }
1367
1368 if (found_any) {
1369 nassertv(!pmin.is_nan());
1370 nassertv(!pmax.is_nan());
1371
1372 // Then we put the bounding volume around both of those points.
1373 PN_stdfloat avg_box_area;
1374 switch (btype) {
1375 case BoundingVolume::BT_best:
1376 case BoundingVolume::BT_fastest:
1377 case BoundingVolume::BT_default:
1378 {
1379 // When considering a box, calculate (roughly) the average area of the
1380 // sides. We will use this to determine whether a sphere or box is a
1381 // better fit.
1382 PN_stdfloat min_extent = min(pmax[0] - pmin[0],
1383 min(pmax[1] - pmin[1],
1384 pmax[2] - pmin[2]));
1385 PN_stdfloat max_extent = max(pmax[0] - pmin[0],
1386 max(pmax[1] - pmin[1],
1387 pmax[2] - pmin[2]));
1388 avg_box_area = ((min_extent * min_extent) + (max_extent * max_extent)) / 2;
1389 }
1390 // Fall through
1391 case BoundingVolume::BT_sphere:
1392 {
1393 // Determine the best radius for a bounding sphere.
1394 LPoint3 aabb_center = (pmin + pmax) * 0.5f;
1395 PN_stdfloat best_sq_radius = (pmax - aabb_center).length_squared();
1396
1397 if (btype != BoundingVolume::BT_fastest && best_sq_radius > 0.0f &&
1398 aabb_center.length_squared() / best_sq_radius >= (0.2f * 0.2f)) {
1399 // Hmm, this is an off-center model. Maybe we can do a better job
1400 // by calculating the bounding sphere from the AABB center.
1401
1402 PN_stdfloat better_sq_radius;
1403 bool found_any = false;
1404 do_calc_sphere_radius(aabb_center, better_sq_radius, found_any,
1405 vertex_data, cdata, current_thread);
1406
1407 if (found_any && better_sq_radius > 0.0f &&
1408 better_sq_radius <= best_sq_radius) {
1409 // Great. This is as good a sphere as we're going to get.
1410 if (btype == BoundingVolume::BT_best &&
1411 avg_box_area < better_sq_radius * MathNumbers::pi) {
1412 // But the box is better, anyway. Use that instead.
1413 cdata->_internal_bounds = new BoundingBox(pmin, pmax);
1414 break;
1415 }
1416 cdata->_internal_bounds =
1417 new BoundingSphere(aabb_center, csqrt(better_sq_radius));
1418 break;
1419 }
1420 }
1421
1422 if (btype != BoundingVolume::BT_sphere &&
1423 avg_box_area < sq_center_dist * MathNumbers::pi) {
1424 // A box is probably a tighter fit.
1425 cdata->_internal_bounds = new BoundingBox(pmin, pmax);
1426 break;
1427
1428 } else if (sq_center_dist >= 0.0f && sq_center_dist <= best_sq_radius) {
1429 // No, but a sphere centered on the origin is apparently still
1430 // better than a sphere around the bounding box.
1431 cdata->_internal_bounds =
1432 new BoundingSphere(LPoint3::origin(), csqrt(sq_center_dist));
1433 break;
1434
1435 } else if (btype == BoundingVolume::BT_sphere) {
1436 // This is the worst sphere we can make, which is why we will only
1437 // do it when the user specifically requests a sphere.
1438 cdata->_internal_bounds =
1439 new BoundingSphere(aabb_center,
1440 (best_sq_radius > 0.0f) ? csqrt(best_sq_radius) : 0.0f);
1441 break;
1442 }
1443 }
1444 // Fall through.
1445
1446 case BoundingVolume::BT_box:
1447 cdata->_internal_bounds = new BoundingBox(pmin, pmax);
1448 }
1449
1450 Primitives::const_iterator pi;
1451 for (pi = cdata->_primitives.begin();
1452 pi != cdata->_primitives.end();
1453 ++pi) {
1454 CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
1455 num_vertices += prim->get_num_vertices();
1456 }
1457
1458 } else {
1459 // No points; empty bounding volume.
1460 if (btype == BoundingVolume::BT_sphere) {
1461 cdata->_internal_bounds = new BoundingSphere;
1462 } else {
1463 cdata->_internal_bounds = new BoundingBox;
1464 }
1465 }
1466
1467 cdata->_nested_vertices = num_vertices;
1468 cdata->_internal_bounds_stale = false;
1469}
1470
1471/**
1472 * The private implementation of calc_tight_bounds().
1473 */
1474void Geom::
1475do_calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
1476 PN_stdfloat &sq_center_dist, bool &found_any,
1477 const GeomVertexData *vertex_data,
1478 bool got_mat, const LMatrix4 &mat,
1479 const InternalName *column_name,
1480 const CData *cdata, Thread *current_thread) const {
1481 Primitives::const_iterator pi;
1482 for (pi = cdata->_primitives.begin();
1483 pi != cdata->_primitives.end();
1484 ++pi) {
1485 CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
1486 prim->calc_tight_bounds(min_point, max_point, sq_center_dist,
1487 found_any, vertex_data, got_mat, mat,
1488 column_name, current_thread);
1489 }
1490}
1491
1492/**
1493 *
1494 */
1495void Geom::
1496do_calc_sphere_radius(const LPoint3 &center, PN_stdfloat &sq_radius,
1497 bool &found_any, const GeomVertexData *vertex_data,
1498 const CData *cdata, Thread *current_thread) const {
1499 Primitives::const_iterator pi;
1500 for (pi = cdata->_primitives.begin();
1501 pi != cdata->_primitives.end();
1502 ++pi) {
1503 CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
1504 prim->calc_sphere_radius(center, sq_radius, found_any,
1505 vertex_data, current_thread);
1506 }
1507}
1508
1509/**
1510 * Removes the indicated PreparedGraphicsObjects table from the Geom's table,
1511 * without actually releasing the geom. This is intended to be called only
1512 * from PreparedGraphicsObjects::release_geom(); it should never be called by
1513 * user code.
1514 */
1515void Geom::
1516clear_prepared(PreparedGraphicsObjects *prepared_objects) {
1517 Contexts::iterator ci;
1518 ci = _contexts.find(prepared_objects);
1519 if (ci != _contexts.end()) {
1520 _contexts.erase(ci);
1521 } else {
1522 // If this assertion fails, clear_prepared() was given a prepared_objects
1523 // that the geom didn't know about.
1524 nassert_raise("unknown PreparedGraphicsObjects");
1525 }
1526}
1527
1528/**
1529 * Verifies that the all of the primitives within the geom reference vertices
1530 * that actually exist within the indicated GeomVertexData (presumably in
1531 * preparation for assigning the geom to use this data). Returns true if the
1532 * data appears to be valid, false otherwise.
1533 */
1534bool Geom::
1535check_will_be_valid(const GeomVertexData *vertex_data) const {
1536 Thread *current_thread = Thread::get_current_thread();
1537
1538 CDReader cdata(_cycler, current_thread);
1539
1540 GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1541 data_reader.check_array_readers();
1542
1543 Primitives::const_iterator pi;
1544 for (pi = cdata->_primitives.begin();
1545 pi != cdata->_primitives.end();
1546 ++pi) {
1547 GeomPrimitivePipelineReader reader((*pi).get_read_pointer(), current_thread);
1548 reader.check_minmax();
1549 if (!reader.check_valid(&data_reader)) {
1550 return false;
1551 }
1552 }
1553
1554 return true;
1555}
1556
1557/**
1558 * Rederives the _geom_rendering member.
1559 */
1560void Geom::
1561reset_geom_rendering(Geom::CData *cdata) {
1562 cdata->_geom_rendering = 0;
1563 Primitives::const_iterator pi;
1564 for (pi = cdata->_primitives.begin();
1565 pi != cdata->_primitives.end();
1566 ++pi) {
1567 cdata->_geom_rendering |= (*pi).get_read_pointer()->get_geom_rendering();
1568 }
1569
1570 if ((cdata->_geom_rendering & GR_point) != 0) {
1571 CPT(GeomVertexData) data = cdata->_data.get_read_pointer();
1572 if (data->has_column(InternalName::get_size())) {
1573 cdata->_geom_rendering |= GR_per_point_size;
1574 }
1575 if (data->has_column(InternalName::get_aspect_ratio())) {
1576 cdata->_geom_rendering |= GR_point_aspect_ratio;
1577 }
1578 if (data->has_column(InternalName::get_rotate())) {
1579 cdata->_geom_rendering |= GR_point_rotate;
1580 }
1581 }
1582
1583 switch (get_shade_model()) {
1584 case SM_flat_first_vertex:
1585 cdata->_geom_rendering |= GR_flat_first_vertex;
1586 break;
1587
1588 case SM_flat_last_vertex:
1589 cdata->_geom_rendering |= GR_flat_last_vertex;
1590 break;
1591
1592 default:
1593 break;
1594 }
1595}
1596
1597/**
1598 * Combines two primitives of the same type into a single primitive. a_prim
1599 * is modified to append the vertices from b_prim, which is unmodified.
1600 */
1601void Geom::
1602combine_primitives(GeomPrimitive *a_prim, CPT(GeomPrimitive) b_prim,
1603 Thread *current_thread) {
1604 nassertv(a_prim != b_prim);
1605 nassertv(a_prim->get_type() == b_prim->get_type());
1606
1607 if (a_prim->get_index_type() != b_prim->get_index_type()) {
1608 GeomPrimitive::NumericType index_type = max(a_prim->get_index_type(), b_prim->get_index_type());
1609 a_prim->set_index_type(index_type);
1610 if (b_prim->get_index_type() != index_type) {
1611 PT(GeomPrimitive) b_prim_copy = b_prim->make_copy();
1612 b_prim_copy->set_index_type(index_type);
1613 b_prim = b_prim_copy;
1614 }
1615 }
1616
1617 if (!b_prim->is_indexed()) {
1618 PT(GeomPrimitive) b_prim_copy = b_prim->make_copy();
1619 b_prim_copy->make_indexed();
1620 b_prim = b_prim_copy;
1621 }
1622
1623 PT(GeomVertexArrayData) a_vertices = a_prim->modify_vertices();
1624 CPT(GeomVertexArrayData) b_vertices = b_prim->get_vertices();
1625
1626 if (a_prim->requires_unused_vertices()) {
1627 GeomVertexReader index(b_vertices, 0);
1628 int b_vertex = index.get_data1i();
1629 a_prim->append_unused_vertices(a_vertices, b_vertex);
1630 }
1631
1632 PT(GeomVertexArrayDataHandle) a_handle =
1633 new GeomVertexArrayDataHandle(std::move(a_vertices), current_thread);
1634 CPT(GeomVertexArrayDataHandle) b_handle =
1635 new GeomVertexArrayDataHandle(std::move(b_vertices), current_thread);
1636
1637 size_t orig_a_vertices = a_handle->get_num_rows();
1638
1639 a_handle->copy_subdata_from(a_handle->get_data_size_bytes(), 0,
1640 b_handle, 0, b_handle->get_data_size_bytes());
1641 a_prim->clear_minmax();
1642 if (a_prim->is_composite()) {
1643 // Also copy the ends array.
1644 PTA_int a_ends = a_prim->modify_ends();
1645 CPTA_int b_ends = b_prim->get_ends();
1646 for (size_t i = 0; i < b_ends.size(); ++i) {
1647 a_ends.push_back(b_ends[i] + orig_a_vertices);
1648 }
1649 }
1650}
1651
1652/**
1653 * Tells the BamReader how to create objects of type Geom.
1654 */
1657 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
1658}
1659
1660/**
1661 * Writes the contents of this object to the datagram for shipping out to a
1662 * Bam file.
1663 */
1665write_datagram(BamWriter *manager, Datagram &dg) {
1666 TypedWritable::write_datagram(manager, dg);
1667
1668 manager->write_cdata(dg, _cycler);
1669}
1670
1671/**
1672 * This function is called by the BamReader's factory when a new object of
1673 * type Geom is encountered in the Bam file. It should create the Geom and
1674 * extract its information from the file.
1675 */
1676TypedWritable *Geom::
1677make_from_bam(const FactoryParams &params) {
1678 Geom *object = new Geom(nullptr);
1679 DatagramIterator scan;
1680 BamReader *manager;
1681
1682 parse_params(params, scan, manager);
1683 object->fillin(scan, manager);
1684 manager->register_finalize(object);
1685
1686 return object;
1687}
1688
1689/**
1690 * Called by the BamReader to perform any final actions needed for setting up
1691 * the object after all objects have been read and all pointers have been
1692 * completed.
1693 */
1695finalize(BamReader *manager) {
1696 CDWriter cdata(_cycler, true);
1697
1698 // Make sure our GeomVertexData is finalized first. This may result in the
1699 // data getting finalized multiple times, but it doesn't mind that.
1700 if (!cdata->_data.is_null()) {
1701 // We shouldn't call get_write_pointer(), which might replicate the
1702 // GeomVertexData unnecessarily.
1703 cdata->_data.get_unsafe_pointer()->finalize(manager);
1704 }
1705
1706 reset_geom_rendering(cdata);
1707}
1708
1709/**
1710 * This internal function is called by make_from_bam to read in all of the
1711 * relevant data from the BamFile for the new Geom.
1712 */
1713void Geom::
1714fillin(DatagramIterator &scan, BamReader *manager) {
1715 TypedWritable::fillin(scan, manager);
1716
1717 manager->read_cdata(scan, _cycler);
1718}
1719
1720/**
1721 *
1722 */
1723Geom::CDataCache::
1724~CDataCache() {
1725 set_result(nullptr, nullptr);
1726}
1727
1728/**
1729 *
1730 */
1731CycleData *Geom::CDataCache::
1732make_copy() const {
1733 return new CDataCache(*this);
1734}
1735
1736/**
1737 * Called when the entry is evicted from the cache, this should clean up the
1738 * owning object appropriately.
1739 */
1742 LightMutexHolder holder(_source->_cache_lock);
1743 Cache::iterator ci = _source->_cache.find(&_key);
1744 nassertv(ci != _source->_cache.end());
1745 nassertv((*ci).second == this);
1746 _source->_cache.erase(ci);
1747}
1748
1749/**
1750 *
1751 */
1752void Geom::CacheEntry::
1753output(std::ostream &out) const {
1754 out << "geom " << (void *)_source << ", "
1755 << (const void *)_key._modifier;
1756}
1757
1758
1759/**
1760 *
1761 */
1762CycleData *Geom::CData::
1763make_copy() const {
1764 return new CData(*this);
1765}
1766
1767/**
1768 * Writes the contents of this object to the datagram for shipping out to a
1769 * Bam file.
1770 */
1771void Geom::CData::
1772write_datagram(BamWriter *manager, Datagram &dg) const {
1773 manager->write_pointer(dg, _data.get_read_pointer());
1774
1775 dg.add_uint16(_primitives.size());
1776 Primitives::const_iterator pi;
1777 for (pi = _primitives.begin(); pi != _primitives.end(); ++pi) {
1778 manager->write_pointer(dg, (*pi).get_read_pointer());
1779 }
1780
1781 dg.add_uint8(_primitive_type);
1782 dg.add_uint8(_shade_model);
1783
1784 // Actually, we shouldn't bother writing out _geom_rendering; we'll just
1785 // throw it away anyway.
1786 dg.add_uint16(_geom_rendering);
1787
1788 dg.add_uint8(_bounds_type);
1789}
1790
1791/**
1792 * Receives an array of pointers, one for each time manager->read_pointer()
1793 * was called in fillin(). Returns the number of pointers processed.
1794 */
1795int Geom::CData::
1796complete_pointers(TypedWritable **p_list, BamReader *manager) {
1797 int pi = CycleData::complete_pointers(p_list, manager);
1798
1799 _data = DCAST(GeomVertexData, p_list[pi++]);
1800
1801 Primitives::iterator pri;
1802 for (pri = _primitives.begin(); pri != _primitives.end(); ++pri) {
1803 (*pri) = DCAST(GeomPrimitive, p_list[pi++]);
1804 }
1805
1806 return pi;
1807}
1808
1809/**
1810 * This internal function is called by make_from_bam to read in all of the
1811 * relevant data from the BamFile for the new Geom.
1812 */
1813void Geom::CData::
1814fillin(DatagramIterator &scan, BamReader *manager) {
1815 manager->read_pointer(scan);
1816
1817 int num_primitives = scan.get_uint16();
1818 _primitives.reserve(num_primitives);
1819 for (int i = 0; i < num_primitives; ++i) {
1820 manager->read_pointer(scan);
1821 _primitives.push_back(nullptr);
1822 }
1823
1824 _primitive_type = (PrimitiveType)scan.get_uint8();
1825 _shade_model = (ShadeModel)scan.get_uint8();
1826
1827 // To be removed: we no longer read _geom_rendering from the bam file;
1828 // instead, we rederive it in finalize().
1829 scan.get_uint16();
1830
1831 _modified = Geom::get_next_modified();
1832
1833 _bounds_type = BoundingVolume::BT_default;
1834 if (manager->get_file_minor_ver() >= 19) {
1835 _bounds_type = (BoundingVolume::BoundsType)scan.get_uint8();
1836 }
1837}
1838
1839/**
1840 *
1841 */
1842bool GeomPipelineReader::
1843check_valid(const GeomVertexDataPipelineReader *data_reader) const {
1844 Geom::Primitives::const_iterator pi;
1845 for (pi = _cdata->_primitives.begin();
1846 pi != _cdata->_primitives.end();
1847 ++pi) {
1848 GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread);
1849 reader.check_minmax();
1850 if (!reader.check_valid(data_reader)) {
1851 return false;
1852 }
1853 }
1854
1855 return true;
1856}
1857
1858/**
1859 * The implementation of Geom::draw().
1860 */
1863 const GeomVertexDataPipelineReader *data_reader, bool force) const {
1864 bool all_ok;
1865 {
1866 PStatTimer timer(Geom::_draw_primitive_setup_pcollector);
1867 all_ok = gsg->begin_draw_primitives(this, data_reader, force);
1868 }
1869 if (all_ok) {
1870 Geom::Primitives::const_iterator pi;
1871 for (pi = _cdata->_primitives.begin();
1872 pi != _cdata->_primitives.end();
1873 ++pi) {
1874 GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread);
1875 if (reader.get_num_vertices() != 0) {
1876 reader.check_minmax();
1877 nassertr(reader.check_valid(data_reader), false);
1878 if (!reader.draw(gsg, force)) {
1879 all_ok = false;
1880 }
1881 }
1882 }
1883 gsg->end_draw_primitives();
1884 }
1885
1886 return all_ok;
1887}
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition: bamReader.I:275
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
void register_finalize(TypedWritable *whom)
Should be called by an object reading itself from the Bam file to indicate that this particular objec...
Definition: bamReader.cxx:808
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
Definition: bamReader.cxx:695
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
Definition: bamWriter.cxx:425
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:317
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition: boundingBox.h:29
This defines a bounding sphere, consisting of a center and a radius.
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
Similar to PointerToArray, except that its contents may not be modified.
This base class provides basic reference counting, but also can be used with a CopyOnWritePointer to ...
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
This class is similar to CycleDataWriter, except it allows writing to a particular stage of the pipel...
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
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
Definition: cycleData.cxx:48
A class to retrieve the individual data elements previously stored in a Datagram.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
This is a special class object that holds all the information returned by a particular GSG to indicat...
Definition: geomContext.h:34
Encapsulates the data from a Geom, pre-fetched for one stage of the pipeline.
Definition: geom.h:405
bool draw(GraphicsStateGuardianBase *gsg, const GeomVertexDataPipelineReader *data_reader, bool force) const
The implementation of Geom::draw().
Definition: geom.cxx:1862
Encapsulates the data from a GeomPrimitive, pre-fetched for one stage of the pipeline.
void check_minmax() const
Ensures that the primitive's minmax cache has been computed.
int get_vertex(int i) const
Returns the ith vertex index in the table.
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
void clear_vertices()
Removes all of the vertices and primitives from the object, so they can be re-added.
CPTA_int get_ends() const
Returns a const pointer to the primitive ends array so application code can read it directly.
void make_indexed()
Converts the primitive from nonindexed form to indexed form.
get_num_vertices
Returns the number of indices used by all the primitives in this object.
Definition: geomPrimitive.h:99
bool check_valid(const GeomVertexData *vertex_data) const
Verifies that the primitive only references vertices that actually exist within the indicated GeomVer...
bool is_composite() const
Returns true if the primitive is a composite primitive such as a tristrip or trifan,...
Definition: geomPrimitive.I:74
void set_shade_model(ShadeModel shade_model)
Changes the ShadeModel hint for this primitive.
Definition: geomPrimitive.I:36
get_index_type
Returns the numeric type of the index column.
Definition: geomPrimitive.h:85
get_num_unused_vertices_per_primitive
Returns the number of vertices that are added between primitives that aren't, strictly speaking,...
void set_index_type(NumericType index_type)
Changes the numeric type of the index column.
get_num_vertices_per_primitive
If the primitive type is a simple type in which all primitives have the same number of vertices,...
PTA_int modify_ends()
Returns a modifiable pointer to the primitive ends array, so application code can directly fiddle wit...
void clear_minmax()
Undoes a previous call to set_minmax(), and allows the minimum and maximum values to be recomputed no...
bool is_indexed() const
Returns true if the primitive is indexed, false otherwise.
Definition: geomPrimitive.I:86
This data object is returned by GeomVertexArrayData::get_handle() or modify_handle().
unsigned char * get_write_pointer()
Returns a writable pointer to the beginning of the actual data stream.
This is the data for one array of a GeomVertexData structure.
Encapsulates the data from a GeomVertexData, pre-fetched for one stage of the pipeline.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
This class defines the physical layout of the vertex data stored within a Geom.
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
This object provides the functionality of both a GeomVertexReader and a GeomVertexWriter,...
virtual void evict_callback()
Called when the entry is evicted from the cache, this should clean up the owning object appropriately...
Definition: geom.cxx:1741
A container for geometry primitives.
Definition: geom.h:54
void decompose_in_place()
Decomposes all of the primitives within this Geom, leaving the results in place.
Definition: geom.cxx:446
bool request_resident() const
Returns true if all the primitive arrays are currently resident in memory.
Definition: geom.cxx:1016
void prepare(PreparedGraphicsObjects *prepared_objects)
Indicates that the geom should be enqueued to be prepared in the indicated prepared_objects at the be...
Definition: geom.cxx:1220
insert_primitive
Inserts a new GeomPrimitive structure to the Geom object.
Definition: geom.h:101
int release_all()
Frees the context allocated on all objects for which the geom has been declared.
Definition: geom.cxx:1261
void reverse_in_place()
Reverses all of the primitives within this Geom, leaving the results in place.
Definition: geom.cxx:520
bool draw(GraphicsStateGuardianBase *gsg, const GeomVertexData *vertex_data, bool force, Thread *current_thread) const
Actually draws the Geom with the indicated GSG, using the indicated vertex data (which might have bee...
Definition: geom.cxx:1319
void offset_vertices(const GeomVertexData *data, int offset)
Replaces a Geom's vertex table with a new table, and simultaneously adds the indicated offset to all ...
Definition: geom.cxx:192
void make_patches_in_place()
Replaces the GeomPrimitives within this Geom with corresponding GeomPatches.
Definition: geom.cxx:869
virtual bool copy_primitives_from(const Geom *other)
Copies the primitives from the indicated Geom into this one.
Definition: geom.cxx:954
void clear_primitives()
Removes all the primitives from the Geom object (but keeps the same table of vertices).
Definition: geom.cxx:427
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the geom context only on the indicated object, if it exists there.
Definition: geom.cxx:1243
int make_nonindexed(bool composite_only)
Converts the geom from indexed to nonindexed by duplicating vertices as necessary.
Definition: geom.cxx:234
void doubleside_in_place()
Doublesides all of the primitives within this Geom, leaving the results in place.
Definition: geom.cxx:483
bool check_valid() const
Verifies that the all of the primitives within the geom reference vertices that actually exist within...
Definition: geom.cxx:1074
remove_primitive
Removes the ith primitive from the list.
Definition: geom.h:101
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
GeomContext * prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the geom on the particular GSG, if it does not already exist.
Definition: geom.cxx:1295
void operator=(const Geom &copy)
The copy assignment operator is not pipeline-safe.
Definition: geom.cxx:71
void make_points_in_place()
Replaces the GeomPrimitives within this Geom with corresponding GeomPoints.
Definition: geom.cxx:828
void rotate_in_place()
Rotates all of the primitives within this Geom, leaving the results in place.
Definition: geom.cxx:557
void make_lines_in_place()
Replaces the GeomPrimitives within this Geom with corresponding GeomLines, representing a wireframe o...
Definition: geom.cxx:786
void unify_in_place(int max_indices, bool preserve_order)
Unifies all of the primitives contained within this Geom into a single (or as few as possible,...
Definition: geom.cxx:613
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: geom.cxx:1665
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
Definition: geom.cxx:1695
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 void register_with_read_factory()
Tells the BamReader how to create objects of type Geom.
Definition: geom.cxx:1656
static UpdateSeq get_next_modified()
Returns a monotonically increasing sequence.
Definition: geom.cxx:1337
bool is_prepared(PreparedGraphicsObjects *prepared_objects) const
Returns true if the geom has already been prepared or enqueued for preparation on the indicated GSG,...
Definition: geom.cxx:1229
void make_adjacency_in_place()
Replaces the GeomPrimitives within this Geom with corresponding versions with adjacency information.
Definition: geom.cxx:912
get_num_bytes
Returns the number of bytes consumed by the geom and its primitives (but not including its vertex tab...
Definition: geom.h:127
void transform_vertices(const LMatrix4 &mat)
Applies the indicated transform to all of the vertices in the Geom.
Definition: geom.cxx:1045
virtual Geom * make_copy() const
Returns a newly-allocated Geom that is a shallow copy of this one.
Definition: geom.cxx:100
void set_vertex_data(const GeomVertexData *data)
Replaces the Geom's underlying vertex data table with a completely new table.
Definition: geom.cxx:171
void set_usage_hint(UsageHint usage_hint)
Changes the UsageHint hint for all of the primitives on this Geom to the same value.
Definition: geom.cxx:130
get_primitive_type
Returns the fundamental primitive type that is common to all GeomPrimitives added within the Geom.
Definition: geom.h:74
UsageHint get_usage_hint() const
Returns the minimum (i.e.
Definition: geom.cxx:110
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
Similar to MutexHolder, but for a light mutex.
A lightweight class that represents a single element that may be timed and/or counted via stats.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
A table of objects that are saved within the graphics context for reference by handle later.
void release_geom(GeomContext *gc)
Indicates that a geom context, created by a previous call to prepare_geom(), is no longer needed.
bool is_geom_queued(const Geom *geom) const
Returns true if the geom has been queued on this GSG, false otherwise.
GeomContext * prepare_geom_now(Geom *geom, GraphicsStateGuardianBase *gsg)
Immediately creates a new GeomContext for the indicated geom and returns it.
bool dequeue_geom(Geom *geom)
Removes a geom from the queued list of geoms to be prepared.
void enqueue_geom(Geom *geom)
Indicates that a geom would like to be put on the list to be prepared when the GSG is next ready to d...
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
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class's make_from_bam() method to read in all...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
This is a sequence number that increments monotonically.
Definition: updateSeq.h:37
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT(GeomVertexData) Geom
Returns a GeomVertexData that represents the results of computing the vertex animation on the CPU for...
Definition: geom.cxx:306
PT(CopyOnWriteObject) Geom
Required to implement CopyOnWriteObject.
Definition: geom.cxx:43
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.