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 
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  */
44 make_cow_copy() {
45  return make_copy();
46 }
47 
48 /**
49  *
50  */
51 Geom::
52 Geom(const GeomVertexData *data) : _cycler(CData((GeomVertexData *)data)) {
53 }
54 
55 /**
56  * Use make_copy() to duplicate a Geom.
57  */
58 Geom::
59 Geom(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  */
88 Geom::
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  */
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  */
109 Geom::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  */
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  */
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  */
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::
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::
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::
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::
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::
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::
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::
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::
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  */
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  */
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  */
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  */
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  */
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  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  */
1132 void Geom::
1133 output(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  */
1159 void Geom::
1160 write(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  */
1179 void Geom::
1180 clear_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  */
1199 clear_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  */
1220 prepare(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  */
1229 is_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  */
1243 release(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  */
1261 release_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  */
1295 prepare_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  */
1319 draw(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  */
1346 void Geom::
1347 compute_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  */
1474 void Geom::
1475 do_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  */
1495 void Geom::
1496 do_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  */
1515 void Geom::
1516 clear_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  */
1534 bool Geom::
1535 check_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  */
1560 void Geom::
1561 reset_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  */
1601 void Geom::
1602 combine_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  */
1665 write_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  */
1676 TypedWritable *Geom::
1677 make_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  */
1695 finalize(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  */
1713 void Geom::
1714 fillin(DatagramIterator &scan, BamReader *manager) {
1715  TypedWritable::fillin(scan, manager);
1716 
1717  manager->read_cdata(scan, _cycler);
1718 }
1719 
1720 /**
1721  *
1722  */
1723 Geom::CDataCache::
1724 ~CDataCache() {
1725  set_result(nullptr, nullptr);
1726 }
1727 
1728 /**
1729  *
1730  */
1731 CycleData *Geom::CDataCache::
1732 make_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  */
1741 evict_callback() {
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  */
1752 void Geom::CacheEntry::
1753 output(std::ostream &out) const {
1754  out << "geom " << (void *)_source << ", "
1755  << (const void *)_key._modifier;
1756 }
1757 
1758 
1759 /**
1760  *
1761  */
1762 CycleData *Geom::CData::
1763 make_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  */
1771 void Geom::CData::
1772 write_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  */
1795 int Geom::CData::
1796 complete_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  */
1813 void Geom::CData::
1814 fillin(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  */
1842 bool GeomPipelineReader::
1843 check_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.