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  * @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  */
1002 bool Geom::
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  */
1031 void Geom::
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  */
1060 bool Geom::
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  */
1075 bool Geom::
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  */
1185 void Geom::
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  */
1206 void Geom::
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  */
1215 bool Geom::
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  */
1229 bool Geom::
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  */
1247 int Geom::
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  */
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  */
1305 bool Geom::
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  */
1642 void Geom::
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  */
1651 void Geom::
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  */
1681 void Geom::
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  */
1727 void Geom::CacheEntry::
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 }
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,...
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:1652
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:1032
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:1306
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's make_from_bam() method to read in all...
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
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:1728
bool draw(GraphicsStateGuardianBase *gsg, const GeomVertexDataPipelineReader *data_reader, bool force) const
The implementation of Geom::draw().
Definition: geom.cxx:1849
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:899
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'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:1186
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:1682
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:1282
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:1061
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'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:1230
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:1207
int release_all()
Frees the context allocated on all objects for which the geom has been declared.
Definition: geom.cxx:1248
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:941
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:1324
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:1643
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
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'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:1003
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,...
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