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  cdata->_modified = Geom::get_next_modified();
809  reset_geom_rendering(cdata);
810  clear_cache_stage(current_thread);
811 
812  nassertv(all_is_valid);
813 }
814 
815 /**
816  * Replaces the GeomPrimitives within this Geom with corresponding GeomPoints.
817  * See GeomPrimitive::make_points().
818  *
819  * Don't call this in a downstream thread unless you don't mind it blowing
820  * away other changes you might have recently made in an upstream thread.
821  */
822 void Geom::
824  Thread *current_thread = Thread::get_current_thread();
825  CDWriter cdata(_cycler, true, current_thread);
826 
827 #ifndef NDEBUG
828  GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
829  data_reader.check_array_readers();
830 
831  bool all_is_valid = true;
832 #endif
833  Primitives::iterator pi;
834  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
835  CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_points();
836  (*pi) = (GeomPrimitive *)new_prim.p();
837 
838 #ifndef NDEBUG
839  if (!new_prim->check_valid(&data_reader)) {
840  all_is_valid = false;
841  }
842 #endif
843  }
844 
845  cdata->_modified = Geom::get_next_modified();
846  reset_geom_rendering(cdata);
847  clear_cache_stage(current_thread);
848 
849  nassertv(all_is_valid);
850 }
851 
852 /**
853  * Replaces the GeomPrimitives within this Geom with corresponding
854  * GeomPatches. See GeomPrimitive::make_patches().
855  *
856  * Don't call this in a downstream thread unless you don't mind it blowing
857  * away other changes you might have recently made in an upstream thread.
858  */
859 void Geom::
861  Thread *current_thread = Thread::get_current_thread();
862  CDWriter cdata(_cycler, true, current_thread);
863 
864 #ifndef NDEBUG
865  GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
866  data_reader.check_array_readers();
867 
868  bool all_is_valid = true;
869 #endif
870  Primitives::iterator pi;
871  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
872  CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_patches();
873  (*pi) = (GeomPrimitive *)new_prim.p();
874 
875 #ifndef NDEBUG
876  if (!new_prim->check_valid(&data_reader)) {
877  all_is_valid = false;
878  }
879 #endif
880  }
881 
882  cdata->_modified = Geom::get_next_modified();
883  reset_geom_rendering(cdata);
884  clear_cache_stage(current_thread);
885 
886  nassertv(all_is_valid);
887 }
888 
889 /**
890  * Replaces the GeomPrimitives within this Geom with corresponding versions
891  * with adjacency information. See GeomPrimitive::make_adjacency().
892  *
893  * Don't call this in a downstream thread unless you don't mind it blowing
894  * away other changes you might have recently made in an upstream thread.
895  *
896  * @since 1.10.0
897  */
898 void Geom::
900  Thread *current_thread = Thread::get_current_thread();
901  CDWriter cdata(_cycler, true, current_thread);
902 
903 #ifndef NDEBUG
904  GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
905  data_reader.check_array_readers();
906 
907  bool all_is_valid = true;
908 #endif
909  Primitives::iterator pi;
910  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
911  CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_adjacency();
912  if (new_prim != nullptr) {
913  (*pi) = (GeomPrimitive *)new_prim.p();
914 
915 #ifndef NDEBUG
916  if (!new_prim->check_valid(&data_reader)) {
917  all_is_valid = false;
918  }
919 #endif
920  }
921  }
922 
923  cdata->_modified = Geom::get_next_modified();
924  reset_geom_rendering(cdata);
925  clear_cache_stage(current_thread);
926 
927  nassertv(all_is_valid);
928 }
929 
930 /**
931  * Copies the primitives from the indicated Geom into this one. This does
932  * require that both Geoms contain the same fundamental type primitives, both
933  * have a compatible shade model, and both use the same GeomVertexData. Both
934  * Geoms must also be the same specific class type (i.e. if one is a
935  * GeomTextGlyph, they both must be.)
936  *
937  * Returns true if the copy is successful, or false otherwise (because the
938  * Geoms were mismatched).
939  */
940 bool Geom::
941 copy_primitives_from(const Geom *other) {
942  if (get_primitive_type() != PT_none &&
943  other->get_primitive_type() != get_primitive_type()) {
944  return false;
945  }
946  if (get_vertex_data() != other->get_vertex_data()) {
947  return false;
948  }
949  if (get_type() != other->get_type()) {
950  return false;
951  }
952 
953  ShadeModel this_shade_model = get_shade_model();
954  ShadeModel other_shade_model = other->get_shade_model();
955  if (this_shade_model != SM_uniform && other_shade_model != SM_uniform &&
956  this_shade_model != other_shade_model) {
957  if ((this_shade_model == SM_flat_first_vertex && other_shade_model == SM_flat_last_vertex) ||
958  (this_shade_model == SM_flat_last_vertex && other_shade_model == SM_flat_first_vertex)) {
959  // This is acceptable; we can rotate the primitives to match.
960 
961  } else {
962  // Otherwise, we have incompatible shade models.
963  return false;
964  }
965  }
966 
967  int num_primitives = other->get_num_primitives();
968  for (int i = 0; i < num_primitives; i++) {
969  add_primitive(other->get_primitive(i));
970  }
971 
972  return true;
973 }
974 
975 /**
976  * Returns the number of bytes consumed by the geom and its primitives (but
977  * not including its vertex table).
978  */
979 int Geom::
980 get_num_bytes() const {
981  CDReader cdata(_cycler);
982 
983  int num_bytes = sizeof(Geom);
984  Primitives::const_iterator pi;
985  for (pi = cdata->_primitives.begin();
986  pi != cdata->_primitives.end();
987  ++pi) {
988  num_bytes += (*pi).get_read_pointer()->get_num_bytes();
989  }
990 
991  return num_bytes;
992 }
993 
994 /**
995  * Returns true if all the primitive arrays are currently resident in memory.
996  * If this returns false, the data will be brought back into memory shortly;
997  * try again later.
998  *
999  * This does not also test the Geom's associated GeomVertexData. That must be
1000  * tested separately.
1001  */
1003 request_resident() const {
1004  Thread *current_thread = Thread::get_current_thread();
1005 
1006  CDReader cdata(_cycler, current_thread);
1007 
1008  bool resident = true;
1009 
1010  Primitives::const_iterator pi;
1011  for (pi = cdata->_primitives.begin();
1012  pi != cdata->_primitives.end();
1013  ++pi) {
1014  if (!(*pi).get_read_pointer(current_thread)->request_resident()) {
1015  resident = false;
1016  }
1017  }
1018 
1019  return resident;
1020 }
1021 
1022 /**
1023  * Applies the indicated transform to all of the vertices in the Geom. If the
1024  * Geom happens to share a vertex table with another Geom, this operation will
1025  * duplicate the vertex table instead of breaking the other Geom; however, if
1026  * multiple Geoms with shared tables are transformed by the same matrix, they
1027  * will no longer share tables after the operation. Consider using the
1028  * GeomTransformer if you will be applying the same transform to multiple
1029  * Geoms.
1030  */
1032 transform_vertices(const LMatrix4 &mat) {
1033  PT(GeomVertexData) new_data = modify_vertex_data();
1034  CPT(GeomVertexFormat) format = new_data->get_format();
1035 
1036  size_t ci;
1037  for (ci = 0; ci < format->get_num_points(); ci++) {
1038  GeomVertexRewriter data(new_data, format->get_point(ci));
1039 
1040  while (!data.is_at_end()) {
1041  const LPoint3 &point = data.get_data3();
1042  data.set_data3(point * mat);
1043  }
1044  }
1045  for (ci = 0; ci < format->get_num_vectors(); ci++) {
1046  GeomVertexRewriter data(new_data, format->get_vector(ci));
1047 
1048  while (!data.is_at_end()) {
1049  const LVector3 &vector = data.get_data3();
1050  data.set_data3(normalize(vector * mat));
1051  }
1052  }
1053 }
1054 
1055 /**
1056  * Verifies that the all of the primitives within the geom reference vertices
1057  * that actually exist within the geom's GeomVertexData. Returns true if the
1058  * geom appears to be valid, false otherwise.
1059  */
1061 check_valid() const {
1062  Thread *current_thread = Thread::get_current_thread();
1063  GeomPipelineReader geom_reader(this, current_thread);
1064  CPT(GeomVertexData) vertex_data = geom_reader.get_vertex_data();
1065  GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1066  data_reader.check_array_readers();
1067  return geom_reader.check_valid(&data_reader);
1068 }
1069 
1070 /**
1071  * Verifies that the all of the primitives within the geom reference vertices
1072  * that actually exist within the indicated GeomVertexData. Returns true if
1073  * the geom appears to be valid, false otherwise.
1074  */
1076 check_valid(const GeomVertexData *vertex_data) const {
1077  Thread *current_thread = Thread::get_current_thread();
1078  GeomPipelineReader geom_reader(this, current_thread);
1079  GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1080  data_reader.check_array_readers();
1081  return geom_reader.check_valid(&data_reader);
1082 }
1083 
1084 /**
1085  * Returns the bounding volume for the Geom.
1086  */
1088 get_bounds(Thread *current_thread) const {
1089  CDLockedReader cdata(_cycler, current_thread);
1090  if (cdata->_user_bounds != nullptr) {
1091  return cdata->_user_bounds;
1092  }
1093 
1094  if (cdata->_internal_bounds_stale) {
1095  CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
1096  compute_internal_bounds(cdataw, current_thread);
1097  return cdataw->_internal_bounds;
1098  }
1099  return cdata->_internal_bounds;
1100 }
1101 
1102 /**
1103  * Returns the number of vertices rendered by all primitives within the Geom.
1104  */
1105 int Geom::
1106 get_nested_vertices(Thread *current_thread) const {
1107  CDLockedReader cdata(_cycler, current_thread);
1108  if (cdata->_internal_bounds_stale) {
1109  CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
1110  compute_internal_bounds(cdataw, current_thread);
1111  return cdataw->_nested_vertices;
1112  }
1113  return cdata->_nested_vertices;
1114 }
1115 
1116 /**
1117  *
1118  */
1119 void Geom::
1120 output(std::ostream &out) const {
1121  CDReader cdata(_cycler);
1122 
1123  // Get a list of the primitive types contained within this object.
1124  int num_faces = 0;
1125  pset<TypeHandle> types;
1126  Primitives::const_iterator pi;
1127  for (pi = cdata->_primitives.begin();
1128  pi != cdata->_primitives.end();
1129  ++pi) {
1130  CPT(GeomPrimitive) prim = (*pi).get_read_pointer();
1131  num_faces += prim->get_num_faces();
1132  types.insert(prim->get_type());
1133  }
1134 
1135  out << get_type() << " [";
1137  for (ti = types.begin(); ti != types.end(); ++ti) {
1138  out << " " << (*ti);
1139  }
1140  out << " ], " << num_faces << " faces";
1141 }
1142 
1143 /**
1144  *
1145  */
1146 void Geom::
1147 write(std::ostream &out, int indent_level) const {
1148  CDReader cdata(_cycler);
1149 
1150  // Get a list of the primitive types contained within this object.
1151  Primitives::const_iterator pi;
1152  for (pi = cdata->_primitives.begin();
1153  pi != cdata->_primitives.end();
1154  ++pi) {
1155  (*pi).get_read_pointer()->write(out, indent_level);
1156  }
1157 }
1158 
1159 /**
1160  * Removes all of the previously-cached results of munge_geom().
1161  *
1162  * This blows away the entire cache, upstream and downstream the pipeline.
1163  * Use clear_cache_stage() instead if you only want to blow away the cache at
1164  * the current stage and upstream.
1165  */
1166 void Geom::
1167 clear_cache() {
1168  LightMutexHolder holder(_cache_lock);
1169  for (Cache::iterator ci = _cache.begin();
1170  ci != _cache.end();
1171  ++ci) {
1172  CacheEntry *entry = (*ci).second;
1173  entry->erase();
1174  }
1175  _cache.clear();
1176 }
1177 
1178 /**
1179  * Removes all of the previously-cached results of munge_geom(), at the
1180  * current pipeline stage and upstream. Does not affect the downstream cache.
1181  *
1182  * Don't call this in a downstream thread unless you don't mind it blowing
1183  * away other changes you might have recently made in an upstream thread.
1184  */
1186 clear_cache_stage(Thread *current_thread) {
1187  LightMutexHolder holder(_cache_lock);
1188  for (Cache::iterator ci = _cache.begin();
1189  ci != _cache.end();
1190  ++ci) {
1191  CacheEntry *entry = (*ci).second;
1192  CDCacheWriter cdata(entry->_cycler, current_thread);
1193  cdata->set_result(nullptr, nullptr);
1194  }
1195 }
1196 
1197 /**
1198  * Indicates that the geom should be enqueued to be prepared in the indicated
1199  * prepared_objects at the beginning of the next frame. This will ensure the
1200  * geom is already loaded into geom memory if it is expected to be rendered
1201  * soon.
1202  *
1203  * Use this function instead of prepare_now() to preload geoms from a user
1204  * interface standpoint.
1205  */
1207 prepare(PreparedGraphicsObjects *prepared_objects) {
1208  prepared_objects->enqueue_geom(this);
1209 }
1210 
1211 /**
1212  * Returns true if the geom has already been prepared or enqueued for
1213  * preparation on the indicated GSG, false otherwise.
1214  */
1216 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
1217  Contexts::const_iterator ci;
1218  ci = _contexts.find(prepared_objects);
1219  if (ci != _contexts.end()) {
1220  return true;
1221  }
1222  return prepared_objects->is_geom_queued(this);
1223 }
1224 
1225 /**
1226  * Frees the geom context only on the indicated object, if it exists there.
1227  * Returns true if it was released, false if it had not been prepared.
1228  */
1230 release(PreparedGraphicsObjects *prepared_objects) {
1231  Contexts::iterator ci;
1232  ci = _contexts.find(prepared_objects);
1233  if (ci != _contexts.end()) {
1234  GeomContext *gc = (*ci).second;
1235  prepared_objects->release_geom(gc);
1236  return true;
1237  }
1238 
1239  // Maybe it wasn't prepared yet, but it's about to be.
1240  return prepared_objects->dequeue_geom(this);
1241 }
1242 
1243 /**
1244  * Frees the context allocated on all objects for which the geom has been
1245  * declared. Returns the number of contexts which have been freed.
1246  */
1248 release_all() {
1249  // We have to traverse a copy of the _contexts list, because the
1250  // PreparedGraphicsObjects object will call clear_prepared() in response to
1251  // each release_geom(), and we don't want to be modifying the _contexts list
1252  // while we're traversing it.
1253  Contexts temp = _contexts;
1254  int num_freed = (int)_contexts.size();
1255 
1256  Contexts::const_iterator ci;
1257  for (ci = temp.begin(); ci != temp.end(); ++ci) {
1258  PreparedGraphicsObjects *prepared_objects = (*ci).first;
1259  GeomContext *gc = (*ci).second;
1260  prepared_objects->release_geom(gc);
1261  }
1262 
1263  // Now that we've called release_geom() on every known context, the
1264  // _contexts list should have completely emptied itself.
1265  nassertr(_contexts.empty(), num_freed);
1266 
1267  return num_freed;
1268 }
1269 
1270 /**
1271  * Creates a context for the geom on the particular GSG, if it does not
1272  * already exist. Returns the new (or old) GeomContext. This assumes that
1273  * the GraphicsStateGuardian is the currently active rendering context and
1274  * that it is ready to accept new geoms. If this is not necessarily the case,
1275  * you should use prepare() instead.
1276  *
1277  * Normally, this is not called directly except by the GraphicsStateGuardian;
1278  * a geom does not need to be explicitly prepared by the user before it may be
1279  * rendered.
1280  */
1282 prepare_now(PreparedGraphicsObjects *prepared_objects,
1284  Contexts::const_iterator ci;
1285  ci = _contexts.find(prepared_objects);
1286  if (ci != _contexts.end()) {
1287  return (*ci).second;
1288  }
1289 
1290  GeomContext *gc = prepared_objects->prepare_geom_now(this, gsg);
1291  if (gc != nullptr) {
1292  _contexts[prepared_objects] = gc;
1293  }
1294  return gc;
1295 }
1296 
1297 /**
1298  * Actually draws the Geom with the indicated GSG, using the indicated vertex
1299  * data (which might have been pre-munged to support the GSG's needs).
1300  *
1301  * Returns true if all of the primitives were drawn normally, false if there
1302  * was a problem (for instance, some of the data was nonresident). If force
1303  * is passed true, it will wait for the data to become resident if necessary.
1304  */
1306 draw(GraphicsStateGuardianBase *gsg, const GeomVertexData *vertex_data,
1307  bool force, Thread *current_thread) const {
1308  GeomPipelineReader geom_reader(this, current_thread);
1309  GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1310  data_reader.check_array_readers();
1311 
1312  return geom_reader.draw(gsg, &data_reader, force);
1313 }
1314 
1315 /**
1316  * Returns a monotonically increasing sequence. Each time this is called, a
1317  * new sequence number is returned, higher than the previous value.
1318  *
1319  * This is used to ensure that GeomVertexArrayData::get_modified() and
1320  * GeomPrimitive::get_modified() update from the same space, so that
1321  * Geom::get_modified() returns a meaningful value.
1322  */
1325  ++_next_modified;
1326  return _next_modified;
1327 }
1328 
1329 /**
1330  * Recomputes the dynamic bounding volume for this Geom. This includes all of
1331  * the vertices.
1332  */
1333 void Geom::
1334 compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
1335  int num_vertices = 0;
1336 
1337  // Get the vertex data, after animation.
1338  CPT(GeomVertexData) vertex_data = get_animated_vertex_data(true, current_thread);
1339 
1340  // Now actually compute the bounding volume. We do this by using
1341  // calc_tight_bounds to determine our box first.
1342  LPoint3 pmin, pmax;
1343  PN_stdfloat sq_center_dist = 0.0f;
1344  bool found_any = false;
1345  do_calc_tight_bounds(pmin, pmax, sq_center_dist, found_any,
1346  vertex_data, false, LMatrix4::ident_mat(),
1347  InternalName::get_vertex(),
1348  cdata, current_thread);
1349 
1350  BoundingVolume::BoundsType btype = cdata->_bounds_type;
1351  if (btype == BoundingVolume::BT_default) {
1352  btype = bounds_type;
1353  }
1354 
1355  if (found_any) {
1356  nassertv(!pmin.is_nan());
1357  nassertv(!pmax.is_nan());
1358 
1359  // Then we put the bounding volume around both of those points.
1360  PN_stdfloat avg_box_area;
1361  switch (btype) {
1362  case BoundingVolume::BT_best:
1363  case BoundingVolume::BT_fastest:
1364  case BoundingVolume::BT_default:
1365  {
1366  // When considering a box, calculate (roughly) the average area of the
1367  // sides. We will use this to determine whether a sphere or box is a
1368  // better fit.
1369  PN_stdfloat min_extent = min(pmax[0] - pmin[0],
1370  min(pmax[1] - pmin[1],
1371  pmax[2] - pmin[2]));
1372  PN_stdfloat max_extent = max(pmax[0] - pmin[0],
1373  max(pmax[1] - pmin[1],
1374  pmax[2] - pmin[2]));
1375  avg_box_area = ((min_extent * min_extent) + (max_extent * max_extent)) / 2;
1376  }
1377  // Fall through
1378  case BoundingVolume::BT_sphere:
1379  {
1380  // Determine the best radius for a bounding sphere.
1381  LPoint3 aabb_center = (pmin + pmax) * 0.5f;
1382  PN_stdfloat best_sq_radius = (pmax - aabb_center).length_squared();
1383 
1384  if (btype != BoundingVolume::BT_fastest && best_sq_radius > 0.0f &&
1385  aabb_center.length_squared() / best_sq_radius >= (0.2f * 0.2f)) {
1386  // Hmm, this is an off-center model. Maybe we can do a better job
1387  // by calculating the bounding sphere from the AABB center.
1388 
1389  PN_stdfloat better_sq_radius;
1390  bool found_any = false;
1391  do_calc_sphere_radius(aabb_center, better_sq_radius, found_any,
1392  vertex_data, cdata, current_thread);
1393 
1394  if (found_any && better_sq_radius > 0.0f &&
1395  better_sq_radius <= best_sq_radius) {
1396  // Great. This is as good a sphere as we're going to get.
1397  if (btype == BoundingVolume::BT_best &&
1398  avg_box_area < better_sq_radius * MathNumbers::pi) {
1399  // But the box is better, anyway. Use that instead.
1400  cdata->_internal_bounds = new BoundingBox(pmin, pmax);
1401  break;
1402  }
1403  cdata->_internal_bounds =
1404  new BoundingSphere(aabb_center, csqrt(better_sq_radius));
1405  break;
1406  }
1407  }
1408 
1409  if (btype != BoundingVolume::BT_sphere &&
1410  avg_box_area < sq_center_dist * MathNumbers::pi) {
1411  // A box is probably a tighter fit.
1412  cdata->_internal_bounds = new BoundingBox(pmin, pmax);
1413  break;
1414 
1415  } else if (sq_center_dist >= 0.0f && sq_center_dist <= best_sq_radius) {
1416  // No, but a sphere centered on the origin is apparently still
1417  // better than a sphere around the bounding box.
1418  cdata->_internal_bounds =
1419  new BoundingSphere(LPoint3::origin(), csqrt(sq_center_dist));
1420  break;
1421 
1422  } else if (btype == BoundingVolume::BT_sphere) {
1423  // This is the worst sphere we can make, which is why we will only
1424  // do it when the user specifically requests a sphere.
1425  cdata->_internal_bounds =
1426  new BoundingSphere(aabb_center,
1427  (best_sq_radius > 0.0f) ? csqrt(best_sq_radius) : 0.0f);
1428  break;
1429  }
1430  }
1431  // Fall through.
1432 
1433  case BoundingVolume::BT_box:
1434  cdata->_internal_bounds = new BoundingBox(pmin, pmax);
1435  }
1436 
1437  Primitives::const_iterator pi;
1438  for (pi = cdata->_primitives.begin();
1439  pi != cdata->_primitives.end();
1440  ++pi) {
1441  CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
1442  num_vertices += prim->get_num_vertices();
1443  }
1444 
1445  } else {
1446  // No points; empty bounding volume.
1447  if (btype == BoundingVolume::BT_sphere) {
1448  cdata->_internal_bounds = new BoundingSphere;
1449  } else {
1450  cdata->_internal_bounds = new BoundingBox;
1451  }
1452  }
1453 
1454  cdata->_nested_vertices = num_vertices;
1455  cdata->_internal_bounds_stale = false;
1456 }
1457 
1458 /**
1459  * The private implementation of calc_tight_bounds().
1460  */
1461 void Geom::
1462 do_calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
1463  PN_stdfloat &sq_center_dist, bool &found_any,
1464  const GeomVertexData *vertex_data,
1465  bool got_mat, const LMatrix4 &mat,
1466  const InternalName *column_name,
1467  const CData *cdata, Thread *current_thread) const {
1468  Primitives::const_iterator pi;
1469  for (pi = cdata->_primitives.begin();
1470  pi != cdata->_primitives.end();
1471  ++pi) {
1472  CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
1473  prim->calc_tight_bounds(min_point, max_point, sq_center_dist,
1474  found_any, vertex_data, got_mat, mat,
1475  column_name, current_thread);
1476  }
1477 }
1478 
1479 /**
1480  *
1481  */
1482 void Geom::
1483 do_calc_sphere_radius(const LPoint3 &center, PN_stdfloat &sq_radius,
1484  bool &found_any, const GeomVertexData *vertex_data,
1485  const CData *cdata, Thread *current_thread) const {
1486  Primitives::const_iterator pi;
1487  for (pi = cdata->_primitives.begin();
1488  pi != cdata->_primitives.end();
1489  ++pi) {
1490  CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
1491  prim->calc_sphere_radius(center, sq_radius, found_any,
1492  vertex_data, current_thread);
1493  }
1494 }
1495 
1496 /**
1497  * Removes the indicated PreparedGraphicsObjects table from the Geom's table,
1498  * without actually releasing the geom. This is intended to be called only
1499  * from PreparedGraphicsObjects::release_geom(); it should never be called by
1500  * user code.
1501  */
1502 void Geom::
1503 clear_prepared(PreparedGraphicsObjects *prepared_objects) {
1504  Contexts::iterator ci;
1505  ci = _contexts.find(prepared_objects);
1506  if (ci != _contexts.end()) {
1507  _contexts.erase(ci);
1508  } else {
1509  // If this assertion fails, clear_prepared() was given a prepared_objects
1510  // that the geom didn't know about.
1511  nassert_raise("unknown PreparedGraphicsObjects");
1512  }
1513 }
1514 
1515 /**
1516  * Verifies that the all of the primitives within the geom reference vertices
1517  * that actually exist within the indicated GeomVertexData (presumably in
1518  * preparation for assigning the geom to use this data). Returns true if the
1519  * data appears to be valid, false otherwise.
1520  */
1521 bool Geom::
1522 check_will_be_valid(const GeomVertexData *vertex_data) const {
1523  Thread *current_thread = Thread::get_current_thread();
1524 
1525  CDReader cdata(_cycler, current_thread);
1526 
1527  GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1528  data_reader.check_array_readers();
1529 
1530  Primitives::const_iterator pi;
1531  for (pi = cdata->_primitives.begin();
1532  pi != cdata->_primitives.end();
1533  ++pi) {
1534  GeomPrimitivePipelineReader reader((*pi).get_read_pointer(), current_thread);
1535  reader.check_minmax();
1536  if (!reader.check_valid(&data_reader)) {
1537  return false;
1538  }
1539  }
1540 
1541  return true;
1542 }
1543 
1544 /**
1545  * Rederives the _geom_rendering member.
1546  */
1547 void Geom::
1548 reset_geom_rendering(Geom::CData *cdata) {
1549  cdata->_geom_rendering = 0;
1550  Primitives::const_iterator pi;
1551  for (pi = cdata->_primitives.begin();
1552  pi != cdata->_primitives.end();
1553  ++pi) {
1554  cdata->_geom_rendering |= (*pi).get_read_pointer()->get_geom_rendering();
1555  }
1556 
1557  if ((cdata->_geom_rendering & GR_point) != 0) {
1558  CPT(GeomVertexData) data = cdata->_data.get_read_pointer();
1559  if (data->has_column(InternalName::get_size())) {
1560  cdata->_geom_rendering |= GR_per_point_size;
1561  }
1562  if (data->has_column(InternalName::get_aspect_ratio())) {
1563  cdata->_geom_rendering |= GR_point_aspect_ratio;
1564  }
1565  if (data->has_column(InternalName::get_rotate())) {
1566  cdata->_geom_rendering |= GR_point_rotate;
1567  }
1568  }
1569 
1570  switch (get_shade_model()) {
1571  case SM_flat_first_vertex:
1572  cdata->_geom_rendering |= GR_flat_first_vertex;
1573  break;
1574 
1575  case SM_flat_last_vertex:
1576  cdata->_geom_rendering |= GR_flat_last_vertex;
1577  break;
1578 
1579  default:
1580  break;
1581  }
1582 }
1583 
1584 /**
1585  * Combines two primitives of the same type into a single primitive. a_prim
1586  * is modified to append the vertices from b_prim, which is unmodified.
1587  */
1588 void Geom::
1589 combine_primitives(GeomPrimitive *a_prim, CPT(GeomPrimitive) b_prim,
1590  Thread *current_thread) {
1591  nassertv(a_prim != b_prim);
1592  nassertv(a_prim->get_type() == b_prim->get_type());
1593 
1594  if (a_prim->get_index_type() != b_prim->get_index_type()) {
1595  GeomPrimitive::NumericType index_type = max(a_prim->get_index_type(), b_prim->get_index_type());
1596  a_prim->set_index_type(index_type);
1597  if (b_prim->get_index_type() != index_type) {
1598  PT(GeomPrimitive) b_prim_copy = b_prim->make_copy();
1599  b_prim_copy->set_index_type(index_type);
1600  b_prim = b_prim_copy;
1601  }
1602  }
1603 
1604  if (!b_prim->is_indexed()) {
1605  PT(GeomPrimitive) b_prim_copy = b_prim->make_copy();
1606  b_prim_copy->make_indexed();
1607  b_prim = b_prim_copy;
1608  }
1609 
1610  PT(GeomVertexArrayData) a_vertices = a_prim->modify_vertices();
1611  CPT(GeomVertexArrayData) b_vertices = b_prim->get_vertices();
1612 
1613  if (a_prim->requires_unused_vertices()) {
1614  GeomVertexReader index(b_vertices, 0);
1615  int b_vertex = index.get_data1i();
1616  a_prim->append_unused_vertices(a_vertices, b_vertex);
1617  }
1618 
1619  PT(GeomVertexArrayDataHandle) a_handle =
1620  new GeomVertexArrayDataHandle(std::move(a_vertices), current_thread);
1621  CPT(GeomVertexArrayDataHandle) b_handle =
1622  new GeomVertexArrayDataHandle(std::move(b_vertices), current_thread);
1623 
1624  size_t orig_a_vertices = a_handle->get_num_rows();
1625 
1626  a_handle->copy_subdata_from(a_handle->get_data_size_bytes(), 0,
1627  b_handle, 0, b_handle->get_data_size_bytes());
1628  a_prim->clear_minmax();
1629  if (a_prim->is_composite()) {
1630  // Also copy the ends array.
1631  PTA_int a_ends = a_prim->modify_ends();
1632  CPTA_int b_ends = b_prim->get_ends();
1633  for (size_t i = 0; i < b_ends.size(); ++i) {
1634  a_ends.push_back(b_ends[i] + orig_a_vertices);
1635  }
1636  }
1637 }
1638 
1639 /**
1640  * Tells the BamReader how to create objects of type Geom.
1641  */
1644  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
1645 }
1646 
1647 /**
1648  * Writes the contents of this object to the datagram for shipping out to a
1649  * Bam file.
1650  */
1652 write_datagram(BamWriter *manager, Datagram &dg) {
1653  TypedWritable::write_datagram(manager, dg);
1654 
1655  manager->write_cdata(dg, _cycler);
1656 }
1657 
1658 /**
1659  * This function is called by the BamReader's factory when a new object of
1660  * type Geom is encountered in the Bam file. It should create the Geom and
1661  * extract its information from the file.
1662  */
1663 TypedWritable *Geom::
1664 make_from_bam(const FactoryParams &params) {
1665  Geom *object = new Geom(nullptr);
1666  DatagramIterator scan;
1667  BamReader *manager;
1668 
1669  parse_params(params, scan, manager);
1670  object->fillin(scan, manager);
1671  manager->register_finalize(object);
1672 
1673  return object;
1674 }
1675 
1676 /**
1677  * Called by the BamReader to perform any final actions needed for setting up
1678  * the object after all objects have been read and all pointers have been
1679  * completed.
1680  */
1682 finalize(BamReader *manager) {
1683  CDWriter cdata(_cycler, true);
1684 
1685  // Make sure our GeomVertexData is finalized first. This may result in the
1686  // data getting finalized multiple times, but it doesn't mind that.
1687  if (!cdata->_data.is_null()) {
1688  // We shouldn't call get_write_pointer(), which might replicate the
1689  // GeomVertexData unnecessarily.
1690  cdata->_data.get_unsafe_pointer()->finalize(manager);
1691  }
1692 
1693  reset_geom_rendering(cdata);
1694 }
1695 
1696 /**
1697  * This internal function is called by make_from_bam to read in all of the
1698  * relevant data from the BamFile for the new Geom.
1699  */
1700 void Geom::
1701 fillin(DatagramIterator &scan, BamReader *manager) {
1702  TypedWritable::fillin(scan, manager);
1703 
1704  manager->read_cdata(scan, _cycler);
1705 }
1706 
1707 /**
1708  *
1709  */
1710 Geom::CDataCache::
1711 ~CDataCache() {
1712  set_result(nullptr, nullptr);
1713 }
1714 
1715 /**
1716  *
1717  */
1718 CycleData *Geom::CDataCache::
1719 make_copy() const {
1720  return new CDataCache(*this);
1721 }
1722 
1723 /**
1724  * Called when the entry is evicted from the cache, this should clean up the
1725  * owning object appropriately.
1726  */
1728 evict_callback() {
1729  LightMutexHolder holder(_source->_cache_lock);
1730  Cache::iterator ci = _source->_cache.find(&_key);
1731  nassertv(ci != _source->_cache.end());
1732  nassertv((*ci).second == this);
1733  _source->_cache.erase(ci);
1734 }
1735 
1736 /**
1737  *
1738  */
1739 void Geom::CacheEntry::
1740 output(std::ostream &out) const {
1741  out << "geom " << (void *)_source << ", "
1742  << (const void *)_key._modifier;
1743 }
1744 
1745 
1746 /**
1747  *
1748  */
1749 CycleData *Geom::CData::
1750 make_copy() const {
1751  return new CData(*this);
1752 }
1753 
1754 /**
1755  * Writes the contents of this object to the datagram for shipping out to a
1756  * Bam file.
1757  */
1758 void Geom::CData::
1759 write_datagram(BamWriter *manager, Datagram &dg) const {
1760  manager->write_pointer(dg, _data.get_read_pointer());
1761 
1762  dg.add_uint16(_primitives.size());
1763  Primitives::const_iterator pi;
1764  for (pi = _primitives.begin(); pi != _primitives.end(); ++pi) {
1765  manager->write_pointer(dg, (*pi).get_read_pointer());
1766  }
1767 
1768  dg.add_uint8(_primitive_type);
1769  dg.add_uint8(_shade_model);
1770 
1771  // Actually, we shouldn't bother writing out _geom_rendering; we'll just
1772  // throw it away anyway.
1773  dg.add_uint16(_geom_rendering);
1774 
1775  dg.add_uint8(_bounds_type);
1776 }
1777 
1778 /**
1779  * Receives an array of pointers, one for each time manager->read_pointer()
1780  * was called in fillin(). Returns the number of pointers processed.
1781  */
1782 int Geom::CData::
1783 complete_pointers(TypedWritable **p_list, BamReader *manager) {
1784  int pi = CycleData::complete_pointers(p_list, manager);
1785 
1786  _data = DCAST(GeomVertexData, p_list[pi++]);
1787 
1788  Primitives::iterator pri;
1789  for (pri = _primitives.begin(); pri != _primitives.end(); ++pri) {
1790  (*pri) = DCAST(GeomPrimitive, p_list[pi++]);
1791  }
1792 
1793  return pi;
1794 }
1795 
1796 /**
1797  * This internal function is called by make_from_bam to read in all of the
1798  * relevant data from the BamFile for the new Geom.
1799  */
1800 void Geom::CData::
1801 fillin(DatagramIterator &scan, BamReader *manager) {
1802  manager->read_pointer(scan);
1803 
1804  int num_primitives = scan.get_uint16();
1805  _primitives.reserve(num_primitives);
1806  for (int i = 0; i < num_primitives; ++i) {
1807  manager->read_pointer(scan);
1808  _primitives.push_back(nullptr);
1809  }
1810 
1811  _primitive_type = (PrimitiveType)scan.get_uint8();
1812  _shade_model = (ShadeModel)scan.get_uint8();
1813 
1814  // To be removed: we no longer read _geom_rendering from the bam file;
1815  // instead, we rederive it in finalize().
1816  scan.get_uint16();
1817 
1818  _modified = Geom::get_next_modified();
1819 
1820  _bounds_type = BoundingVolume::BT_default;
1821  if (manager->get_file_minor_ver() >= 19) {
1822  _bounds_type = (BoundingVolume::BoundsType)scan.get_uint8();
1823  }
1824 }
1825 
1826 /**
1827  *
1828  */
1829 bool GeomPipelineReader::
1830 check_valid(const GeomVertexDataPipelineReader *data_reader) const {
1831  Geom::Primitives::const_iterator pi;
1832  for (pi = _cdata->_primitives.begin();
1833  pi != _cdata->_primitives.end();
1834  ++pi) {
1835  GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread);
1836  reader.check_minmax();
1837  if (!reader.check_valid(data_reader)) {
1838  return false;
1839  }
1840  }
1841 
1842  return true;
1843 }
1844 
1845 /**
1846  * The implementation of Geom::draw().
1847  */
1850  const GeomVertexDataPipelineReader *data_reader, bool force) const {
1851  bool all_ok;
1852  {
1853  PStatTimer timer(Geom::_draw_primitive_setup_pcollector);
1854  all_ok = gsg->begin_draw_primitives(this, data_reader, force);
1855  }
1856  if (all_ok) {
1857  Geom::Primitives::const_iterator pi;
1858  for (pi = _cdata->_primitives.begin();
1859  pi != _cdata->_primitives.end();
1860  ++pi) {
1861  GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread);
1862  if (reader.get_num_vertices() != 0) {
1863  reader.check_minmax();
1864  nassertr(reader.check_valid(data_reader), false);
1865  if (!reader.draw(gsg, force)) {
1866  all_ok = false;
1867  }
1868  }
1869  }
1870  gsg->end_draw_primitives();
1871  }
1872 
1873  return all_ok;
1874 }
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:1849
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:1728
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:1003
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:1207
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:1248
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:1306
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:860
virtual bool copy_primitives_from(const Geom *other)
Copies the primitives from the indicated Geom into this one.
Definition: geom.cxx:941
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:1230
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:1061
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:1186
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:1282
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:823
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:1652
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:1682
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:1643
static UpdateSeq get_next_modified()
Returns a monotonically increasing sequence.
Definition: geom.cxx:1324
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:1216
void make_adjacency_in_place()
Replaces the GeomPrimitives within this Geom with corresponding versions with adjacency information.
Definition: geom.cxx:899
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:1032
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.