Panda3D

Loading...
Searching...
No Matches
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"
18#include "graphicsStateGuardianBase.h"
19#include "preparedGraphicsObjects.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
28 using std::max;
29 using std::min;
30
31 UpdateSeq Geom::_next_modified;
32 PStatCollector Geom::_draw_primitive_setup_pcollector("Draw:Primitive:Setup");
33
34 TypeHandle Geom::_type_handle;
35 TypeHandle Geom::CDataCache::_type_handle;
36 TypeHandle Geom::CacheEntry::_type_handle;
37 TypeHandle Geom::CData::_type_handle;
38 TypeHandle GeomPipelineReader::_type_handle;
39
40/**
41 * Required to implement CopyOnWriteObject.
42 */
43PT(CopyOnWriteObject) Geom::
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) :
60 CopyOnWriteObject(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 */
70 void Geom::
71 operator = (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();
91 release_all();
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 */
99Geom *Geom::
100 make_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::
110 get_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 */
129 void Geom::
130 set_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 */
151PT(GeomVertexData) Geom::
152 modify_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 */
170 void Geom::
171 set_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 */
191 void Geom::
192 offset_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 */
233 int Geom::
234 make_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 */
306CPT(GeomVertexData) Geom::
307 get_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 */
318 void Geom::
319 set_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 */
359 void Geom::
360 insert_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 */
402 void Geom::
403 remove_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 */
426 void Geom::
427 clear_primitives() {
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 */
445 void Geom::
446 decompose_in_place() {
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 */
482 void Geom::
483 doubleside_in_place() {
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 */
519 void Geom::
520 reverse_in_place() {
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 */
556 void Geom::
557 rotate_in_place() {
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 */
612 void Geom::
613 unify_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 */
785 void Geom::
786 make_lines_in_place() {
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 */
827 void Geom::
828 make_points_in_place() {
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 */
868 void Geom::
869 make_patches_in_place() {
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 */
911 void Geom::
912 make_adjacency_in_place() {
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 */
953 bool Geom::
954 copy_primitives_from(const Geom *other) {
955 if (get_primitive_type() != PT_none &&
956 other->get_primitive_type() != get_primitive_type()) {
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 */
992 int Geom::
993 get_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 */
1015 bool Geom::
1016 request_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 */
1044 void Geom::
1045 transform_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 */
1073 bool Geom::
1074 check_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 */
1088 bool Geom::
1089 check_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 */
1100CPT(BoundingVolume) Geom::
1101 get_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 */
1118 int Geom::
1119 get_nested_vertices(Thread *current_thread) const {
1120 CDLockedReader cdata(_cycler, current_thread);
1121 if (cdata->_internal_bounds_stale) {
1122 if (cdata->_user_bounds != nullptr) {
1123 // Don't do the expensive compute_internal_bounds call.
1124 if (cdata->_nested_vertices == 0) {
1125 CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
1126 int num_vertices = 0;
1127
1128 Primitives::const_iterator pi;
1129 for (pi = cdataw->_primitives.begin();
1130 pi != cdataw->_primitives.end();
1131 ++pi) {
1132 GeomPrimitivePipelineReader reader((*pi).get_read_pointer(current_thread), current_thread);
1133 num_vertices += reader.get_num_vertices();
1134 }
1135
1136 cdataw->_nested_vertices = num_vertices;
1137 return num_vertices;
1138 }
1139 } else {
1140 CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
1141 compute_internal_bounds(cdataw, current_thread);
1142 return cdataw->_nested_vertices;
1143 }
1144 }
1145 return cdata->_nested_vertices;
1146}
1147
1148/**
1149 *
1150 */
1151 void Geom::
1152output(std::ostream &out) const {
1153 CDReader cdata(_cycler);
1154
1155 // Get a list of the primitive types contained within this object.
1156 int num_faces = 0;
1157 pset<TypeHandle> types;
1158 Primitives::const_iterator pi;
1159 for (pi = cdata->_primitives.begin();
1160 pi != cdata->_primitives.end();
1161 ++pi) {
1162 CPT(GeomPrimitive) prim = (*pi).get_read_pointer();
1163 num_faces += prim->get_num_faces();
1164 types.insert(prim->get_type());
1165 }
1166
1167 out << get_type() << " [";
1168 pset<TypeHandle>::iterator ti;
1169 for (ti = types.begin(); ti != types.end(); ++ti) {
1170 out << " " << (*ti);
1171 }
1172 out << " ], " << num_faces << " faces";
1173}
1174
1175/**
1176 *
1177 */
1178 void Geom::
1179write(std::ostream &out, int indent_level) const {
1180 CDReader cdata(_cycler);
1181
1182 // Get a list of the primitive types contained within this object.
1183 Primitives::const_iterator pi;
1184 for (pi = cdata->_primitives.begin();
1185 pi != cdata->_primitives.end();
1186 ++pi) {
1187 (*pi).get_read_pointer()->write(out, indent_level);
1188 }
1189}
1190
1191/**
1192 * Removes all of the previously-cached results of munge_geom().
1193 *
1194 * This blows away the entire cache, upstream and downstream the pipeline.
1195 * Use clear_cache_stage() instead if you only want to blow away the cache at
1196 * the current stage and upstream.
1197 */
1198 void Geom::
1199 clear_cache() {
1200 LightMutexHolder holder(_cache_lock);
1201 for (Cache::iterator ci = _cache.begin();
1202 ci != _cache.end();
1203 ++ci) {
1204 CacheEntry *entry = (*ci).second;
1205 entry->erase();
1206 }
1207 _cache.clear();
1208}
1209
1210/**
1211 * Removes all of the previously-cached results of munge_geom(), at the
1212 * current pipeline stage and upstream. Does not affect the downstream cache.
1213 *
1214 * Don't call this in a downstream thread unless you don't mind it blowing
1215 * away other changes you might have recently made in an upstream thread.
1216 */
1217 void Geom::
1218 clear_cache_stage(Thread *current_thread) {
1219 LightMutexHolder holder(_cache_lock);
1220 for (Cache::iterator ci = _cache.begin();
1221 ci != _cache.end();
1222 ++ci) {
1223 CacheEntry *entry = (*ci).second;
1224 CDCacheWriter cdata(entry->_cycler, current_thread);
1225 cdata->set_result(nullptr, nullptr);
1226 }
1227}
1228
1229/**
1230 * Indicates that the geom should be enqueued to be prepared in the indicated
1231 * prepared_objects at the beginning of the next frame. This will ensure the
1232 * geom is already loaded into geom memory if it is expected to be rendered
1233 * soon.
1234 *
1235 * Use this function instead of prepare_now() to preload geoms from a user
1236 * interface standpoint.
1237 */
1238 void Geom::
1239 prepare(PreparedGraphicsObjects *prepared_objects) {
1240 prepared_objects->enqueue_geom(this);
1241}
1242
1243/**
1244 * Returns true if the geom has already been prepared or enqueued for
1245 * preparation on the indicated GSG, false otherwise.
1246 */
1247 bool Geom::
1248 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
1249 Contexts::const_iterator ci;
1250 ci = _contexts.find(prepared_objects);
1251 if (ci != _contexts.end()) {
1252 return true;
1253 }
1254 return prepared_objects->is_geom_queued(this);
1255}
1256
1257/**
1258 * Frees the geom context only on the indicated object, if it exists there.
1259 * Returns true if it was released, false if it had not been prepared.
1260 */
1261 bool Geom::
1262 release(PreparedGraphicsObjects *prepared_objects) {
1263 Contexts::iterator ci;
1264 ci = _contexts.find(prepared_objects);
1265 if (ci != _contexts.end()) {
1266 GeomContext *gc = (*ci).second;
1267 prepared_objects->release_geom(gc);
1268 return true;
1269 }
1270
1271 // Maybe it wasn't prepared yet, but it's about to be.
1272 return prepared_objects->dequeue_geom(this);
1273}
1274
1275/**
1276 * Frees the context allocated on all objects for which the geom has been
1277 * declared. Returns the number of contexts which have been freed.
1278 */
1279 int Geom::
1280 release_all() {
1281 // We have to traverse a copy of the _contexts list, because the
1282 // PreparedGraphicsObjects object will call clear_prepared() in response to
1283 // each release_geom(), and we don't want to be modifying the _contexts list
1284 // while we're traversing it.
1285 Contexts temp = _contexts;
1286 int num_freed = (int)_contexts.size();
1287
1288 Contexts::const_iterator ci;
1289 for (ci = temp.begin(); ci != temp.end(); ++ci) {
1290 PreparedGraphicsObjects *prepared_objects = (*ci).first;
1291 GeomContext *gc = (*ci).second;
1292 prepared_objects->release_geom(gc);
1293 }
1294
1295 // Now that we've called release_geom() on every known context, the
1296 // _contexts list should have completely emptied itself.
1297 nassertr(_contexts.empty(), num_freed);
1298
1299 return num_freed;
1300}
1301
1302/**
1303 * Creates a context for the geom on the particular GSG, if it does not
1304 * already exist. Returns the new (or old) GeomContext. This assumes that
1305 * the GraphicsStateGuardian is the currently active rendering context and
1306 * that it is ready to accept new geoms. If this is not necessarily the case,
1307 * you should use prepare() instead.
1308 *
1309 * Normally, this is not called directly except by the GraphicsStateGuardian;
1310 * a geom does not need to be explicitly prepared by the user before it may be
1311 * rendered.
1312 */
1313GeomContext *Geom::
1314 prepare_now(PreparedGraphicsObjects *prepared_objects,
1315 GraphicsStateGuardianBase *gsg) {
1316 Contexts::const_iterator ci;
1317 ci = _contexts.find(prepared_objects);
1318 if (ci != _contexts.end()) {
1319 return (*ci).second;
1320 }
1321
1322 GeomContext *gc = prepared_objects->prepare_geom_now(this, gsg);
1323 if (gc != nullptr) {
1324 _contexts[prepared_objects] = gc;
1325 }
1326 return gc;
1327}
1328
1329/**
1330 * Actually draws the Geom with the indicated GSG, using the indicated vertex
1331 * data (which might have been pre-munged to support the GSG's needs).
1332 *
1333 * Returns true if all of the primitives were drawn normally, false if there
1334 * was a problem (for instance, some of the data was nonresident). If force
1335 * is passed true, it will wait for the data to become resident if necessary.
1336 */
1337 bool Geom::
1338 draw(GraphicsStateGuardianBase *gsg, const GeomVertexData *vertex_data,
1339 bool force, Thread *current_thread) const {
1340 GeomPipelineReader geom_reader(this, current_thread);
1341 GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1342 data_reader.check_array_readers();
1343
1344 return geom_reader.draw(gsg, &data_reader, force);
1345}
1346
1347/**
1348 * Returns a monotonically increasing sequence. Each time this is called, a
1349 * new sequence number is returned, higher than the previous value.
1350 *
1351 * This is used to ensure that GeomVertexArrayData::get_modified() and
1352 * GeomPrimitive::get_modified() update from the same space, so that
1353 * Geom::get_modified() returns a meaningful value.
1354 */
1355 UpdateSeq Geom::
1356 get_next_modified() {
1357 ++_next_modified;
1358 return _next_modified;
1359}
1360
1361/**
1362 * Recomputes the dynamic bounding volume for this Geom. This includes all of
1363 * the vertices.
1364 */
1365 void Geom::
1366compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
1367 int num_vertices = 0;
1368
1369 // Get the vertex data, after animation.
1370 CPT(GeomVertexData) vertex_data = get_animated_vertex_data(true, current_thread);
1371
1372 // Now actually compute the bounding volume. We do this by using
1373 // calc_tight_bounds to determine our box first.
1374 LPoint3 pmin, pmax;
1375 PN_stdfloat sq_center_dist = 0.0f;
1376 bool found_any = false;
1377 do_calc_tight_bounds(pmin, pmax, sq_center_dist, found_any,
1378 vertex_data, false, LMatrix4::ident_mat(),
1379 InternalName::get_vertex(),
1380 cdata, current_thread);
1381
1382 BoundingVolume::BoundsType btype = cdata->_bounds_type;
1383 if (btype == BoundingVolume::BT_default) {
1384 btype = bounds_type;
1385 }
1386
1387 if (found_any) {
1388 nassertv(!pmin.is_nan());
1389 nassertv(!pmax.is_nan());
1390
1391 // Then we put the bounding volume around both of those points.
1392 PN_stdfloat avg_box_area;
1393 switch (btype) {
1394 case BoundingVolume::BT_best:
1395 case BoundingVolume::BT_fastest:
1396 case BoundingVolume::BT_default:
1397 {
1398 // When considering a box, calculate (roughly) the average area of the
1399 // sides. We will use this to determine whether a sphere or box is a
1400 // better fit.
1401 PN_stdfloat min_extent = min(pmax[0] - pmin[0],
1402 min(pmax[1] - pmin[1],
1403 pmax[2] - pmin[2]));
1404 PN_stdfloat max_extent = max(pmax[0] - pmin[0],
1405 max(pmax[1] - pmin[1],
1406 pmax[2] - pmin[2]));
1407 avg_box_area = ((min_extent * min_extent) + (max_extent * max_extent)) / 2;
1408 }
1409 // Fall through
1410 case BoundingVolume::BT_sphere:
1411 {
1412 // Determine the best radius for a bounding sphere.
1413 LPoint3 aabb_center = (pmin + pmax) * 0.5f;
1414 PN_stdfloat best_sq_radius = (pmax - aabb_center).length_squared();
1415
1416 if (btype != BoundingVolume::BT_fastest && best_sq_radius > 0.0f &&
1417 aabb_center.length_squared() / best_sq_radius >= (0.2f * 0.2f)) {
1418 // Hmm, this is an off-center model. Maybe we can do a better job
1419 // by calculating the bounding sphere from the AABB center.
1420
1421 PN_stdfloat better_sq_radius;
1422 bool found_any = false;
1423 do_calc_sphere_radius(aabb_center, better_sq_radius, found_any,
1424 vertex_data, cdata, current_thread);
1425
1426 if (found_any && better_sq_radius > 0.0f &&
1427 better_sq_radius <= best_sq_radius) {
1428 // Great. This is as good a sphere as we're going to get.
1429 if (btype == BoundingVolume::BT_best &&
1430 avg_box_area < better_sq_radius * MathNumbers::pi) {
1431 // But the box is better, anyway. Use that instead.
1432 cdata->_internal_bounds = new BoundingBox(pmin, pmax);
1433 break;
1434 }
1435 cdata->_internal_bounds =
1436 new BoundingSphere(aabb_center, csqrt(better_sq_radius));
1437 break;
1438 }
1439 }
1440
1441 if (btype != BoundingVolume::BT_sphere &&
1442 avg_box_area < sq_center_dist * MathNumbers::pi) {
1443 // A box is probably a tighter fit.
1444 cdata->_internal_bounds = new BoundingBox(pmin, pmax);
1445 break;
1446
1447 } else if (sq_center_dist >= 0.0f && sq_center_dist <= best_sq_radius) {
1448 // No, but a sphere centered on the origin is apparently still
1449 // better than a sphere around the bounding box.
1450 cdata->_internal_bounds =
1451 new BoundingSphere(LPoint3::origin(), csqrt(sq_center_dist));
1452 break;
1453
1454 } else if (btype == BoundingVolume::BT_sphere) {
1455 // This is the worst sphere we can make, which is why we will only
1456 // do it when the user specifically requests a sphere.
1457 cdata->_internal_bounds =
1458 new BoundingSphere(aabb_center,
1459 (best_sq_radius > 0.0f) ? csqrt(best_sq_radius) : 0.0f);
1460 break;
1461 }
1462 }
1463 // Fall through.
1464
1465 case BoundingVolume::BT_box:
1466 cdata->_internal_bounds = new BoundingBox(pmin, pmax);
1467 }
1468
1469 Primitives::const_iterator pi;
1470 for (pi = cdata->_primitives.begin();
1471 pi != cdata->_primitives.end();
1472 ++pi) {
1473 CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
1474 num_vertices += prim->get_num_vertices();
1475 }
1476
1477 } else {
1478 // No points; empty bounding volume.
1479 if (btype == BoundingVolume::BT_sphere) {
1480 cdata->_internal_bounds = new BoundingSphere;
1481 } else {
1482 cdata->_internal_bounds = new BoundingBox;
1483 }
1484 }
1485
1486 cdata->_nested_vertices = num_vertices;
1487 cdata->_internal_bounds_stale = false;
1488}
1489
1490/**
1491 * The private implementation of calc_tight_bounds().
1492 */
1493 void Geom::
1494do_calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
1495 PN_stdfloat &sq_center_dist, bool &found_any,
1496 const GeomVertexData *vertex_data,
1497 bool got_mat, const LMatrix4 &mat,
1498 const InternalName *column_name,
1499 const CData *cdata, Thread *current_thread) const {
1500 Primitives::const_iterator pi;
1501 for (pi = cdata->_primitives.begin();
1502 pi != cdata->_primitives.end();
1503 ++pi) {
1504 CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
1505 prim->calc_tight_bounds(min_point, max_point, sq_center_dist,
1506 found_any, vertex_data, got_mat, mat,
1507 column_name, current_thread);
1508 }
1509}
1510
1511/**
1512 *
1513 */
1514 void Geom::
1515do_calc_sphere_radius(const LPoint3 &center, PN_stdfloat &sq_radius,
1516 bool &found_any, const GeomVertexData *vertex_data,
1517 const CData *cdata, Thread *current_thread) const {
1518 Primitives::const_iterator pi;
1519 for (pi = cdata->_primitives.begin();
1520 pi != cdata->_primitives.end();
1521 ++pi) {
1522 CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
1523 prim->calc_sphere_radius(center, sq_radius, found_any,
1524 vertex_data, current_thread);
1525 }
1526}
1527
1528/**
1529 * Removes the indicated PreparedGraphicsObjects table from the Geom's table,
1530 * without actually releasing the geom. This is intended to be called only
1531 * from PreparedGraphicsObjects::release_geom(); it should never be called by
1532 * user code.
1533 */
1534 void Geom::
1535clear_prepared(PreparedGraphicsObjects *prepared_objects) {
1536 Contexts::iterator ci;
1537 ci = _contexts.find(prepared_objects);
1538 if (ci != _contexts.end()) {
1539 _contexts.erase(ci);
1540 } else {
1541 // If this assertion fails, clear_prepared() was given a prepared_objects
1542 // that the geom didn't know about.
1543 nassert_raise("unknown PreparedGraphicsObjects");
1544 }
1545}
1546
1547/**
1548 * Verifies that the all of the primitives within the geom reference vertices
1549 * that actually exist within the indicated GeomVertexData (presumably in
1550 * preparation for assigning the geom to use this data). Returns true if the
1551 * data appears to be valid, false otherwise.
1552 */
1553 bool Geom::
1554check_will_be_valid(const GeomVertexData *vertex_data) const {
1555 Thread *current_thread = Thread::get_current_thread();
1556
1557 CDReader cdata(_cycler, current_thread);
1558
1559 GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1560 data_reader.check_array_readers();
1561
1562 Primitives::const_iterator pi;
1563 for (pi = cdata->_primitives.begin();
1564 pi != cdata->_primitives.end();
1565 ++pi) {
1566 GeomPrimitivePipelineReader reader((*pi).get_read_pointer(), current_thread);
1567 reader.check_minmax();
1568 if (!reader.check_valid(&data_reader)) {
1569 return false;
1570 }
1571 }
1572
1573 return true;
1574}
1575
1576/**
1577 * Rederives the _geom_rendering member.
1578 */
1579 void Geom::
1580reset_geom_rendering(Geom::CData *cdata) {
1581 cdata->_geom_rendering = 0;
1582 Primitives::const_iterator pi;
1583 for (pi = cdata->_primitives.begin();
1584 pi != cdata->_primitives.end();
1585 ++pi) {
1586 cdata->_geom_rendering |= (*pi).get_read_pointer()->get_geom_rendering();
1587 }
1588
1589 if ((cdata->_geom_rendering & GR_point) != 0) {
1590 CPT(GeomVertexData) data = cdata->_data.get_read_pointer();
1591 if (data->has_column(InternalName::get_size())) {
1592 cdata->_geom_rendering |= GR_per_point_size;
1593 }
1594 if (data->has_column(InternalName::get_aspect_ratio())) {
1595 cdata->_geom_rendering |= GR_point_aspect_ratio;
1596 }
1597 if (data->has_column(InternalName::get_rotate())) {
1598 cdata->_geom_rendering |= GR_point_rotate;
1599 }
1600 }
1601
1602 switch (get_shade_model()) {
1603 case SM_flat_first_vertex:
1604 cdata->_geom_rendering |= GR_flat_first_vertex;
1605 break;
1606
1607 case SM_flat_last_vertex:
1608 cdata->_geom_rendering |= GR_flat_last_vertex;
1609 break;
1610
1611 default:
1612 break;
1613 }
1614}
1615
1616/**
1617 * Combines two primitives of the same type into a single primitive. a_prim
1618 * is modified to append the vertices from b_prim, which is unmodified.
1619 */
1620 void Geom::
1621combine_primitives(GeomPrimitive *a_prim, CPT(GeomPrimitive) b_prim,
1622 Thread *current_thread) {
1623 nassertv(a_prim != b_prim);
1624 nassertv(a_prim->get_type() == b_prim->get_type());
1625
1626 if (a_prim->get_index_type() != b_prim->get_index_type()) {
1627 GeomPrimitive::NumericType index_type = max(a_prim->get_index_type(), b_prim->get_index_type());
1628 a_prim->set_index_type(index_type);
1629 if (b_prim->get_index_type() != index_type) {
1630 PT(GeomPrimitive) b_prim_copy = b_prim->make_copy();
1631 b_prim_copy->set_index_type(index_type);
1632 b_prim = b_prim_copy;
1633 }
1634 }
1635
1636 if (!b_prim->is_indexed()) {
1637 PT(GeomPrimitive) b_prim_copy = b_prim->make_copy();
1638 b_prim_copy->make_indexed();
1639 b_prim = b_prim_copy;
1640 }
1641
1642 PT(GeomVertexArrayData) a_vertices = a_prim->modify_vertices();
1643 CPT(GeomVertexArrayData) b_vertices = b_prim->get_vertices();
1644
1645 if (a_prim->requires_unused_vertices()) {
1646 GeomVertexReader index(b_vertices, 0);
1647 int b_vertex = index.get_data1i();
1648 a_prim->append_unused_vertices(a_vertices, b_vertex);
1649 }
1650
1651 PT(GeomVertexArrayDataHandle) a_handle =
1652 new GeomVertexArrayDataHandle(std::move(a_vertices), current_thread);
1653 CPT(GeomVertexArrayDataHandle) b_handle =
1654 new GeomVertexArrayDataHandle(std::move(b_vertices), current_thread);
1655
1656 size_t orig_a_vertices = a_handle->get_num_rows();
1657
1658 a_handle->copy_subdata_from(a_handle->get_data_size_bytes(), 0,
1659 b_handle, 0, b_handle->get_data_size_bytes());
1660 a_prim->clear_minmax();
1661 if (a_prim->is_composite()) {
1662 // Also copy the ends array.
1663 PTA_int a_ends = a_prim->modify_ends();
1664 CPTA_int b_ends = b_prim->get_ends();
1665 for (size_t i = 0; i < b_ends.size(); ++i) {
1666 a_ends.push_back(b_ends[i] + orig_a_vertices);
1667 }
1668 }
1669}
1670
1671/**
1672 * Tells the BamReader how to create objects of type Geom.
1673 */
1674 void Geom::
1675 register_with_read_factory() {
1676 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
1677}
1678
1679/**
1680 * Writes the contents of this object to the datagram for shipping out to a
1681 * Bam file.
1682 */
1683 void Geom::
1684 write_datagram(BamWriter *manager, Datagram &dg) {
1685 TypedWritable::write_datagram(manager, dg);
1686
1687 manager->write_cdata(dg, _cycler);
1688}
1689
1690/**
1691 * This function is called by the BamReader's factory when a new object of
1692 * type Geom is encountered in the Bam file. It should create the Geom and
1693 * extract its information from the file.
1694 */
1695 TypedWritable *Geom::
1696make_from_bam(const FactoryParams &params) {
1697 Geom *object = new Geom(nullptr);
1698 DatagramIterator scan;
1699 BamReader *manager;
1700
1701 parse_params(params, scan, manager);
1702 object->fillin(scan, manager);
1703 manager->register_finalize(object);
1704
1705 return object;
1706}
1707
1708/**
1709 * Called by the BamReader to perform any final actions needed for setting up
1710 * the object after all objects have been read and all pointers have been
1711 * completed.
1712 */
1713 void Geom::
1714 finalize(BamReader *manager) {
1715 CDWriter cdata(_cycler, true);
1716
1717 // Make sure our GeomVertexData is finalized first. This may result in the
1718 // data getting finalized multiple times, but it doesn't mind that.
1719 if (!cdata->_data.is_null()) {
1720 // We shouldn't call get_write_pointer(), which might replicate the
1721 // GeomVertexData unnecessarily.
1722 cdata->_data.get_unsafe_pointer()->finalize(manager);
1723 }
1724
1725 reset_geom_rendering(cdata);
1726}
1727
1728/**
1729 * This internal function is called by make_from_bam to read in all of the
1730 * relevant data from the BamFile for the new Geom.
1731 */
1732 void Geom::
1733fillin(DatagramIterator &scan, BamReader *manager) {
1734 TypedWritable::fillin(scan, manager);
1735
1736 manager->read_cdata(scan, _cycler);
1737}
1738
1739/**
1740 *
1741 */
1742Geom::CDataCache::
1743~CDataCache() {
1744 set_result(nullptr, nullptr);
1745}
1746
1747/**
1748 *
1749 */
1750CycleData *Geom::CDataCache::
1751make_copy() const {
1752 return new CDataCache(*this);
1753}
1754
1755/**
1756 * Called when the entry is evicted from the cache, this should clean up the
1757 * owning object appropriately.
1758 */
1759 void Geom::CacheEntry::
1760 evict_callback() {
1761 LightMutexHolder holder(_source->_cache_lock);
1762 Cache::iterator ci = _source->_cache.find(&_key);
1763 nassertv(ci != _source->_cache.end());
1764 nassertv((*ci).second == this);
1765 _source->_cache.erase(ci);
1766}
1767
1768/**
1769 *
1770 */
1771 void Geom::CacheEntry::
1772output(std::ostream &out) const {
1773 out << "geom " << (void *)_source << ", "
1774 << (const void *)_key._modifier;
1775}
1776
1777
1778/**
1779 *
1780 */
1781 CycleData *Geom::CData::
1782make_copy() const {
1783 return new CData(*this);
1784}
1785
1786/**
1787 * Writes the contents of this object to the datagram for shipping out to a
1788 * Bam file.
1789 */
1790 void Geom::CData::
1791write_datagram(BamWriter *manager, Datagram &dg) const {
1792 manager->write_pointer(dg, _data.get_read_pointer());
1793
1794 dg.add_uint16(_primitives.size());
1795 Primitives::const_iterator pi;
1796 for (pi = _primitives.begin(); pi != _primitives.end(); ++pi) {
1797 manager->write_pointer(dg, (*pi).get_read_pointer());
1798 }
1799
1800 dg.add_uint8(_primitive_type);
1801 dg.add_uint8(_shade_model);
1802
1803 // Actually, we shouldn't bother writing out _geom_rendering; we'll just
1804 // throw it away anyway.
1805 dg.add_uint16(_geom_rendering);
1806
1807 dg.add_uint8(_bounds_type);
1808}
1809
1810/**
1811 * Receives an array of pointers, one for each time manager->read_pointer()
1812 * was called in fillin(). Returns the number of pointers processed.
1813 */
1814 int Geom::CData::
1815complete_pointers(TypedWritable **p_list, BamReader *manager) {
1816 int pi = CycleData::complete_pointers(p_list, manager);
1817
1818 _data = DCAST(GeomVertexData, p_list[pi++]);
1819
1820 Primitives::iterator pri;
1821 for (pri = _primitives.begin(); pri != _primitives.end(); ++pri) {
1822 (*pri) = DCAST(GeomPrimitive, p_list[pi++]);
1823 }
1824
1825 return pi;
1826}
1827
1828/**
1829 * This internal function is called by make_from_bam to read in all of the
1830 * relevant data from the BamFile for the new Geom.
1831 */
1832 void Geom::CData::
1833fillin(DatagramIterator &scan, BamReader *manager) {
1834 manager->read_pointer(scan);
1835
1836 int num_primitives = scan.get_uint16();
1837 _primitives.reserve(num_primitives);
1838 for (int i = 0; i < num_primitives; ++i) {
1839 manager->read_pointer(scan);
1840 _primitives.push_back(nullptr);
1841 }
1842
1843 _primitive_type = (PrimitiveType)scan.get_uint8();
1844 _shade_model = (ShadeModel)scan.get_uint8();
1845
1846 // To be removed: we no longer read _geom_rendering from the bam file;
1847 // instead, we rederive it in finalize().
1848 scan.get_uint16();
1849
1850 _modified = Geom::get_next_modified();
1851
1852 _bounds_type = BoundingVolume::BT_default;
1853 if (manager->get_file_minor_ver() >= 19) {
1854 _bounds_type = (BoundingVolume::BoundsType)scan.get_uint8();
1855 }
1856}
1857
1858/**
1859 *
1860 */
1861 bool GeomPipelineReader::
1862check_valid(const GeomVertexDataPipelineReader *data_reader) const {
1863 Geom::Primitives::const_iterator pi;
1864 for (pi = _cdata->_primitives.begin();
1865 pi != _cdata->_primitives.end();
1866 ++pi) {
1867 GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread);
1868 reader.check_minmax();
1869 if (!reader.check_valid(data_reader)) {
1870 return false;
1871 }
1872 }
1873
1874 return true;
1875}
1876
1877/**
1878 * The implementation of Geom::draw().
1879 */
1880 bool GeomPipelineReader::
1881 draw(GraphicsStateGuardianBase *gsg,
1882 const GeomVertexDataPipelineReader *data_reader, bool force) const {
1883 bool all_ok;
1884 {
1885 PStatTimer timer(Geom::_draw_primitive_setup_pcollector);
1886 all_ok = gsg->begin_draw_primitives(this, data_reader, force);
1887 }
1888 if (all_ok) {
1889 Geom::Primitives::const_iterator pi;
1890 for (pi = _cdata->_primitives.begin();
1891 pi != _cdata->_primitives.end();
1892 ++pi) {
1893 GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread);
1894 if (reader.get_num_vertices() != 0) {
1895 reader.check_minmax();
1896 nassertr(reader.check_valid(data_reader), false);
1897 if (!reader.draw(gsg, force)) {
1898 all_ok = false;
1899 }
1900 }
1901 }
1902 gsg->end_draw_primitives();
1903 }
1904
1905 return all_ok;
1906}
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
parse_params
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
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
boundingBox.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
boundingSphere.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition bamReader.h:110
BamReader::register_finalize
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
BamReader::read_pointer
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition bamReader.cxx:610
BamReader::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition bamReader.I:83
BamReader::read_cdata
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
Definition bamReader.cxx:695
BamReader::get_factory
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition bamReader.I:177
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition bamWriter.h:63
BamWriter::write_cdata
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
Definition bamWriter.cxx:425
BamWriter::write_pointer
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
BoundingVolume
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
Definition boundingVolume.h:41
CopyOnWriteObject
This base class provides basic reference counting, but also can be used with a CopyOnWritePointer to ...
Definition copyOnWriteObject.h:41
CycleData
A single page of data maintained by a PipelineCycler.
Definition cycleData.h:50
CycleData::complete_pointers
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
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition datagramIterator.h:30
DatagramIterator::get_uint8
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
Definition datagramIterator.I:72
DatagramIterator::get_uint16
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
Definition datagramIterator.I:145
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
Datagram::add_uint8
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition datagram.I:50
Datagram::add_uint16
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition datagram.I:85
FactoryParams
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition factoryParams.h:36
Factory::register_factory
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
GeomPipelineReader::draw
bool draw(GraphicsStateGuardianBase *gsg, const GeomVertexDataPipelineReader *data_reader, bool force) const
The implementation of Geom::draw().
Definition geom.cxx:1881
GeomPrimitivePipelineReader
Encapsulates the data from a GeomPrimitive, pre-fetched for one stage of the pipeline.
Definition geomPrimitive.h:352
GeomPrimitivePipelineReader::check_minmax
void check_minmax() const
Ensures that the primitive's minmax cache has been computed.
Definition geomPrimitive.cxx:2267
GeomPrimitive
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition geomPrimitive.h:56
GeomPrimitive::get_ends
CPTA_int get_ends() const
Returns a const pointer to the primitive ends array so application code can read it directly.
Definition geomPrimitive.I:314
GeomPrimitive::get_num_vertices
get_num_vertices
Returns the number of indices used by all the primitives in this object.
Definition geomPrimitive.h:99
GeomPrimitive::check_valid
bool check_valid(const GeomVertexData *vertex_data) const
Verifies that the primitive only references vertices that actually exist within the indicated GeomVer...
Definition geomPrimitive.I:224
GeomPrimitive::is_composite
bool is_composite() const
Returns true if the primitive is a composite primitive such as a tristrip or trifan,...
Definition geomPrimitive.I:74
GeomPrimitive::match_shade_model
ConstPointerTo< GeomPrimitive > match_shade_model(ShadeModel shade_model) const
Returns a new primitive that is compatible with the indicated shade model, if possible,...
Definition geomPrimitive.cxx:949
GeomPrimitive::set_shade_model
void set_shade_model(ShadeModel shade_model)
Changes the ShadeModel hint for this primitive.
Definition geomPrimitive.I:36
GeomPrimitive::get_index_type
get_index_type
Returns the numeric type of the index column.
Definition geomPrimitive.h:85
GeomPrimitive::get_num_unused_vertices_per_primitive
get_num_unused_vertices_per_primitive
Returns the number of vertices that are added between primitives that aren't, strictly speaking,...
Definition geomPrimitive.h:196
GeomPrimitive::decompose
ConstPointerTo< GeomPrimitive > decompose() const
Decomposes a complex primitive type into a simpler primitive type, for instance triangle strips to tr...
Definition geomPrimitive.cxx:845
GeomPrimitive::set_index_type
void set_index_type(NumericType index_type)
Changes the numeric type of the index column.
Definition geomPrimitive.cxx:142
GeomPrimitive::get_num_vertices_per_primitive
get_num_vertices_per_primitive
If the primitive type is a simple type in which all primitives have the same number of vertices,...
Definition geomPrimitive.h:194
GeomPrimitive::modify_ends
PTA_int modify_ends()
Returns a modifiable pointer to the primitive ends array, so application code can directly fiddle wit...
Definition geomPrimitive.cxx:1310
GeomPrimitive::clear_minmax
void clear_minmax()
Undoes a previous call to set_minmax(), and allows the minimum and maximum values to be recomputed no...
Definition geomPrimitive.cxx:1386
GeomPrimitive::is_indexed
bool is_indexed() const
Returns true if the primitive is indexed, false otherwise.
Definition geomPrimitive.I:86
GeomPrimitive::modify_vertices
PointerTo< GeomVertexArrayData > modify_vertices(int num_vertices=-1)
Returns a modifiable pointer to the vertex index list, so application code can directly fiddle with t...
Definition geomPrimitive.cxx:1229
GeomVertexArrayDataHandle
This data object is returned by GeomVertexArrayData::get_handle() or modify_handle().
Definition geomVertexArrayData.h:250
GeomVertexArrayDataHandle::get_write_pointer
unsigned char * get_write_pointer()
Returns a writable pointer to the beginning of the actual data stream.
Definition geomVertexArrayData.cxx:614
GeomVertexDataPipelineReader
Encapsulates the data from a GeomVertexData, pre-fetched for one stage of the pipeline.
Definition geomVertexData.h:442
GeomVertexData
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
Definition geomVertexData.h:68
GeomVertexFormat
This class defines the physical layout of the vertex data stored within a Geom.
Definition geomVertexFormat.h:55
GeomVertexRewriter
This object provides the functionality of both a GeomVertexReader and a GeomVertexWriter,...
Definition geomVertexRewriter.h:33
Geom::CacheEntry
Definition geom.h:269
Geom::CacheEntry::evict_callback
virtual void evict_callback()
Called when the entry is evicted from the cache, this should clean up the owning object appropriately...
Definition geom.cxx:1760
Geom
A container for geometry primitives.
Definition geom.h:54
Geom::clear_cache
void clear_cache()
Removes all of the previously-cached results of munge_geom().
Definition geom.cxx:1199
Geom::decompose_in_place
void decompose_in_place()
Decomposes all of the primitives within this Geom, leaving the results in place.
Definition geom.cxx:446
Geom::request_resident
bool request_resident() const
Returns true if all the primitive arrays are currently resident in memory.
Definition geom.cxx:1016
Geom::prepare
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:1239
Geom::insert_primitive
insert_primitive
Inserts a new GeomPrimitive structure to the Geom object.
Definition geom.h:101
Geom::get_nested_vertices
int get_nested_vertices(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of vertices rendered by all primitives within the Geom.
Definition geom.cxx:1119
Geom::release_all
int release_all()
Frees the context allocated on all objects for which the geom has been declared.
Definition geom.cxx:1280
Geom::reverse_in_place
void reverse_in_place()
Reverses all of the primitives within this Geom, leaving the results in place.
Definition geom.cxx:520
Geom::draw
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:1338
Geom::offset_vertices
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
Geom::make_patches_in_place
void make_patches_in_place()
Replaces the GeomPrimitives within this Geom with corresponding GeomPatches.
Definition geom.cxx:869
Geom::copy_primitives_from
virtual bool copy_primitives_from(const Geom *other)
Copies the primitives from the indicated Geom into this one.
Definition geom.cxx:954
Geom::clear_primitives
void clear_primitives()
Removes all the primitives from the Geom object (but keeps the same table of vertices).
Definition geom.cxx:427
Geom::release
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the geom context only on the indicated object, if it exists there.
Definition geom.cxx:1262
Geom::make_nonindexed
int make_nonindexed(bool composite_only)
Converts the geom from indexed to nonindexed by duplicating vertices as necessary.
Definition geom.cxx:234
Geom::doubleside_in_place
void doubleside_in_place()
Doublesides all of the primitives within this Geom, leaving the results in place.
Definition geom.cxx:483
Geom::get_animated_vertex_data
ConstPointerTo< GeomVertexData > get_animated_vertex_data(bool force, Thread *current_thread=Thread::get_current_thread()) const
Returns a GeomVertexData that represents the results of computing the vertex animation on the CPU for...
Definition geom.cxx:307
Geom::check_valid
bool check_valid() const
Verifies that the all of the primitives within the geom reference vertices that actually exist within...
Definition geom.cxx:1074
Geom::remove_primitive
remove_primitive
Removes the ith primitive from the list.
Definition geom.h:101
Geom::add_primitive
void add_primitive(const GeomPrimitive *primitive)
Inserts a new GeomPrimitive structure to the Geom object.
Definition geom.I:116
Geom::clear_cache_stage
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
Geom::prepare_now
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:1314
Geom::operator=
void operator=(const Geom &copy)
The copy assignment operator is not pipeline-safe.
Definition geom.cxx:71
Geom::make_points_in_place
void make_points_in_place()
Replaces the GeomPrimitives within this Geom with corresponding GeomPoints.
Definition geom.cxx:828
Geom::rotate_in_place
void rotate_in_place()
Rotates all of the primitives within this Geom, leaving the results in place.
Definition geom.cxx:557
Geom::make_lines_in_place
void make_lines_in_place()
Replaces the GeomPrimitives within this Geom with corresponding GeomLines, representing a wireframe o...
Definition geom.cxx:786
Geom::unify_in_place
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
Geom::write_datagram
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:1684
Geom::finalize
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:1714
Geom::get_shade_model
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
Geom::register_with_read_factory
static void register_with_read_factory()
Tells the BamReader how to create objects of type Geom.
Definition geom.cxx:1675
Geom::get_next_modified
static UpdateSeq get_next_modified()
Returns a monotonically increasing sequence.
Definition geom.cxx:1356
Geom::is_prepared
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:1248
Geom::make_adjacency_in_place
void make_adjacency_in_place()
Replaces the GeomPrimitives within this Geom with corresponding versions with adjacency information.
Definition geom.cxx:912
Geom::get_num_bytes
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
Geom::transform_vertices
void transform_vertices(const LMatrix4 &mat)
Applies the indicated transform to all of the vertices in the Geom.
Definition geom.cxx:1045
Geom::make_copy
virtual Geom * make_copy() const
Returns a newly-allocated Geom that is a shallow copy of this one.
Definition geom.cxx:100
Geom::set_primitive
set_primitive
Replaces the ith GeomPrimitive object stored within the Geom with the new object.
Definition geom.h:101
Geom::set_vertex_data
void set_vertex_data(const GeomVertexData *data)
Replaces the Geom's underlying vertex data table with a completely new table.
Definition geom.cxx:171
Geom::set_usage_hint
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
Geom::get_primitive_type
get_primitive_type
Returns the fundamental primitive type that is common to all GeomPrimitives added within the Geom.
Definition geom.h:74
Geom::modify_vertex_data
PointerTo< GeomVertexData > modify_vertex_data()
Returns a modifiable pointer to the GeomVertexData, so that application code may directly maniuplate ...
Definition geom.cxx:152
Geom::get_bounds
ConstPointerTo< BoundingVolume > get_bounds(Thread *current_thread=Thread::get_current_thread()) const
Returns the bounding volume for the Geom.
Definition geom.cxx:1101
Geom::get_usage_hint
UsageHint get_usage_hint() const
Returns the minimum (i.e.
Definition geom.cxx:110
GraphicsStateGuardianBase
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Definition graphicsStateGuardianBase.h:110
InternalName
Encodes a string name in a hash table, mapping it to a pointer.
Definition internalName.h:38
LightMutexHolder
Similar to MutexHolder, but for a light mutex.
Definition lightMutexHolder.h:25
PStatCollector
A lightweight class that represents a single element that may be timed and/or counted via stats.
Definition pStatCollector.h:43
PStatTimer
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition pStatTimer.h:30
PreparedGraphicsObjects
A table of objects that are saved within the graphics context for reference by handle later.
Definition preparedGraphicsObjects.h:58
PreparedGraphicsObjects::release_geom
void release_geom(GeomContext *gc)
Indicates that a geom context, created by a previous call to prepare_geom(), is no longer needed.
Definition preparedGraphicsObjects.cxx:604
PreparedGraphicsObjects::is_geom_queued
bool is_geom_queued(const Geom *geom) const
Returns true if the geom has been queued on this GSG, false otherwise.
Definition preparedGraphicsObjects.cxx:557
PreparedGraphicsObjects::prepare_geom_now
GeomContext * prepare_geom_now(Geom *geom, GraphicsStateGuardianBase *gsg)
Immediately creates a new GeomContext for the indicated geom and returns it.
Definition preparedGraphicsObjects.cxx:681
PreparedGraphicsObjects::dequeue_geom
bool dequeue_geom(Geom *geom)
Removes a geom from the queued list of geoms to be prepared.
Definition preparedGraphicsObjects.cxx:574
PreparedGraphicsObjects::enqueue_geom
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...
Definition preparedGraphicsObjects.cxx:547
Thread
A thread; that is, a lightweight process.
Definition thread.h:46
Thread::get_current_thread
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition thread.h:109
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition typedWritable.h:35
TypedWritable::fillin
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...
Definition typedWritable.cxx:103
TypedWritable::write_datagram
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 typedWritable.cxx:54
UpdateSeq
This is a sequence number that increments monotonically.
Definition updateSeq.h:37
vector
STL class.
config_mathutil.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomPoints.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomVertexReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomVertexRewriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geom.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
graphicsStateGuardianBase.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
lightMutexHolder.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pStatTimer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
preparedGraphicsObjects.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.