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  */
99 Geom *Geom::
100 make_copy() const {
101  return new Geom(*this);
102 }
103 
104 /**
105  * Returns the minimum (i.e. most dynamic) usage_hint among all of the
106  * individual GeomPrimitives that have been added to the geom.
107  * @deprecated This is no longer very useful.
108  */
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::
172  Thread *current_thread = Thread::get_current_thread();
173  nassertv(check_will_be_valid(data));
174  CDWriter cdata(_cycler, true, current_thread);
175  cdata->_data = (GeomVertexData *)data;
176  clear_cache_stage(current_thread);
177  mark_internal_bounds_stale(cdata);
178  reset_geom_rendering(cdata);
179 }
180 
181 /**
182  * Replaces a Geom's vertex table with a new table, and simultaneously adds
183  * the indicated offset to all vertex references within the Geom's primitives.
184  * This is intended to be used to combine multiple GeomVertexDatas from
185  * different Geoms into a single big buffer, with each Geom referencing a
186  * subset of the vertices in the buffer.
187  *
188  * Don't call this in a downstream thread unless you don't mind it blowing
189  * away other changes you might have recently made in an upstream thread.
190  */
191 void Geom::
192 offset_vertices(const GeomVertexData *data, int offset) {
193  Thread *current_thread = Thread::get_current_thread();
194  CDWriter cdata(_cycler, true, current_thread);
195  cdata->_data = (GeomVertexData *)data;
196 
197 #ifndef NDEBUG
198  GeomVertexDataPipelineReader data_reader(data, current_thread);
199  data_reader.check_array_readers();
200 
201  bool all_is_valid = true;
202 #endif
203  Primitives::iterator pi;
204  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
205  PT(GeomPrimitive) prim = (*pi).get_write_pointer();
206  prim->offset_vertices(offset);
207 
208 #ifndef NDEBUG
209  if (!prim->check_valid(&data_reader)) {
210  gobj_cat.warning()
211  << *prim << " is invalid for " << *data << ":\n";
212  prim->write(gobj_cat.warning(false), 4);
213 
214  all_is_valid = false;
215  }
216 #endif
217  }
218 
219  cdata->_modified = Geom::get_next_modified();
220  clear_cache_stage(current_thread);
221  nassertv(all_is_valid);
222 }
223 
224 /**
225  * Converts the geom from indexed to nonindexed by duplicating vertices as
226  * necessary. If composite_only is true, then only composite primitives such
227  * as trifans and tristrips are converted. Returns the number of
228  * GeomPrimitive objects converted.
229  *
230  * Don't call this in a downstream thread unless you don't mind it blowing
231  * away other changes you might have recently made in an upstream thread.
232  */
233 int Geom::
234 make_nonindexed(bool composite_only) {
235  Thread *current_thread = Thread::get_current_thread();
236  int num_changed = 0;
237 
238  CDWriter cdata(_cycler, true, current_thread);
239  CPT(GeomVertexData) orig_data = cdata->_data.get_read_pointer(current_thread);
240  PT(GeomVertexData) new_data = new GeomVertexData(*orig_data);
241  new_data->clear_rows();
242 
243 #ifndef NDEBUG
244  bool all_is_valid = true;
245 #endif
246  Primitives::iterator pi;
247  Primitives new_prims;
248  new_prims.reserve(cdata->_primitives.size());
249  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
250  PT(GeomPrimitive) primitive = (*pi).get_read_pointer(current_thread)->make_copy();
251  new_prims.push_back(primitive.p());
252 
253  // GeomPoints are considered "composite" for the purposes of making
254  // nonindexed, since there's no particular advantage to having indexed
255  // points (as opposed to, say, indexed triangles or indexed lines).
256  if (primitive->is_indexed() &&
257  (primitive->is_composite() ||
258  primitive->is_exact_type(GeomPoints::get_class_type()) ||
259  !composite_only)) {
260  primitive->make_nonindexed(new_data, orig_data);
261  ++num_changed;
262  } else {
263  // If it's a simple primitive, pack it anyway, so it can share the same
264  // GeomVertexData.
265  primitive->pack_vertices(new_data, orig_data);
266  }
267 
268 #ifndef NDEBUG
269  if (!primitive->check_valid(new_data)) {
270  all_is_valid = false;
271  }
272 #endif
273  }
274 
275  nassertr(all_is_valid, 0);
276 
277  if (num_changed != 0) {
278  // If any at all were changed, then keep the result (otherwise, discard
279  // it, since we might have de-optimized the indexed geometry a bit).
280  cdata->_data = new_data;
281  cdata->_primitives.swap(new_prims);
282  cdata->_modified = Geom::get_next_modified();
283  clear_cache_stage(current_thread);
284  }
285 
286  return num_changed;
287 }
288 
289 /**
290  * Returns a GeomVertexData that represents the results of computing the
291  * vertex animation on the CPU for this Geom's vertex data.
292  *
293  * If there is no CPU-defined vertex animation on this object, this just
294  * returns the original object.
295  *
296  * If there is vertex animation, but the VertexTransform values have not
297  * changed since last time, this may return the same pointer it returned
298  * previously. Even if the VertexTransform values have changed, it may still
299  * return the same pointer, but with its contents modified (this is preferred,
300  * since it allows the graphics backend to update vertex buffers optimally).
301  *
302  * If force is false, this method may return immediately with stale data, if
303  * the vertex data is not completely resident. If force is true, this method
304  * will never return stale data, but may block until the data is available.
305  */
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::
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 void Geom::
898  Thread *current_thread = Thread::get_current_thread();
899  CDWriter cdata(_cycler, true, current_thread);
900 
901 #ifndef NDEBUG
902  GeomVertexDataPipelineReader data_reader(cdata->_data.get_read_pointer(current_thread), current_thread);
903  data_reader.check_array_readers();
904 
905  bool all_is_valid = true;
906 #endif
907  Primitives::iterator pi;
908  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
909  CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_adjacency();
910  if (new_prim != nullptr) {
911  (*pi) = (GeomPrimitive *)new_prim.p();
912 
913 #ifndef NDEBUG
914  if (!new_prim->check_valid(&data_reader)) {
915  all_is_valid = false;
916  }
917 #endif
918  }
919  }
920 
921  cdata->_modified = Geom::get_next_modified();
922  reset_geom_rendering(cdata);
923  clear_cache_stage(current_thread);
924 
925  nassertv(all_is_valid);
926 }
927 
928 /**
929  * Copies the primitives from the indicated Geom into this one. This does
930  * require that both Geoms contain the same fundamental type primitives, both
931  * have a compatible shade model, and both use the same GeomVertexData. Both
932  * Geoms must also be the same specific class type (i.e. if one is a
933  * GeomTextGlyph, they both must be.)
934  *
935  * Returns true if the copy is successful, or false otherwise (because the
936  * Geoms were mismatched).
937  */
938 bool Geom::
939 copy_primitives_from(const Geom *other) {
940  if (get_primitive_type() != PT_none &&
941  other->get_primitive_type() != get_primitive_type()) {
942  return false;
943  }
944  if (get_vertex_data() != other->get_vertex_data()) {
945  return false;
946  }
947  if (get_type() != other->get_type()) {
948  return false;
949  }
950 
951  ShadeModel this_shade_model = get_shade_model();
952  ShadeModel other_shade_model = other->get_shade_model();
953  if (this_shade_model != SM_uniform && other_shade_model != SM_uniform &&
954  this_shade_model != other_shade_model) {
955  if ((this_shade_model == SM_flat_first_vertex && other_shade_model == SM_flat_last_vertex) ||
956  (this_shade_model == SM_flat_last_vertex && other_shade_model == SM_flat_first_vertex)) {
957  // This is acceptable; we can rotate the primitives to match.
958 
959  } else {
960  // Otherwise, we have incompatible shade models.
961  return false;
962  }
963  }
964 
965  int num_primitives = other->get_num_primitives();
966  for (int i = 0; i < num_primitives; i++) {
967  add_primitive(other->get_primitive(i));
968  }
969 
970  return true;
971 }
972 
973 /**
974  * Returns the number of bytes consumed by the geom and its primitives (but
975  * not including its vertex table).
976  */
977 int Geom::
978 get_num_bytes() const {
979  CDReader cdata(_cycler);
980 
981  int num_bytes = sizeof(Geom);
982  Primitives::const_iterator pi;
983  for (pi = cdata->_primitives.begin();
984  pi != cdata->_primitives.end();
985  ++pi) {
986  num_bytes += (*pi).get_read_pointer()->get_num_bytes();
987  }
988 
989  return num_bytes;
990 }
991 
992 /**
993  * Returns true if all the primitive arrays are currently resident in memory.
994  * If this returns false, the data will be brought back into memory shortly;
995  * try again later.
996  *
997  * This does not also test the Geom's associated GeomVertexData. That must be
998  * tested separately.
999  */
1000 bool Geom::
1002  Thread *current_thread = Thread::get_current_thread();
1003 
1004  CDReader cdata(_cycler, current_thread);
1005 
1006  bool resident = true;
1007 
1008  Primitives::const_iterator pi;
1009  for (pi = cdata->_primitives.begin();
1010  pi != cdata->_primitives.end();
1011  ++pi) {
1012  if (!(*pi).get_read_pointer(current_thread)->request_resident()) {
1013  resident = false;
1014  }
1015  }
1016 
1017  return resident;
1018 }
1019 
1020 /**
1021  * Applies the indicated transform to all of the vertices in the Geom. If the
1022  * Geom happens to share a vertex table with another Geom, this operation will
1023  * duplicate the vertex table instead of breaking the other Geom; however, if
1024  * multiple Geoms with shared tables are transformed by the same matrix, they
1025  * will no longer share tables after the operation. Consider using the
1026  * GeomTransformer if you will be applying the same transform to multiple
1027  * Geoms.
1028  */
1029 void Geom::
1030 transform_vertices(const LMatrix4 &mat) {
1031  PT(GeomVertexData) new_data = modify_vertex_data();
1032  CPT(GeomVertexFormat) format = new_data->get_format();
1033 
1034  size_t ci;
1035  for (ci = 0; ci < format->get_num_points(); ci++) {
1036  GeomVertexRewriter data(new_data, format->get_point(ci));
1037 
1038  while (!data.is_at_end()) {
1039  const LPoint3 &point = data.get_data3();
1040  data.set_data3(point * mat);
1041  }
1042  }
1043  for (ci = 0; ci < format->get_num_vectors(); ci++) {
1044  GeomVertexRewriter data(new_data, format->get_vector(ci));
1045 
1046  while (!data.is_at_end()) {
1047  const LVector3 &vector = data.get_data3();
1048  data.set_data3(normalize(vector * mat));
1049  }
1050  }
1051 }
1052 
1053 /**
1054  * Verifies that the all of the primitives within the geom reference vertices
1055  * that actually exist within the geom's GeomVertexData. Returns true if the
1056  * geom appears to be valid, false otherwise.
1057  */
1058 bool Geom::
1059 check_valid() const {
1060  Thread *current_thread = Thread::get_current_thread();
1061  GeomPipelineReader geom_reader(this, current_thread);
1062  CPT(GeomVertexData) vertex_data = geom_reader.get_vertex_data();
1063  GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1064  data_reader.check_array_readers();
1065  return geom_reader.check_valid(&data_reader);
1066 }
1067 
1068 /**
1069  * Verifies that the all of the primitives within the geom reference vertices
1070  * that actually exist within the indicated GeomVertexData. Returns true if
1071  * the geom appears to be valid, false otherwise.
1072  */
1073 bool Geom::
1074 check_valid(const GeomVertexData *vertex_data) const {
1075  Thread *current_thread = Thread::get_current_thread();
1076  GeomPipelineReader geom_reader(this, current_thread);
1077  GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1078  data_reader.check_array_readers();
1079  return geom_reader.check_valid(&data_reader);
1080 }
1081 
1082 /**
1083  * Returns the bounding volume for the Geom.
1084  */
1086 get_bounds(Thread *current_thread) const {
1087  CDLockedReader cdata(_cycler, current_thread);
1088  if (cdata->_user_bounds != nullptr) {
1089  return cdata->_user_bounds;
1090  }
1091 
1092  if (cdata->_internal_bounds_stale) {
1093  CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
1094  compute_internal_bounds(cdataw, current_thread);
1095  return cdataw->_internal_bounds;
1096  }
1097  return cdata->_internal_bounds;
1098 }
1099 
1100 /**
1101  * Returns the number of vertices rendered by all primitives within the Geom.
1102  */
1103 int Geom::
1104 get_nested_vertices(Thread *current_thread) const {
1105  CDLockedReader cdata(_cycler, current_thread);
1106  if (cdata->_internal_bounds_stale) {
1107  CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
1108  compute_internal_bounds(cdataw, current_thread);
1109  return cdataw->_nested_vertices;
1110  }
1111  return cdata->_nested_vertices;
1112 }
1113 
1114 /**
1115  *
1116  */
1117 void Geom::
1118 output(std::ostream &out) const {
1119  CDReader cdata(_cycler);
1120 
1121  // Get a list of the primitive types contained within this object.
1122  int num_faces = 0;
1123  pset<TypeHandle> types;
1124  Primitives::const_iterator pi;
1125  for (pi = cdata->_primitives.begin();
1126  pi != cdata->_primitives.end();
1127  ++pi) {
1128  CPT(GeomPrimitive) prim = (*pi).get_read_pointer();
1129  num_faces += prim->get_num_faces();
1130  types.insert(prim->get_type());
1131  }
1132 
1133  out << get_type() << " [";
1135  for (ti = types.begin(); ti != types.end(); ++ti) {
1136  out << " " << (*ti);
1137  }
1138  out << " ], " << num_faces << " faces";
1139 }
1140 
1141 /**
1142  *
1143  */
1144 void Geom::
1145 write(std::ostream &out, int indent_level) const {
1146  CDReader cdata(_cycler);
1147 
1148  // Get a list of the primitive types contained within this object.
1149  Primitives::const_iterator pi;
1150  for (pi = cdata->_primitives.begin();
1151  pi != cdata->_primitives.end();
1152  ++pi) {
1153  (*pi).get_read_pointer()->write(out, indent_level);
1154  }
1155 }
1156 
1157 /**
1158  * Removes all of the previously-cached results of munge_geom().
1159  *
1160  * This blows away the entire cache, upstream and downstream the pipeline.
1161  * Use clear_cache_stage() instead if you only want to blow away the cache at
1162  * the current stage and upstream.
1163  */
1164 void Geom::
1165 clear_cache() {
1166  LightMutexHolder holder(_cache_lock);
1167  for (Cache::iterator ci = _cache.begin();
1168  ci != _cache.end();
1169  ++ci) {
1170  CacheEntry *entry = (*ci).second;
1171  entry->erase();
1172  }
1173  _cache.clear();
1174 }
1175 
1176 /**
1177  * Removes all of the previously-cached results of munge_geom(), at the
1178  * current pipeline stage and upstream. Does not affect the downstream cache.
1179  *
1180  * Don't call this in a downstream thread unless you don't mind it blowing
1181  * away other changes you might have recently made in an upstream thread.
1182  */
1183 void Geom::
1184 clear_cache_stage(Thread *current_thread) {
1185  LightMutexHolder holder(_cache_lock);
1186  for (Cache::iterator ci = _cache.begin();
1187  ci != _cache.end();
1188  ++ci) {
1189  CacheEntry *entry = (*ci).second;
1190  CDCacheWriter cdata(entry->_cycler, current_thread);
1191  cdata->set_result(nullptr, nullptr);
1192  }
1193 }
1194 
1195 /**
1196  * Indicates that the geom should be enqueued to be prepared in the indicated
1197  * prepared_objects at the beginning of the next frame. This will ensure the
1198  * geom is already loaded into geom memory if it is expected to be rendered
1199  * soon.
1200  *
1201  * Use this function instead of prepare_now() to preload geoms from a user
1202  * interface standpoint.
1203  */
1204 void Geom::
1205 prepare(PreparedGraphicsObjects *prepared_objects) {
1206  prepared_objects->enqueue_geom(this);
1207 }
1208 
1209 /**
1210  * Returns true if the geom has already been prepared or enqueued for
1211  * preparation on the indicated GSG, false otherwise.
1212  */
1213 bool Geom::
1214 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
1215  Contexts::const_iterator ci;
1216  ci = _contexts.find(prepared_objects);
1217  if (ci != _contexts.end()) {
1218  return true;
1219  }
1220  return prepared_objects->is_geom_queued(this);
1221 }
1222 
1223 /**
1224  * Frees the geom context only on the indicated object, if it exists there.
1225  * Returns true if it was released, false if it had not been prepared.
1226  */
1227 bool Geom::
1228 release(PreparedGraphicsObjects *prepared_objects) {
1229  Contexts::iterator ci;
1230  ci = _contexts.find(prepared_objects);
1231  if (ci != _contexts.end()) {
1232  GeomContext *gc = (*ci).second;
1233  prepared_objects->release_geom(gc);
1234  return true;
1235  }
1236 
1237  // Maybe it wasn't prepared yet, but it's about to be.
1238  return prepared_objects->dequeue_geom(this);
1239 }
1240 
1241 /**
1242  * Frees the context allocated on all objects for which the geom has been
1243  * declared. Returns the number of contexts which have been freed.
1244  */
1245 int Geom::
1247  // We have to traverse a copy of the _contexts list, because the
1248  // PreparedGraphicsObjects object will call clear_prepared() in response to
1249  // each release_geom(), and we don't want to be modifying the _contexts list
1250  // while we're traversing it.
1251  Contexts temp = _contexts;
1252  int num_freed = (int)_contexts.size();
1253 
1254  Contexts::const_iterator ci;
1255  for (ci = temp.begin(); ci != temp.end(); ++ci) {
1256  PreparedGraphicsObjects *prepared_objects = (*ci).first;
1257  GeomContext *gc = (*ci).second;
1258  prepared_objects->release_geom(gc);
1259  }
1260 
1261  // Now that we've called release_geom() on every known context, the
1262  // _contexts list should have completely emptied itself.
1263  nassertr(_contexts.empty(), num_freed);
1264 
1265  return num_freed;
1266 }
1267 
1268 /**
1269  * Creates a context for the geom on the particular GSG, if it does not
1270  * already exist. Returns the new (or old) GeomContext. This assumes that
1271  * the GraphicsStateGuardian is the currently active rendering context and
1272  * that it is ready to accept new geoms. If this is not necessarily the case,
1273  * you should use prepare() instead.
1274  *
1275  * Normally, this is not called directly except by the GraphicsStateGuardian;
1276  * a geom does not need to be explicitly prepared by the user before it may be
1277  * rendered.
1278  */
1282  Contexts::const_iterator ci;
1283  ci = _contexts.find(prepared_objects);
1284  if (ci != _contexts.end()) {
1285  return (*ci).second;
1286  }
1287 
1288  GeomContext *gc = prepared_objects->prepare_geom_now(this, gsg);
1289  if (gc != nullptr) {
1290  _contexts[prepared_objects] = gc;
1291  }
1292  return gc;
1293 }
1294 
1295 /**
1296  * Actually draws the Geom with the indicated GSG, using the indicated vertex
1297  * data (which might have been pre-munged to support the GSG's needs).
1298  *
1299  * Returns true if all of the primitives were drawn normally, false if there
1300  * was a problem (for instance, some of the data was nonresident). If force
1301  * is passed true, it will wait for the data to become resident if necessary.
1302  */
1303 bool Geom::
1305  bool force, Thread *current_thread) const {
1306  GeomPipelineReader geom_reader(this, current_thread);
1307  GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1308  data_reader.check_array_readers();
1309 
1310  return geom_reader.draw(gsg, &data_reader, force);
1311 }
1312 
1313 /**
1314  * Returns a monotonically increasing sequence. Each time this is called, a
1315  * new sequence number is returned, higher than the previous value.
1316  *
1317  * This is used to ensure that GeomVertexArrayData::get_modified() and
1318  * GeomPrimitive::get_modified() update from the same space, so that
1319  * Geom::get_modified() returns a meaningful value.
1320  */
1323  ++_next_modified;
1324  return _next_modified;
1325 }
1326 
1327 /**
1328  * Recomputes the dynamic bounding volume for this Geom. This includes all of
1329  * the vertices.
1330  */
1331 void Geom::
1332 compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
1333  int num_vertices = 0;
1334 
1335  // Get the vertex data, after animation.
1336  CPT(GeomVertexData) vertex_data = get_animated_vertex_data(true, current_thread);
1337 
1338  // Now actually compute the bounding volume. We do this by using
1339  // calc_tight_bounds to determine our box first.
1340  LPoint3 pmin, pmax;
1341  PN_stdfloat sq_center_dist = 0.0f;
1342  bool found_any = false;
1343  do_calc_tight_bounds(pmin, pmax, sq_center_dist, found_any,
1344  vertex_data, false, LMatrix4::ident_mat(),
1345  InternalName::get_vertex(),
1346  cdata, current_thread);
1347 
1348  BoundingVolume::BoundsType btype = cdata->_bounds_type;
1349  if (btype == BoundingVolume::BT_default) {
1350  btype = bounds_type;
1351  }
1352 
1353  if (found_any) {
1354  nassertv(!pmin.is_nan());
1355  nassertv(!pmax.is_nan());
1356 
1357  // Then we put the bounding volume around both of those points.
1358  PN_stdfloat avg_box_area;
1359  switch (btype) {
1360  case BoundingVolume::BT_best:
1361  case BoundingVolume::BT_fastest:
1362  case BoundingVolume::BT_default:
1363  {
1364  // When considering a box, calculate (roughly) the average area of the
1365  // sides. We will use this to determine whether a sphere or box is a
1366  // better fit.
1367  PN_stdfloat min_extent = min(pmax[0] - pmin[0],
1368  min(pmax[1] - pmin[1],
1369  pmax[2] - pmin[2]));
1370  PN_stdfloat max_extent = max(pmax[0] - pmin[0],
1371  max(pmax[1] - pmin[1],
1372  pmax[2] - pmin[2]));
1373  avg_box_area = ((min_extent * min_extent) + (max_extent * max_extent)) / 2;
1374  }
1375  // Fall through
1376  case BoundingVolume::BT_sphere:
1377  {
1378  // Determine the best radius for a bounding sphere.
1379  LPoint3 aabb_center = (pmin + pmax) * 0.5f;
1380  PN_stdfloat best_sq_radius = (pmax - aabb_center).length_squared();
1381 
1382  if (btype != BoundingVolume::BT_fastest && best_sq_radius > 0.0f &&
1383  aabb_center.length_squared() / best_sq_radius >= (0.2f * 0.2f)) {
1384  // Hmm, this is an off-center model. Maybe we can do a better job
1385  // by calculating the bounding sphere from the AABB center.
1386 
1387  PN_stdfloat better_sq_radius;
1388  bool found_any = false;
1389  do_calc_sphere_radius(aabb_center, better_sq_radius, found_any,
1390  vertex_data, cdata, current_thread);
1391 
1392  if (found_any && better_sq_radius > 0.0f &&
1393  better_sq_radius <= best_sq_radius) {
1394  // Great. This is as good a sphere as we're going to get.
1395  if (btype == BoundingVolume::BT_best &&
1396  avg_box_area < better_sq_radius * MathNumbers::pi) {
1397  // But the box is better, anyway. Use that instead.
1398  cdata->_internal_bounds = new BoundingBox(pmin, pmax);
1399  break;
1400  }
1401  cdata->_internal_bounds =
1402  new BoundingSphere(aabb_center, csqrt(better_sq_radius));
1403  break;
1404  }
1405  }
1406 
1407  if (btype != BoundingVolume::BT_sphere &&
1408  avg_box_area < sq_center_dist * MathNumbers::pi) {
1409  // A box is probably a tighter fit.
1410  cdata->_internal_bounds = new BoundingBox(pmin, pmax);
1411  break;
1412 
1413  } else if (sq_center_dist >= 0.0f && sq_center_dist <= best_sq_radius) {
1414  // No, but a sphere centered on the origin is apparently still
1415  // better than a sphere around the bounding box.
1416  cdata->_internal_bounds =
1417  new BoundingSphere(LPoint3::origin(), csqrt(sq_center_dist));
1418  break;
1419 
1420  } else if (btype == BoundingVolume::BT_sphere) {
1421  // This is the worst sphere we can make, which is why we will only
1422  // do it when the user specifically requests a sphere.
1423  cdata->_internal_bounds =
1424  new BoundingSphere(aabb_center,
1425  (best_sq_radius > 0.0f) ? csqrt(best_sq_radius) : 0.0f);
1426  break;
1427  }
1428  }
1429  // Fall through.
1430 
1431  case BoundingVolume::BT_box:
1432  cdata->_internal_bounds = new BoundingBox(pmin, pmax);
1433  }
1434 
1435  Primitives::const_iterator pi;
1436  for (pi = cdata->_primitives.begin();
1437  pi != cdata->_primitives.end();
1438  ++pi) {
1439  CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
1440  num_vertices += prim->get_num_vertices();
1441  }
1442 
1443  } else {
1444  // No points; empty bounding volume.
1445  if (btype == BoundingVolume::BT_sphere) {
1446  cdata->_internal_bounds = new BoundingSphere;
1447  } else {
1448  cdata->_internal_bounds = new BoundingBox;
1449  }
1450  }
1451 
1452  cdata->_nested_vertices = num_vertices;
1453  cdata->_internal_bounds_stale = false;
1454 }
1455 
1456 /**
1457  * The private implementation of calc_tight_bounds().
1458  */
1459 void Geom::
1460 do_calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
1461  PN_stdfloat &sq_center_dist, bool &found_any,
1462  const GeomVertexData *vertex_data,
1463  bool got_mat, const LMatrix4 &mat,
1464  const InternalName *column_name,
1465  const CData *cdata, Thread *current_thread) const {
1466  Primitives::const_iterator pi;
1467  for (pi = cdata->_primitives.begin();
1468  pi != cdata->_primitives.end();
1469  ++pi) {
1470  CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
1471  prim->calc_tight_bounds(min_point, max_point, sq_center_dist,
1472  found_any, vertex_data, got_mat, mat,
1473  column_name, current_thread);
1474  }
1475 }
1476 
1477 /**
1478  *
1479  */
1480 void Geom::
1481 do_calc_sphere_radius(const LPoint3 &center, PN_stdfloat &sq_radius,
1482  bool &found_any, const GeomVertexData *vertex_data,
1483  const CData *cdata, Thread *current_thread) const {
1484  Primitives::const_iterator pi;
1485  for (pi = cdata->_primitives.begin();
1486  pi != cdata->_primitives.end();
1487  ++pi) {
1488  CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
1489  prim->calc_sphere_radius(center, sq_radius, found_any,
1490  vertex_data, current_thread);
1491  }
1492 }
1493 
1494 /**
1495  * Removes the indicated PreparedGraphicsObjects table from the Geom's table,
1496  * without actually releasing the geom. This is intended to be called only
1497  * from PreparedGraphicsObjects::release_geom(); it should never be called by
1498  * user code.
1499  */
1500 void Geom::
1501 clear_prepared(PreparedGraphicsObjects *prepared_objects) {
1502  Contexts::iterator ci;
1503  ci = _contexts.find(prepared_objects);
1504  if (ci != _contexts.end()) {
1505  _contexts.erase(ci);
1506  } else {
1507  // If this assertion fails, clear_prepared() was given a prepared_objects
1508  // that the geom didn't know about.
1509  nassert_raise("unknown PreparedGraphicsObjects");
1510  }
1511 }
1512 
1513 /**
1514  * Verifies that the all of the primitives within the geom reference vertices
1515  * that actually exist within the indicated GeomVertexData (presumably in
1516  * preparation for assigning the geom to use this data). Returns true if the
1517  * data appears to be valid, false otherwise.
1518  */
1519 bool Geom::
1520 check_will_be_valid(const GeomVertexData *vertex_data) const {
1521  Thread *current_thread = Thread::get_current_thread();
1522 
1523  CDReader cdata(_cycler, current_thread);
1524 
1525  GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1526  data_reader.check_array_readers();
1527 
1528  Primitives::const_iterator pi;
1529  for (pi = cdata->_primitives.begin();
1530  pi != cdata->_primitives.end();
1531  ++pi) {
1532  GeomPrimitivePipelineReader reader((*pi).get_read_pointer(), current_thread);
1533  reader.check_minmax();
1534  if (!reader.check_valid(&data_reader)) {
1535  return false;
1536  }
1537  }
1538 
1539  return true;
1540 }
1541 
1542 /**
1543  * Rederives the _geom_rendering member.
1544  */
1545 void Geom::
1546 reset_geom_rendering(Geom::CData *cdata) {
1547  cdata->_geom_rendering = 0;
1548  Primitives::const_iterator pi;
1549  for (pi = cdata->_primitives.begin();
1550  pi != cdata->_primitives.end();
1551  ++pi) {
1552  cdata->_geom_rendering |= (*pi).get_read_pointer()->get_geom_rendering();
1553  }
1554 
1555  if ((cdata->_geom_rendering & GR_point) != 0) {
1556  CPT(GeomVertexData) data = cdata->_data.get_read_pointer();
1557  if (data->has_column(InternalName::get_size())) {
1558  cdata->_geom_rendering |= GR_per_point_size;
1559  }
1560  if (data->has_column(InternalName::get_aspect_ratio())) {
1561  cdata->_geom_rendering |= GR_point_aspect_ratio;
1562  }
1563  if (data->has_column(InternalName::get_rotate())) {
1564  cdata->_geom_rendering |= GR_point_rotate;
1565  }
1566  }
1567 
1568  switch (get_shade_model()) {
1569  case SM_flat_first_vertex:
1570  cdata->_geom_rendering |= GR_flat_first_vertex;
1571  break;
1572 
1573  case SM_flat_last_vertex:
1574  cdata->_geom_rendering |= GR_flat_last_vertex;
1575  break;
1576 
1577  default:
1578  break;
1579  }
1580 }
1581 
1582 /**
1583  * Combines two primitives of the same type into a single primitive. a_prim
1584  * is modified to append the vertices from b_prim, which is unmodified.
1585  */
1586 void Geom::
1587 combine_primitives(GeomPrimitive *a_prim, CPT(GeomPrimitive) b_prim,
1588  Thread *current_thread) {
1589  nassertv(a_prim != b_prim);
1590  nassertv(a_prim->get_type() == b_prim->get_type());
1591 
1592  if (a_prim->get_index_type() != b_prim->get_index_type()) {
1593  GeomPrimitive::NumericType index_type = max(a_prim->get_index_type(), b_prim->get_index_type());
1594  a_prim->set_index_type(index_type);
1595  if (b_prim->get_index_type() != index_type) {
1596  PT(GeomPrimitive) b_prim_copy = b_prim->make_copy();
1597  b_prim_copy->set_index_type(index_type);
1598  b_prim = b_prim_copy;
1599  }
1600  }
1601 
1602  if (!b_prim->is_indexed()) {
1603  PT(GeomPrimitive) b_prim_copy = b_prim->make_copy();
1604  b_prim_copy->make_indexed();
1605  b_prim = b_prim_copy;
1606  }
1607 
1608  PT(GeomVertexArrayData) a_vertices = a_prim->modify_vertices();
1609  CPT(GeomVertexArrayData) b_vertices = b_prim->get_vertices();
1610 
1611  if (a_prim->requires_unused_vertices()) {
1612  GeomVertexReader index(b_vertices, 0);
1613  int b_vertex = index.get_data1i();
1614  a_prim->append_unused_vertices(a_vertices, b_vertex);
1615  }
1616 
1617  PT(GeomVertexArrayDataHandle) a_handle =
1618  new GeomVertexArrayDataHandle(std::move(a_vertices), current_thread);
1619  CPT(GeomVertexArrayDataHandle) b_handle =
1620  new GeomVertexArrayDataHandle(std::move(b_vertices), current_thread);
1621 
1622  size_t orig_a_vertices = a_handle->get_num_rows();
1623 
1624  a_handle->copy_subdata_from(a_handle->get_data_size_bytes(), 0,
1625  b_handle, 0, b_handle->get_data_size_bytes());
1626  a_prim->clear_minmax();
1627  if (a_prim->is_composite()) {
1628  // Also copy the ends array.
1629  PTA_int a_ends = a_prim->modify_ends();
1630  CPTA_int b_ends = b_prim->get_ends();
1631  for (size_t i = 0; i < b_ends.size(); ++i) {
1632  a_ends.push_back(b_ends[i] + orig_a_vertices);
1633  }
1634  }
1635 }
1636 
1637 /**
1638  * Tells the BamReader how to create objects of type Geom.
1639  */
1640 void Geom::
1642  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
1643 }
1644 
1645 /**
1646  * Writes the contents of this object to the datagram for shipping out to a
1647  * Bam file.
1648  */
1649 void Geom::
1651  TypedWritable::write_datagram(manager, dg);
1652 
1653  manager->write_cdata(dg, _cycler);
1654 }
1655 
1656 /**
1657  * This function is called by the BamReader's factory when a new object of
1658  * type Geom is encountered in the Bam file. It should create the Geom and
1659  * extract its information from the file.
1660  */
1661 TypedWritable *Geom::
1662 make_from_bam(const FactoryParams &params) {
1663  Geom *object = new Geom(nullptr);
1664  DatagramIterator scan;
1665  BamReader *manager;
1666 
1667  parse_params(params, scan, manager);
1668  object->fillin(scan, manager);
1669  manager->register_finalize(object);
1670 
1671  return object;
1672 }
1673 
1674 /**
1675  * Called by the BamReader to perform any final actions needed for setting up
1676  * the object after all objects have been read and all pointers have been
1677  * completed.
1678  */
1679 void Geom::
1680 finalize(BamReader *manager) {
1681  CDWriter cdata(_cycler, true);
1682 
1683  // Make sure our GeomVertexData is finalized first. This may result in the
1684  // data getting finalized multiple times, but it doesn't mind that.
1685  if (!cdata->_data.is_null()) {
1686  // We shouldn't call get_write_pointer(), which might replicate the
1687  // GeomVertexData unnecessarily.
1688  cdata->_data.get_unsafe_pointer()->finalize(manager);
1689  }
1690 
1691  reset_geom_rendering(cdata);
1692 }
1693 
1694 /**
1695  * This internal function is called by make_from_bam to read in all of the
1696  * relevant data from the BamFile for the new Geom.
1697  */
1698 void Geom::
1699 fillin(DatagramIterator &scan, BamReader *manager) {
1700  TypedWritable::fillin(scan, manager);
1701 
1702  manager->read_cdata(scan, _cycler);
1703 }
1704 
1705 /**
1706  *
1707  */
1708 Geom::CDataCache::
1709 ~CDataCache() {
1710  set_result(nullptr, nullptr);
1711 }
1712 
1713 /**
1714  *
1715  */
1716 CycleData *Geom::CDataCache::
1717 make_copy() const {
1718  return new CDataCache(*this);
1719 }
1720 
1721 /**
1722  * Called when the entry is evicted from the cache, this should clean up the
1723  * owning object appropriately.
1724  */
1725 void Geom::CacheEntry::
1727  LightMutexHolder holder(_source->_cache_lock);
1728  Cache::iterator ci = _source->_cache.find(&_key);
1729  nassertv(ci != _source->_cache.end());
1730  nassertv((*ci).second == this);
1731  _source->_cache.erase(ci);
1732 }
1733 
1734 /**
1735  *
1736  */
1737 void Geom::CacheEntry::
1738 output(std::ostream &out) const {
1739  out << "geom " << (void *)_source << ", "
1740  << (const void *)_key._modifier;
1741 }
1742 
1743 
1744 /**
1745  *
1746  */
1747 CycleData *Geom::CData::
1748 make_copy() const {
1749  return new CData(*this);
1750 }
1751 
1752 /**
1753  * Writes the contents of this object to the datagram for shipping out to a
1754  * Bam file.
1755  */
1756 void Geom::CData::
1757 write_datagram(BamWriter *manager, Datagram &dg) const {
1758  manager->write_pointer(dg, _data.get_read_pointer());
1759 
1760  dg.add_uint16(_primitives.size());
1761  Primitives::const_iterator pi;
1762  for (pi = _primitives.begin(); pi != _primitives.end(); ++pi) {
1763  manager->write_pointer(dg, (*pi).get_read_pointer());
1764  }
1765 
1766  dg.add_uint8(_primitive_type);
1767  dg.add_uint8(_shade_model);
1768 
1769  // Actually, we shouldn't bother writing out _geom_rendering; we'll just
1770  // throw it away anyway.
1771  dg.add_uint16(_geom_rendering);
1772 
1773  dg.add_uint8(_bounds_type);
1774 }
1775 
1776 /**
1777  * Receives an array of pointers, one for each time manager->read_pointer()
1778  * was called in fillin(). Returns the number of pointers processed.
1779  */
1780 int Geom::CData::
1781 complete_pointers(TypedWritable **p_list, BamReader *manager) {
1782  int pi = CycleData::complete_pointers(p_list, manager);
1783 
1784  _data = DCAST(GeomVertexData, p_list[pi++]);
1785 
1786  Primitives::iterator pri;
1787  for (pri = _primitives.begin(); pri != _primitives.end(); ++pri) {
1788  (*pri) = DCAST(GeomPrimitive, p_list[pi++]);
1789  }
1790 
1791  return pi;
1792 }
1793 
1794 /**
1795  * This internal function is called by make_from_bam to read in all of the
1796  * relevant data from the BamFile for the new Geom.
1797  */
1798 void Geom::CData::
1799 fillin(DatagramIterator &scan, BamReader *manager) {
1800  manager->read_pointer(scan);
1801 
1802  int num_primitives = scan.get_uint16();
1803  _primitives.reserve(num_primitives);
1804  for (int i = 0; i < num_primitives; ++i) {
1805  manager->read_pointer(scan);
1806  _primitives.push_back(nullptr);
1807  }
1808 
1809  _primitive_type = (PrimitiveType)scan.get_uint8();
1810  _shade_model = (ShadeModel)scan.get_uint8();
1811 
1812  // To be removed: we no longer read _geom_rendering from the bam file;
1813  // instead, we rederive it in finalize().
1814  scan.get_uint16();
1815 
1816  _modified = Geom::get_next_modified();
1817 
1818  _bounds_type = BoundingVolume::BT_default;
1819  if (manager->get_file_minor_ver() >= 19) {
1820  _bounds_type = (BoundingVolume::BoundsType)scan.get_uint8();
1821  }
1822 }
1823 
1824 /**
1825  *
1826  */
1827 bool GeomPipelineReader::
1828 check_valid(const GeomVertexDataPipelineReader *data_reader) const {
1829  Geom::Primitives::const_iterator pi;
1830  for (pi = _cdata->_primitives.begin();
1831  pi != _cdata->_primitives.end();
1832  ++pi) {
1833  GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread);
1834  reader.check_minmax();
1835  if (!reader.check_valid(data_reader)) {
1836  return false;
1837  }
1838  }
1839 
1840  return true;
1841 }
1842 
1843 /**
1844  * The implementation of Geom::draw().
1845  */
1848  const GeomVertexDataPipelineReader *data_reader, bool force) const {
1849  bool all_ok;
1850  {
1851  PStatTimer timer(Geom::_draw_primitive_setup_pcollector);
1852  all_ok = gsg->begin_draw_primitives(this, data_reader, force);
1853  }
1854  if (all_ok) {
1855  Geom::Primitives::const_iterator pi;
1856  for (pi = _cdata->_primitives.begin();
1857  pi != _cdata->_primitives.end();
1858  ++pi) {
1859  GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread);
1860  if (reader.get_num_vertices() != 0) {
1861  reader.check_minmax();
1862  nassertr(reader.check_valid(data_reader), false);
1863  if (!reader.draw(gsg, force)) {
1864  all_ok = false;
1865  }
1866  }
1867  }
1868  gsg->end_draw_primitives();
1869  }
1870 
1871  return all_ok;
1872 }
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition: boundingBox.h:29
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool is_composite() const
Returns true if the primitive is a composite primitive such as a tristrip or trifan, or false if it is a fundamental primitive such as a collection of triangles.
Definition: geomPrimitive.I:74
This is a special class object that holds all the information returned by a particular GSG to indicat...
Definition: geomContext.h:34
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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:1650
void release_geom(GeomContext *gc)
Indicates that a geom context, created by a previous call to prepare_geom(), is no longer needed...
GeomContext * prepare_geom_now(Geom *geom, GraphicsStateGuardianBase *gsg)
Immediately creates a new GeomContext for the indicated geom and returns it.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
void transform_vertices(const LMatrix4 &mat)
Applies the indicated transform to all of the vertices in the Geom.
Definition: geom.cxx:1030
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 read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
Definition: bamReader.cxx:695
UsageHint get_usage_hint() const
Returns the minimum (i.e.
Definition: geom.cxx:110
This defines a bounding sphere, consisting of a center and a radius.
This class is similar to CycleDataWriter, except it allows writing to a particular stage of the pipel...
void clear_primitives()
Removes all the primitives from the Geom object (but keeps the same table of vertices).
Definition: geom.cxx:427
void set_index_type(NumericType index_type)
Changes the numeric type of the index column.
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:47
PT(CopyOnWriteObject) Geom
Required to implement CopyOnWriteObject.
Definition: geom.cxx:43
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
insert_primitive
Inserts a new GeomPrimitive structure to the Geom object.
Definition: geom.h:101
PTA_int modify_ends()
Returns a modifiable pointer to the primitive ends array, so application code can directly fiddle wit...
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
void reverse_in_place()
Reverses all of the primitives within this Geom, leaving the results in place.
Definition: geom.cxx:520
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
Definition: bamWriter.cxx:425
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_num_vertices
Returns the number of indices used by all the primitives in this object.
Definition: geomPrimitive.h:99
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:1304
void add_primitive(const GeomPrimitive *primitive)
Inserts a new GeomPrimitive structure to the Geom object.
Definition: geom.I:116
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void make_lines_in_place()
Replaces the GeomPrimitives within this Geom with corresponding GeomLines, representing a wireframe o...
Definition: geom.cxx:786
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
This data object is returned by GeomVertexArrayData::get_handle() or modify_handle().
Encapsulates the data from a Geom, pre-fetched for one stage of the pipeline.
Definition: geom.h:405
A table of objects that are saved within the graphics context for reference by handle later...
void rotate_in_place()
Rotates all of the primitives within this Geom, leaving the results in place.
Definition: geom.cxx:557
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class&#39;s make_from_bam() method to read in all...
void offset_vertices(const GeomVertexData *data, int offset)
Replaces a Geom&#39;s vertex table with a new table, and simultaneously adds the indicated offset to all ...
Definition: geom.cxx:192
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 template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
virtual void evict_callback()
Called when the entry is evicted from the cache, this should clean up the owning object appropriately...
Definition: geom.cxx:1726
bool draw(GraphicsStateGuardianBase *gsg, const GeomVertexDataPipelineReader *data_reader, bool force) const
The implementation of Geom::draw().
Definition: geom.cxx:1847
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
void make_adjacency_in_place()
Replaces the GeomPrimitives within this Geom with corresponding versions with adjacency information...
Definition: geom.cxx:897
A lightweight class that represents a single element that may be timed and/or counted via stats...
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable&#39;s make function...
Definition: bamReader.I:275
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
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
bool is_geom_queued(const Geom *geom) const
Returns true if the geom has been queued on this GSG, false otherwise.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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:1184
virtual Geom * make_copy() const
Returns a newly-allocated Geom that is a shallow copy of this one.
Definition: geom.cxx:100
CPT(GeomVertexData) Geom
Returns a GeomVertexData that represents the results of computing the vertex animation on the CPU for...
Definition: geom.cxx:306
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:1680
Similar to MutexHolder, but for a light mutex.
void clear_vertices()
Removes all of the vertices and primitives from the object, so they can be re-added.
void clear_minmax()
Undoes a previous call to set_minmax(), and allows the minimum and maximum values to be recomputed no...
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
Definition: geom.h:54
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
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:1280
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
CPTA_int get_ends() const
Returns a const pointer to the primitive ends array so application code can read it directly...
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
int get_vertex(int i) const
Returns the ith vertex index in the table.
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
remove_primitive
Removes the ith primitive from the list.
Definition: geom.h:101
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
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
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 GeomVertexData *vertex_data) const
Verifies that the primitive only references vertices that actually exist within the indicated GeomVer...
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
This class defines the physical layout of the vertex data stored within a Geom.
bool check_valid() const
Verifies that the all of the primitives within the geom reference vertices that actually exist within...
Definition: geom.cxx:1059
This base class provides basic reference counting, but also can be used with a CopyOnWritePointer to ...
get_primitive_type
Returns the fundamental primitive type that is common to all GeomPrimitives added within the Geom...
Definition: geom.h:74
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
void make_patches_in_place()
Replaces the GeomPrimitives within this Geom with corresponding GeomPatches.
Definition: geom.cxx:860
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
void set_vertex_data(const GeomVertexData *data)
Replaces the Geom&#39;s underlying vertex data table with a completely new table.
Definition: geom.cxx:171
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the geom context only on the indicated object, if it exists there.
Definition: geom.cxx:1228
A thread; that is, a lightweight process.
Definition: thread.h:46
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:1205
int release_all()
Frees the context allocated on all objects for which the geom has been declared.
Definition: geom.cxx:1246
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
virtual bool copy_primitives_from(const Geom *other)
Copies the primitives from the indicated Geom into this one.
Definition: geom.cxx:939
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
static UpdateSeq get_next_modified()
Returns a monotonically increasing sequence.
Definition: geom.cxx:1322
void decompose_in_place()
Decomposes all of the primitives within this Geom, leaving the results in place.
Definition: geom.cxx:446
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...
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
void make_points_in_place()
Replaces the GeomPrimitives within this Geom with corresponding GeomPoints.
Definition: geom.cxx:823
Encapsulates the data from a GeomVertexData, pre-fetched for one stage of the pipeline.
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
int make_nonindexed(bool composite_only)
Converts the geom from indexed to nonindexed by duplicating vertices as necessary.
Definition: geom.cxx:234
A class to retrieve the individual data elements previously stored in a Datagram. ...
void operator=(const Geom &copy)
The copy assignment operator is not pipeline-safe.
Definition: geom.cxx:71
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static void register_with_read_factory()
Tells the BamReader how to create objects of type Geom.
Definition: geom.cxx:1641
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:1214
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
This is a sequence number that increments monotonically.
Definition: updateSeq.h:37
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
Encapsulates the data from a GeomPrimitive, pre-fetched for one stage of the pipeline.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
void make_indexed()
Converts the primitive from nonindexed form to indexed form.
get_num_unused_vertices_per_primitive
Returns the number of vertices that are added between primitives that aren&#39;t, strictly speaking...
bool is_indexed() const
Returns true if the primitive is indexed, false otherwise.
Definition: geomPrimitive.I:86
bool request_resident() const
Returns true if all the primitive arrays are currently resident in memory.
Definition: geom.cxx:1001
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_num_vertices_per_primitive
If the primitive type is a simple type in which all primitives have the same number of vertices...
This object provides the functionality of both a GeomVertexReader and a GeomVertexWriter, combined together into one convenient package.
bool dequeue_geom(Geom *geom)
Removes a geom from the queued list of geoms to be prepared.
Similar to PointerToArray, except that its contents may not be modified.
This is the data for one array of a GeomVertexData structure.
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