Panda3D
geom.cxx
1 // Filename: geom.cxx
2 // Created by: drose (06Mar05)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "geom.h"
16 #include "geomPoints.h"
17 #include "geomVertexReader.h"
18 #include "geomVertexRewriter.h"
19 #include "graphicsStateGuardianBase.h"
20 #include "preparedGraphicsObjects.h"
21 #include "pStatTimer.h"
22 #include "bamReader.h"
23 #include "bamWriter.h"
24 #include "boundingSphere.h"
25 #include "boundingBox.h"
26 #include "lightMutexHolder.h"
27 #include "config_mathutil.h"
28 
29 UpdateSeq Geom::_next_modified;
30 PStatCollector Geom::_draw_primitive_setup_pcollector("Draw:Primitive:Setup");
31 
32 TypeHandle Geom::_type_handle;
33 TypeHandle Geom::CDataCache::_type_handle;
34 TypeHandle Geom::CacheEntry::_type_handle;
35 TypeHandle Geom::CData::_type_handle;
36 TypeHandle GeomPipelineReader::_type_handle;
37 
38 ////////////////////////////////////////////////////////////////////
39 // Function: Geom::make_cow_copy
40 // Access: Protected, Virtual
41 // Description: Required to implement CopyOnWriteObject.
42 ////////////////////////////////////////////////////////////////////
43 PT(CopyOnWriteObject) Geom::
44 make_cow_copy() {
45  return make_copy();
46 }
47 
48 ////////////////////////////////////////////////////////////////////
49 // Function: Geom::Constructor
50 // Access: Published
51 // Description:
52 ////////////////////////////////////////////////////////////////////
53 Geom::
54 Geom(const GeomVertexData *data) {
55  // Let's ensure the vertex data gets set on all stages at once.
56  OPEN_ITERATE_ALL_STAGES(_cycler) {
57  CDStageWriter cdata(_cycler, pipeline_stage);
58  cdata->_data = (GeomVertexData *)data;
59  }
60  CLOSE_ITERATE_ALL_STAGES(_cycler);
61 }
62 
63 ////////////////////////////////////////////////////////////////////
64 // Function: Geom::Copy Constructor
65 // Access: Protected
66 // Description: Use make_copy() to duplicate a Geom.
67 ////////////////////////////////////////////////////////////////////
68 Geom::
69 Geom(const Geom &copy) :
70  CopyOnWriteObject(copy),
71  _cycler(copy._cycler)
72 {
73 }
74 
75 ////////////////////////////////////////////////////////////////////
76 // Function: Geom::Copy Assignment Operator
77 // Access: Published
78 // Description: The copy assignment operator is not pipeline-safe.
79 // This will completely obliterate all stages of the
80 // pipeline, so don't do it for a Geom that is actively
81 // being used for rendering.
82 ////////////////////////////////////////////////////////////////////
83 void Geom::
84 operator = (const Geom &copy) {
85  CopyOnWriteObject::operator = (copy);
86 
87  clear_cache();
88 
89  _cycler = copy._cycler;
90 
91  OPEN_ITERATE_ALL_STAGES(_cycler) {
92  CDStageWriter cdata(_cycler, pipeline_stage);
93  mark_internal_bounds_stale(cdata);
94  }
95  CLOSE_ITERATE_ALL_STAGES(_cycler);
96 }
97 
98 ////////////////////////////////////////////////////////////////////
99 // Function: Geom::Destructor
100 // Access: Published, Virtual
101 // Description:
102 ////////////////////////////////////////////////////////////////////
103 Geom::
104 ~Geom() {
105  clear_cache();
106  release_all();
107 }
108 
109 ////////////////////////////////////////////////////////////////////
110 // Function: Geom::make_copy
111 // Access: Protected, Virtual
112 // Description: Returns a newly-allocated Geom that is a shallow copy
113 // of this one. It will be a different Geom pointer,
114 // but its internal data may or may not be shared with
115 // that of the original Geom.
116 ////////////////////////////////////////////////////////////////////
117 Geom *Geom::
118 make_copy() const {
119  return new Geom(*this);
120 }
121 
122 ////////////////////////////////////////////////////////////////////
123 // Function: Geom::set_usage_hint
124 // Access: Published
125 // Description: Changes the UsageHint hint for all of the primitives
126 // on this Geom to the same value. See
127 // get_usage_hint().
128 //
129 // Don't call this in a downstream thread unless you
130 // don't mind it blowing away other changes you might
131 // have recently made in an upstream thread.
132 ////////////////////////////////////////////////////////////////////
133 void Geom::
134 set_usage_hint(Geom::UsageHint usage_hint) {
135  Thread *current_thread = Thread::get_current_thread();
136  CDWriter cdata(_cycler, true, current_thread);
137  cdata->_usage_hint = usage_hint;
138 
139  Primitives::iterator pi;
140  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
141  PT(GeomPrimitive) prim = (*pi).get_write_pointer();
142  prim->set_usage_hint(usage_hint);
143  }
144 
145  clear_cache_stage(current_thread);
146  cdata->_modified = Geom::get_next_modified();
147 }
148 
149 ////////////////////////////////////////////////////////////////////
150 // Function: Geom::modify_vertex_data
151 // Access: Published
152 // Description: Returns a modifiable pointer to the GeomVertexData,
153 // so that application code may directly maniuplate the
154 // geom's underlying data.
155 //
156 // Don't call this in a downstream thread unless you
157 // don't mind it blowing away other changes you might
158 // have recently made in an upstream thread.
159 ////////////////////////////////////////////////////////////////////
160 PT(GeomVertexData) Geom::
161 modify_vertex_data() {
162  Thread *current_thread = Thread::get_current_thread();
163  // Perform copy-on-write: if the reference count on the vertex data
164  // is greater than 1, assume some other Geom has the same pointer,
165  // so make a copy of it first.
166  CDWriter cdata(_cycler, true, current_thread);
167  clear_cache_stage(current_thread);
168  mark_internal_bounds_stale(cdata);
169  return cdata->_data.get_write_pointer();
170 }
171 
172 ////////////////////////////////////////////////////////////////////
173 // Function: Geom::set_vertex_data
174 // Access: Published
175 // Description: Replaces the Geom's underlying vertex data table with
176 // a completely new table.
177 //
178 // Don't call this in a downstream thread unless you
179 // don't mind it blowing away other changes you might
180 // have recently made in an upstream thread.
181 ////////////////////////////////////////////////////////////////////
182 void Geom::
184  Thread *current_thread = Thread::get_current_thread();
185  nassertv(check_will_be_valid(data));
186  CDWriter cdata(_cycler, true, current_thread);
187  cdata->_data = (GeomVertexData *)data;
188  clear_cache_stage(current_thread);
189  mark_internal_bounds_stale(cdata);
190  reset_geom_rendering(cdata);
191 }
192 
193 ////////////////////////////////////////////////////////////////////
194 // Function: Geom::offset_vertices
195 // Access: Published
196 // Description: Replaces a Geom's vertex table with a new table, and
197 // simultaneously adds the indicated offset to all
198 // vertex references within the Geom's primitives. This
199 // is intended to be used to combine multiple
200 // GeomVertexDatas from different Geoms into a single
201 // big buffer, with each Geom referencing a subset of
202 // the vertices in the buffer.
203 //
204 // Don't call this in a downstream thread unless you
205 // don't mind it blowing away other changes you might
206 // have recently made in an upstream thread.
207 ////////////////////////////////////////////////////////////////////
208 void Geom::
209 offset_vertices(const GeomVertexData *data, int offset) {
210  Thread *current_thread = Thread::get_current_thread();
211  CDWriter cdata(_cycler, true, current_thread);
212  cdata->_data = (GeomVertexData *)data;
213 
214 #ifndef NDEBUG
215  bool all_is_valid = true;
216 #endif
217  Primitives::iterator pi;
218  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
219  PT(GeomPrimitive) prim = (*pi).get_write_pointer();
220  prim->offset_vertices(offset);
221 
222 #ifndef NDEBUG
223  if (!prim->check_valid(data)) {
224  gobj_cat.warning()
225  << *prim << " is invalid for " << *data << ":\n";
226  prim->write(gobj_cat.warning(false), 4);
227 
228  all_is_valid = false;
229  }
230 #endif
231  }
232 
233  cdata->_modified = Geom::get_next_modified();
234  clear_cache_stage(current_thread);
235  nassertv(all_is_valid);
236 }
237 
238 ////////////////////////////////////////////////////////////////////
239 // Function: Geom::make_nonindexed
240 // Access: Published
241 // Description: Converts the geom from indexed to nonindexed by
242 // duplicating vertices as necessary. If composite_only
243 // is true, then only composite primitives such as
244 // trifans and tristrips are converted. Returns the
245 // number of GeomPrimitive objects converted.
246 //
247 // Don't call this in a downstream thread unless you
248 // don't mind it blowing away other changes you might
249 // have recently made in an upstream thread.
250 ////////////////////////////////////////////////////////////////////
251 int Geom::
252 make_nonindexed(bool composite_only) {
253  Thread *current_thread = Thread::get_current_thread();
254  int num_changed = 0;
255 
256  CDWriter cdata(_cycler, true, current_thread);
257  CPT(GeomVertexData) orig_data = cdata->_data.get_read_pointer();
258  PT(GeomVertexData) new_data = new GeomVertexData(*orig_data);
259  new_data->clear_rows();
260 
261 #ifndef NDEBUG
262  bool all_is_valid = true;
263 #endif
264  Primitives::iterator pi;
265  Primitives new_prims;
266  new_prims.reserve(cdata->_primitives.size());
267  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
268  PT(GeomPrimitive) primitive = (*pi).get_read_pointer()->make_copy();
269  new_prims.push_back(primitive.p());
270 
271  // GeomPoints are considered "composite" for the purposes of
272  // making nonindexed, since there's no particular advantage to
273  // having indexed points (as opposed to, say, indexed triangles or
274  // indexed lines).
275  if (primitive->is_indexed() &&
276  (primitive->is_composite() ||
277  primitive->is_exact_type(GeomPoints::get_class_type()) ||
278  !composite_only)) {
279  primitive->make_nonindexed(new_data, orig_data);
280  ++num_changed;
281  } else {
282  // If it's a simple primitive, pack it anyway, so it can share
283  // the same GeomVertexData.
284  primitive->pack_vertices(new_data, orig_data);
285  }
286 
287 #ifndef NDEBUG
288  if (!primitive->check_valid(new_data)) {
289  all_is_valid = false;
290  }
291 #endif
292  }
293 
294  nassertr(all_is_valid, 0);
295 
296  if (num_changed != 0) {
297  // If any at all were changed, then keep the result (otherwise,
298  // discard it, since we might have de-optimized the indexed
299  // geometry a bit).
300  cdata->_data = new_data;
301  cdata->_primitives.swap(new_prims);
302  cdata->_modified = Geom::get_next_modified();
303  clear_cache_stage(current_thread);
304  }
305 
306  return num_changed;
307 }
308 
309 ////////////////////////////////////////////////////////////////////
310 // Function: Geom::set_primitive
311 // Access: Published
312 // Description: Replaces the ith GeomPrimitive object stored within
313 // the Geom with the new object.
314 //
315 // Don't call this in a downstream thread unless you
316 // don't mind it blowing away other changes you might
317 // have recently made in an upstream thread.
318 ////////////////////////////////////////////////////////////////////
319 void Geom::
320 set_primitive(int i, const GeomPrimitive *primitive) {
321  Thread *current_thread = Thread::get_current_thread();
322  CDWriter cdata(_cycler, true, current_thread);
323  nassertv(i >= 0 && i < (int)cdata->_primitives.size());
324  nassertv(primitive->check_valid(cdata->_data.get_read_pointer()));
325 
326  // All primitives within a particular Geom must have the same
327  // fundamental primitive type (triangles, points, or lines).
328  nassertv(cdata->_primitive_type == PT_none ||
329  cdata->_primitive_type == primitive->get_primitive_type());
330 
331  // They also should have a compatible shade model.
332  CPT(GeomPrimitive) compat = primitive->match_shade_model(cdata->_shade_model);
333  nassertv_always(compat != (GeomPrimitive *)NULL);
334 
335  cdata->_primitives[i] = (GeomPrimitive *)compat.p();
336  PrimitiveType new_primitive_type = compat->get_primitive_type();
337  if (new_primitive_type != cdata->_primitive_type) {
338  cdata->_primitive_type = new_primitive_type;
339  }
340  ShadeModel new_shade_model = compat->get_shade_model();
341  if (new_shade_model != cdata->_shade_model &&
342  new_shade_model != SM_uniform) {
343  cdata->_shade_model = new_shade_model;
344  }
345 
346  reset_geom_rendering(cdata);
347  cdata->_got_usage_hint = false;
348  cdata->_modified = Geom::get_next_modified();
349  clear_cache_stage(current_thread);
350  mark_internal_bounds_stale(cdata);
351 }
352 
353 ////////////////////////////////////////////////////////////////////
354 // Function: Geom::add_primitive
355 // Access: Published
356 // Description: Adds a new GeomPrimitive structure to the Geom
357 // object. This specifies a particular subset of
358 // vertices that are used to define geometric primitives
359 // of the indicated type.
360 //
361 // Don't call this in a downstream thread unless you
362 // don't mind it blowing away other changes you might
363 // have recently made in an upstream thread.
364 ////////////////////////////////////////////////////////////////////
365 void Geom::
366 add_primitive(const GeomPrimitive *primitive) {
367  Thread *current_thread = Thread::get_current_thread();
368  CDWriter cdata(_cycler, true, current_thread);
369 
370  nassertv(primitive->check_valid(cdata->_data.get_read_pointer()));
371 
372  // All primitives within a particular Geom must have the same
373  // fundamental primitive type (triangles, points, or lines).
374  nassertv(cdata->_primitive_type == PT_none ||
375  cdata->_primitive_type == primitive->get_primitive_type());
376 
377  // They also should have a compatible shade model.
378  CPT(GeomPrimitive) compat = primitive->match_shade_model(cdata->_shade_model);
379  nassertv_always(compat != (GeomPrimitive *)NULL);
380 
381  cdata->_primitives.push_back((GeomPrimitive *)compat.p());
382  PrimitiveType new_primitive_type = compat->get_primitive_type();
383  if (new_primitive_type != cdata->_primitive_type) {
384  cdata->_primitive_type = new_primitive_type;
385  }
386  ShadeModel new_shade_model = compat->get_shade_model();
387  if (new_shade_model != cdata->_shade_model &&
388  new_shade_model != SM_uniform) {
389  cdata->_shade_model = new_shade_model;
390  }
391 
392  reset_geom_rendering(cdata);
393  cdata->_got_usage_hint = false;
394  cdata->_modified = Geom::get_next_modified();
395  clear_cache_stage(current_thread);
396  mark_internal_bounds_stale(cdata);
397 }
398 
399 ////////////////////////////////////////////////////////////////////
400 // Function: Geom::remove_primitive
401 // Access: Published
402 // Description: Removes the ith primitive from the list.
403 //
404 // Don't call this in a downstream thread unless you
405 // don't mind it blowing away other changes you might
406 // have recently made in an upstream thread.
407 ////////////////////////////////////////////////////////////////////
408 void Geom::
410  Thread *current_thread = Thread::get_current_thread();
411  CDWriter cdata(_cycler, true, current_thread);
412  nassertv(i >= 0 && i < (int)cdata->_primitives.size());
413  cdata->_primitives.erase(cdata->_primitives.begin() + i);
414  if (cdata->_primitives.empty()) {
415  cdata->_primitive_type = PT_none;
416  cdata->_shade_model = SM_uniform;
417  }
418  reset_geom_rendering(cdata);
419  cdata->_got_usage_hint = false;
420  cdata->_modified = Geom::get_next_modified();
421  clear_cache_stage(current_thread);
422  mark_internal_bounds_stale(cdata);
423 }
424 
425 ////////////////////////////////////////////////////////////////////
426 // Function: Geom::clear_primitives
427 // Access: Published
428 // Description: Removes all the primitives from the Geom object (but
429 // keeps the same table of vertices). You may then
430 // re-add primitives one at a time via calls to
431 // add_primitive().
432 //
433 // Don't call this in a downstream thread unless you
434 // don't mind it blowing away other changes you might
435 // have recently made in an upstream thread.
436 ////////////////////////////////////////////////////////////////////
437 void Geom::
439  Thread *current_thread = Thread::get_current_thread();
440  CDWriter cdata(_cycler, true, current_thread);
441  cdata->_primitives.clear();
442  cdata->_primitive_type = PT_none;
443  cdata->_shade_model = SM_uniform;
444  reset_geom_rendering(cdata);
445  clear_cache_stage(current_thread);
446  mark_internal_bounds_stale(cdata);
447 }
448 
449 ////////////////////////////////////////////////////////////////////
450 // Function: Geom::decompose_in_place
451 // Access: Published
452 // Description: Decomposes all of the primitives within this Geom,
453 // leaving the results in place. See
454 // GeomPrimitive::decompose().
455 //
456 // Don't call this in a downstream thread unless you
457 // don't mind it blowing away other changes you might
458 // have recently made in an upstream thread.
459 ////////////////////////////////////////////////////////////////////
460 void Geom::
462  Thread *current_thread = Thread::get_current_thread();
463  CDWriter cdata(_cycler, true, current_thread);
464 
465 #ifndef NDEBUG
466  bool all_is_valid = true;
467 #endif
468  Primitives::iterator pi;
469  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
470  CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->decompose();
471  (*pi) = (GeomPrimitive *)new_prim.p();
472 
473 #ifndef NDEBUG
474  if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
475  all_is_valid = false;
476  }
477 #endif
478  }
479 
480  cdata->_modified = Geom::get_next_modified();
481  reset_geom_rendering(cdata);
482  clear_cache_stage(current_thread);
483 
484  nassertv(all_is_valid);
485 }
486 
487 ////////////////////////////////////////////////////////////////////
488 // Function: Geom::doubleside_in_place
489 // Access: Published
490 // Description: Doublesides all of the primitives within this Geom,
491 // leaving the results in place. See
492 // GeomPrimitive::doubleside().
493 //
494 // Don't call this in a downstream thread unless you
495 // don't mind it blowing away other changes you might
496 // have recently made in an upstream thread.
497 ////////////////////////////////////////////////////////////////////
498 void Geom::
500  Thread *current_thread = Thread::get_current_thread();
501  CDWriter cdata(_cycler, true, current_thread);
502 
503 #ifndef NDEBUG
504  bool all_is_valid = true;
505 #endif
506  Primitives::iterator pi;
507  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
508  CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->doubleside();
509  (*pi) = (GeomPrimitive *)new_prim.p();
510 
511 #ifndef NDEBUG
512  if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
513  all_is_valid = false;
514  }
515 #endif
516  }
517 
518  cdata->_modified = Geom::get_next_modified();
519  reset_geom_rendering(cdata);
520  clear_cache_stage(current_thread);
521 
522  nassertv(all_is_valid);
523 }
524 
525 ////////////////////////////////////////////////////////////////////
526 // Function: Geom::reverse_in_place
527 // Access: Published
528 // Description: Reverses all of the primitives within this Geom,
529 // leaving the results in place. See
530 // GeomPrimitive::reverse().
531 //
532 // Don't call this in a downstream thread unless you
533 // don't mind it blowing away other changes you might
534 // have recently made in an upstream thread.
535 ////////////////////////////////////////////////////////////////////
536 void Geom::
538  Thread *current_thread = Thread::get_current_thread();
539  CDWriter cdata(_cycler, true, current_thread);
540 
541 #ifndef NDEBUG
542  bool all_is_valid = true;
543 #endif
544  Primitives::iterator pi;
545  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
546  CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->reverse();
547  (*pi) = (GeomPrimitive *)new_prim.p();
548 
549 #ifndef NDEBUG
550  if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
551  all_is_valid = false;
552  }
553 #endif
554  }
555 
556  cdata->_modified = Geom::get_next_modified();
557  reset_geom_rendering(cdata);
558  clear_cache_stage(current_thread);
559 
560  nassertv(all_is_valid);
561 }
562 
563 ////////////////////////////////////////////////////////////////////
564 // Function: Geom::rotate_in_place
565 // Access: Published
566 // Description: Rotates all of the primitives within this Geom,
567 // leaving the results in place. See
568 // GeomPrimitive::rotate().
569 //
570 // Don't call this in a downstream thread unless you
571 // don't mind it blowing away other changes you might
572 // have recently made in an upstream thread.
573 ////////////////////////////////////////////////////////////////////
574 void Geom::
576  Thread *current_thread = Thread::get_current_thread();
577  CDWriter cdata(_cycler, true, current_thread);
578 
579 #ifndef NDEBUG
580  bool all_is_valid = true;
581 #endif
582  Primitives::iterator pi;
583  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
584  CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->rotate();
585  (*pi) = (GeomPrimitive *)new_prim.p();
586 
587 #ifndef NDEBUG
588  if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
589  all_is_valid = false;
590  }
591 #endif
592  }
593 
594  switch (cdata->_shade_model) {
595  case SM_flat_first_vertex:
596  cdata->_shade_model = SM_flat_last_vertex;
597  break;
598 
599  case SM_flat_last_vertex:
600  cdata->_shade_model = SM_flat_first_vertex;
601  break;
602 
603  default:
604  break;
605  }
606 
607  cdata->_modified = Geom::get_next_modified();
608  clear_cache_stage(current_thread);
609 
610  nassertv(all_is_valid);
611 }
612 
613 ////////////////////////////////////////////////////////////////////
614 // Function: Geom::unify_in_place
615 // Access: Published
616 // Description: Unifies all of the primitives contained within this
617 // Geom into a single (or as few as possible, within the
618 // constraints of max_indices) primitive objects. This
619 // may require decomposing the primitives if, for
620 // instance, the Geom contains both triangle strips and
621 // triangle fans.
622 //
623 // max_indices represents the maximum number of indices
624 // that will be put in any one GeomPrimitive. If
625 // preserve_order is true, then the primitives will not
626 // be reordered during the operation, even if this
627 // results in a suboptimal result.
628 //
629 // Don't call this in a downstream thread unless you
630 // don't mind it blowing away other changes you might
631 // have recently made in an upstream thread.
632 ////////////////////////////////////////////////////////////////////
633 void Geom::
634 unify_in_place(int max_indices, bool preserve_order) {
635  if (gobj_cat.is_debug()) {
636  gobj_cat.debug()
637  << "unify_in_place(" << max_indices << ", " << preserve_order
638  << "): " << *this << "\n";
639  }
640 
641  Thread *current_thread = Thread::get_current_thread();
642  if (get_num_primitives() <= 1) {
643  // If we don't have more than one primitive to start with, no need
644  // to do anything.
645  return;
646  }
647 
648  CDWriter cdata(_cycler, true, current_thread);
649 
650  typedef pmap<TypeHandle, PT(GeomPrimitive) > NewPrims;
651 
652  NewPrims new_prims;
653 
654  bool keep_different_types = preserve_triangle_strips && !preserve_order;
655 
656  Primitives::const_iterator pi;
657  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
658  CPT(GeomPrimitive) primitive = (*pi).get_read_pointer();
659  NewPrims::iterator npi = new_prims.find(primitive->get_type());
660  if (npi == new_prims.end()) {
661  // This is the first primitive of this type.
662  if (!keep_different_types && !new_prims.empty()) {
663  // Actually, since we aren't trying to keep the different
664  // types of primitives, we should try to combine this type and
665  // the other type by decomposing them both (into triangles,
666  // segments, or whatever).
667 
668  // First, decompose the incoming one.
669  primitive = primitive->decompose();
670  npi = new_prims.find(primitive->get_type());
671  if (npi == new_prims.end()) {
672  // That didn't help, so decompose the one already in the
673  // table.
674  nassertv(new_prims.size() == 1);
675  npi = new_prims.begin();
676  CPT(GeomPrimitive) np = (*npi).second->decompose();
677  new_prims.clear();
678  new_prims.insert(NewPrims::value_type(np->get_type(), np->make_copy()));
679  npi = new_prims.find(primitive->get_type());
680  }
681  }
682  }
683 
684  if (npi == new_prims.end()) {
685  // This is the first primitive of this type. Just store it.
686  new_prims.insert(NewPrims::value_type(primitive->get_type(), primitive->make_copy()));
687 
688  } else {
689  // We have already encountered another primitive of this type.
690  // Combine them.
691  combine_primitives((*npi).second, primitive, current_thread);
692  }
693  }
694 
695  // Now, we have one or more primitives, but only one of each type.
696 #ifndef NDEBUG
697  if (!keep_different_types && new_prims.size() > 1) {
698  // This shouldn't be possible, because we decompose as we go, in
699  // the loop above. (We have to decompose as we go to preserve the
700  // ordering of the primitives.)
701  nassertv(false);
702  }
703 #endif
704 
705  // Finally, iterate through the remaining primitives, and copy them
706  // to the output list.
707  cdata->_primitives.clear();
708  NewPrims::iterator npi;
709  for (npi = new_prims.begin(); npi != new_prims.end(); ++npi) {
710  GeomPrimitive *prim = (*npi).second;
711 
712  nassertv(prim->check_valid(cdata->_data.get_read_pointer()));
713 
714  // Each new primitive, naturally, inherits the Geom's overall
715  // shade model.
716  prim->set_shade_model(cdata->_shade_model);
717 
718  // Should we split it up again to satisfy max_indices?
719  if (prim->get_num_vertices() > max_indices) {
720  // Copy prim into smaller prims, no one of which has more than
721  // max_indices vertices.
722  int i = 0;
723 
724  while (i < prim->get_num_primitives()) {
725  PT(GeomPrimitive) smaller = prim->make_copy();
726  smaller->clear_vertices();
727  while (i < prim->get_num_primitives() &&
728  smaller->get_num_vertices() + prim->get_primitive_num_vertices(i) < max_indices) {
729  int start = prim->get_primitive_start(i);
730  int end = prim->get_primitive_end(i);
731  for (int n = start; n < end; ++n) {
732  smaller->add_vertex(prim->get_vertex(n));
733  }
734  smaller->close_primitive();
735 
736  ++i;
737  }
738 
739  cdata->_primitives.push_back(smaller.p());
740  }
741 
742  } else {
743  // The prim has few enough vertices; keep it.
744  cdata->_primitives.push_back(prim);
745  }
746  }
747 
748  cdata->_modified = Geom::get_next_modified();
749  clear_cache_stage(current_thread);
750  reset_geom_rendering(cdata);
751 }
752 
753 ////////////////////////////////////////////////////////////////////
754 // Function: Geom::make_lines_in_place
755 // Access: Published
756 // Description: Replaces the GeomPrimitives within this Geom with
757 // corresponding GeomLines, representing a wireframe
758 // of the primitives. See GeomPrimitive::make_lines().
759 //
760 // Don't call this in a downstream thread unless you
761 // don't mind it blowing away other changes you might
762 // have recently made in an upstream thread.
763 ////////////////////////////////////////////////////////////////////
764 void Geom::
766  Thread *current_thread = Thread::get_current_thread();
767  CDWriter cdata(_cycler, true, current_thread);
768 
769 #ifndef NDEBUG
770  bool all_is_valid = true;
771 #endif
772  Primitives::iterator pi;
773  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
774  CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_lines();
775  (*pi) = (GeomPrimitive *)new_prim.p();
776 
777 #ifndef NDEBUG
778  if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
779  all_is_valid = false;
780  }
781 #endif
782  }
783 
784  cdata->_modified = Geom::get_next_modified();
785  reset_geom_rendering(cdata);
786  clear_cache_stage(current_thread);
787 
788  nassertv(all_is_valid);
789 }
790 
791 ////////////////////////////////////////////////////////////////////
792 // Function: Geom::make_points_in_place
793 // Access: Published
794 // Description: Replaces the GeomPrimitives within this Geom with
795 // corresponding GeomPoints. See
796 // GeomPrimitive::make_points().
797 //
798 // Don't call this in a downstream thread unless you
799 // don't mind it blowing away other changes you might
800 // have recently made in an upstream thread.
801 ////////////////////////////////////////////////////////////////////
802 void Geom::
804  Thread *current_thread = Thread::get_current_thread();
805  CDWriter cdata(_cycler, true, current_thread);
806 
807 #ifndef NDEBUG
808  bool all_is_valid = true;
809 #endif
810  Primitives::iterator pi;
811  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
812  CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_points();
813  (*pi) = (GeomPrimitive *)new_prim.p();
814 
815 #ifndef NDEBUG
816  if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
817  all_is_valid = false;
818  }
819 #endif
820  }
821 
822  cdata->_modified = Geom::get_next_modified();
823  reset_geom_rendering(cdata);
824  clear_cache_stage(current_thread);
825 
826  nassertv(all_is_valid);
827 }
828 
829 ////////////////////////////////////////////////////////////////////
830 // Function: Geom::make_patches_in_place
831 // Access: Published
832 // Description: Replaces the GeomPrimitives within this Geom with
833 // corresponding GeomPatches. See
834 // GeomPrimitive::make_patches().
835 //
836 // Don't call this in a downstream thread unless you
837 // don't mind it blowing away other changes you might
838 // have recently made in an upstream thread.
839 ////////////////////////////////////////////////////////////////////
840 void Geom::
842  Thread *current_thread = Thread::get_current_thread();
843  CDWriter cdata(_cycler, true, current_thread);
844 
845 #ifndef NDEBUG
846  bool all_is_valid = true;
847 #endif
848  Primitives::iterator pi;
849  for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
850  CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_patches();
851  (*pi) = (GeomPrimitive *)new_prim.p();
852 
853 #ifndef NDEBUG
854  if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
855  all_is_valid = false;
856  }
857 #endif
858  }
859 
860  cdata->_modified = Geom::get_next_modified();
861  reset_geom_rendering(cdata);
862  clear_cache_stage(current_thread);
863 
864  nassertv(all_is_valid);
865 }
866 
867 ////////////////////////////////////////////////////////////////////
868 // Function: Geom::copy_primitives_from
869 // Access: Published, Virtual
870 // Description: Copies the primitives from the indicated Geom into
871 // this one. This does require that both Geoms contain
872 // the same fundamental type primitives, both have a
873 // compatible shade model, and both use the same
874 // GeomVertexData. Both Geoms must also be the same
875 // specific class type (i.e. if one is a GeomTextGlyph,
876 // they both must be.)
877 //
878 // Returns true if the copy is successful, or false
879 // otherwise (because the Geoms were mismatched).
880 ////////////////////////////////////////////////////////////////////
881 bool Geom::
882 copy_primitives_from(const Geom *other) {
883  if (get_primitive_type() != PT_none &&
884  other->get_primitive_type() != get_primitive_type()) {
885  return false;
886  }
887  if (get_vertex_data() != other->get_vertex_data()) {
888  return false;
889  }
890  if (get_type() != other->get_type()) {
891  return false;
892  }
893 
894  ShadeModel this_shade_model = get_shade_model();
895  ShadeModel other_shade_model = other->get_shade_model();
896  if (this_shade_model != SM_uniform && other_shade_model != SM_uniform &&
897  this_shade_model != other_shade_model) {
898  if ((this_shade_model == SM_flat_first_vertex && other_shade_model == SM_flat_last_vertex) ||
899  (this_shade_model == SM_flat_last_vertex && other_shade_model == SM_flat_first_vertex)) {
900  // This is acceptable; we can rotate the primitives to match.
901 
902  } else {
903  // Otherwise, we have incompatible shade models.
904  return false;
905  }
906  }
907 
908  int num_primitives = other->get_num_primitives();
909  for (int i = 0; i < num_primitives; i++) {
910  add_primitive(other->get_primitive(i));
911  }
912 
913  return true;
914 }
915 
916 ////////////////////////////////////////////////////////////////////
917 // Function: Geom::get_num_bytes
918 // Access: Published
919 // Description: Returns the number of bytes consumed by the geom and
920 // its primitives (but not including its vertex table).
921 ////////////////////////////////////////////////////////////////////
922 int Geom::
923 get_num_bytes() const {
924  CDReader cdata(_cycler);
925 
926  int num_bytes = sizeof(Geom);
927  Primitives::const_iterator pi;
928  for (pi = cdata->_primitives.begin();
929  pi != cdata->_primitives.end();
930  ++pi) {
931  num_bytes += (*pi).get_read_pointer()->get_num_bytes();
932  }
933 
934  return num_bytes;
935 }
936 
937 ////////////////////////////////////////////////////////////////////
938 // Function: Geom::request_resident
939 // Access: Published
940 // Description: Returns true if all the primitive arrays are
941 // currently resident in memory. If this returns false,
942 // the data will be brought back into memory shortly;
943 // try again later.
944 //
945 // This does not also test the Geom's associated
946 // GeomVertexData. That must be tested separately.
947 ////////////////////////////////////////////////////////////////////
948 bool Geom::
950  CDReader cdata(_cycler);
951 
952  bool resident = true;
953 
954  Primitives::const_iterator pi;
955  for (pi = cdata->_primitives.begin();
956  pi != cdata->_primitives.end();
957  ++pi) {
958  if (!(*pi).get_read_pointer()->request_resident()) {
959  resident = false;
960  }
961  }
962 
963  return resident;
964 }
965 
966 ////////////////////////////////////////////////////////////////////
967 // Function: Geom::transform_vertices
968 // Access: Published
969 // Description: Applies the indicated transform to all of the
970 // vertices in the Geom. If the Geom happens to share a
971 // vertex table with another Geom, this operation will
972 // duplicate the vertex table instead of breaking the
973 // other Geom; however, if multiple Geoms with shared
974 // tables are transformed by the same matrix, they will
975 // no longer share tables after the operation. Consider
976 // using the GeomTransformer if you will be applying the
977 // same transform to multiple Geoms.
978 ////////////////////////////////////////////////////////////////////
979 void Geom::
981  PT(GeomVertexData) new_data = modify_vertex_data();
982  CPT(GeomVertexFormat) format = new_data->get_format();
983 
984  int ci;
985  for (ci = 0; ci < format->get_num_points(); ci++) {
986  GeomVertexRewriter data(new_data, format->get_point(ci));
987 
988  while (!data.is_at_end()) {
989  const LPoint3 &point = data.get_data3();
990  data.set_data3(point * mat);
991  }
992  }
993  for (ci = 0; ci < format->get_num_vectors(); ci++) {
994  GeomVertexRewriter data(new_data, format->get_vector(ci));
995 
996  while (!data.is_at_end()) {
997  const LVector3 &vector = data.get_data3();
998  data.set_data3(normalize(vector * mat));
999  }
1000  }
1001 }
1002 
1003 ////////////////////////////////////////////////////////////////////
1004 // Function: Geom::check_valid
1005 // Access: Published
1006 // Description: Verifies that the all of the primitives within the
1007 // geom reference vertices that actually exist within
1008 // the geom's GeomVertexData. Returns true if the geom
1009 // appears to be valid, false otherwise.
1010 ////////////////////////////////////////////////////////////////////
1011 bool Geom::
1012 check_valid() const {
1013  Thread *current_thread = Thread::get_current_thread();
1014  GeomPipelineReader geom_reader(this, current_thread);
1015  GeomVertexDataPipelineReader data_reader(geom_reader.get_vertex_data(), current_thread);
1016  data_reader.check_array_readers();
1017  return geom_reader.check_valid(&data_reader);
1018 }
1019 
1020 ////////////////////////////////////////////////////////////////////
1021 // Function: Geom::check_valid
1022 // Access: Published
1023 // Description: Verifies that the all of the primitives within the
1024 // geom reference vertices that actually exist within
1025 // the indicated GeomVertexData. Returns true if the
1026 // geom appears to be valid, false otherwise.
1027 ////////////////////////////////////////////////////////////////////
1028 bool Geom::
1029 check_valid(const GeomVertexData *vertex_data) const {
1030  Thread *current_thread = Thread::get_current_thread();
1031  GeomPipelineReader geom_reader(this, current_thread);
1032  GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1033  data_reader.check_array_readers();
1034  return geom_reader.check_valid(&data_reader);
1035 }
1036 
1037 ////////////////////////////////////////////////////////////////////
1038 // Function: Geom::get_bounds
1039 // Access: Published
1040 // Description: Returns the bounding volume for the Geom.
1041 ////////////////////////////////////////////////////////////////////
1042 CPT(BoundingVolume) Geom::
1043 get_bounds(Thread *current_thread) const {
1044  CDLockedReader cdata(_cycler, current_thread);
1045  if (cdata->_user_bounds != (BoundingVolume *)NULL) {
1046  return cdata->_user_bounds;
1047  }
1048 
1049  if (cdata->_internal_bounds_stale) {
1050  CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
1051  compute_internal_bounds(cdataw, current_thread);
1052  return cdataw->_internal_bounds;
1053  }
1054  return cdata->_internal_bounds;
1055 }
1056 
1057 ////////////////////////////////////////////////////////////////////
1058 // Function: Geom::get_nested_vertices
1059 // Access: Published
1060 // Description: Returns the number of vertices rendered by all
1061 // primitives within the Geom.
1062 ////////////////////////////////////////////////////////////////////
1063 int Geom::
1064 get_nested_vertices(Thread *current_thread) const {
1065  CDLockedReader cdata(_cycler, current_thread);
1066  if (cdata->_internal_bounds_stale) {
1067  CDWriter cdataw(((Geom *)this)->_cycler, cdata, false);
1068  compute_internal_bounds(cdataw, current_thread);
1069  return cdataw->_nested_vertices;
1070  }
1071  return cdata->_nested_vertices;
1072 }
1073 
1074 ////////////////////////////////////////////////////////////////////
1075 // Function: Geom::output
1076 // Access: Published, Virtual
1077 // Description:
1078 ////////////////////////////////////////////////////////////////////
1079 void Geom::
1080 output(ostream &out) const {
1081  CDReader cdata(_cycler);
1082 
1083  // Get a list of the primitive types contained within this object.
1084  int num_faces = 0;
1085  pset<TypeHandle> types;
1086  Primitives::const_iterator pi;
1087  for (pi = cdata->_primitives.begin();
1088  pi != cdata->_primitives.end();
1089  ++pi) {
1090  CPT(GeomPrimitive) prim = (*pi).get_read_pointer();
1091  num_faces += prim->get_num_faces();
1092  types.insert(prim->get_type());
1093  }
1094 
1095  out << get_type() << " [";
1097  for (ti = types.begin(); ti != types.end(); ++ti) {
1098  out << " " << (*ti);
1099  }
1100  out << " ], " << num_faces << " faces";
1101 }
1102 
1103 ////////////////////////////////////////////////////////////////////
1104 // Function: Geom::write
1105 // Access: Published, Virtual
1106 // Description:
1107 ////////////////////////////////////////////////////////////////////
1108 void Geom::
1109 write(ostream &out, int indent_level) const {
1110  CDReader cdata(_cycler);
1111 
1112  // Get a list of the primitive types contained within this object.
1113  Primitives::const_iterator pi;
1114  for (pi = cdata->_primitives.begin();
1115  pi != cdata->_primitives.end();
1116  ++pi) {
1117  (*pi).get_read_pointer()->write(out, indent_level);
1118  }
1119 }
1120 
1121 ////////////////////////////////////////////////////////////////////
1122 // Function: Geom::clear_cache
1123 // Access: Published
1124 // Description: Removes all of the previously-cached results of
1125 // munge_geom().
1126 //
1127 // This blows away the entire cache, upstream and
1128 // downstream the pipeline. Use clear_cache_stage()
1129 // instead if you only want to blow away the cache at
1130 // the current stage and upstream.
1131 ////////////////////////////////////////////////////////////////////
1132 void Geom::
1133 clear_cache() {
1134  LightMutexHolder holder(_cache_lock);
1135  for (Cache::iterator ci = _cache.begin();
1136  ci != _cache.end();
1137  ++ci) {
1138  CacheEntry *entry = (*ci).second;
1139  entry->erase();
1140  }
1141  _cache.clear();
1142 }
1143 
1144 ////////////////////////////////////////////////////////////////////
1145 // Function: Geom::clear_cache_stage
1146 // Access: Published
1147 // Description: Removes all of the previously-cached results of
1148 // munge_geom(), at the current pipeline stage and
1149 // upstream. Does not affect the downstream cache.
1150 //
1151 // Don't call this in a downstream thread unless you
1152 // don't mind it blowing away other changes you might
1153 // have recently made in an upstream thread.
1154 ////////////////////////////////////////////////////////////////////
1155 void Geom::
1156 clear_cache_stage(Thread *current_thread) {
1157  LightMutexHolder holder(_cache_lock);
1158  for (Cache::iterator ci = _cache.begin();
1159  ci != _cache.end();
1160  ++ci) {
1161  CacheEntry *entry = (*ci).second;
1162  CDCacheWriter cdata(entry->_cycler, current_thread);
1163  cdata->set_result(NULL, NULL);
1164  }
1165 }
1166 
1167 ////////////////////////////////////////////////////////////////////
1168 // Function: Geom::prepare
1169 // Access: Published
1170 // Description: Indicates that the geom should be enqueued to be
1171 // prepared in the indicated prepared_objects at the
1172 // beginning of the next frame. This will ensure the
1173 // geom is already loaded into geom memory if it
1174 // is expected to be rendered soon.
1175 //
1176 // Use this function instead of prepare_now() to preload
1177 // geoms from a user interface standpoint.
1178 ////////////////////////////////////////////////////////////////////
1179 void Geom::
1180 prepare(PreparedGraphicsObjects *prepared_objects) {
1181  prepared_objects->enqueue_geom(this);
1182 }
1183 
1184 ////////////////////////////////////////////////////////////////////
1185 // Function: Geom::is_prepared
1186 // Access: Published
1187 // Description: Returns true if the geom has already been prepared
1188 // or enqueued for preparation on the indicated GSG,
1189 // false otherwise.
1190 ////////////////////////////////////////////////////////////////////
1191 bool Geom::
1192 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
1193  Contexts::const_iterator ci;
1194  ci = _contexts.find(prepared_objects);
1195  if (ci != _contexts.end()) {
1196  return true;
1197  }
1198  return prepared_objects->is_geom_queued(this);
1199 }
1200 
1201 ////////////////////////////////////////////////////////////////////
1202 // Function: Geom::release
1203 // Access: Published
1204 // Description: Frees the geom context only on the indicated object,
1205 // if it exists there. Returns true if it was released,
1206 // false if it had not been prepared.
1207 ////////////////////////////////////////////////////////////////////
1208 bool Geom::
1209 release(PreparedGraphicsObjects *prepared_objects) {
1210  Contexts::iterator ci;
1211  ci = _contexts.find(prepared_objects);
1212  if (ci != _contexts.end()) {
1213  GeomContext *gc = (*ci).second;
1214  prepared_objects->release_geom(gc);
1215  return true;
1216  }
1217 
1218  // Maybe it wasn't prepared yet, but it's about to be.
1219  return prepared_objects->dequeue_geom(this);
1220 }
1221 
1222 ////////////////////////////////////////////////////////////////////
1223 // Function: Geom::release_all
1224 // Access: Published
1225 // Description: Frees the context allocated on all objects for which
1226 // the geom has been declared. Returns the number of
1227 // contexts which have been freed.
1228 ////////////////////////////////////////////////////////////////////
1229 int Geom::
1231  // We have to traverse a copy of the _contexts list, because the
1232  // PreparedGraphicsObjects object will call clear_prepared() in response
1233  // to each release_geom(), and we don't want to be modifying the
1234  // _contexts list while we're traversing it.
1235  Contexts temp = _contexts;
1236  int num_freed = (int)_contexts.size();
1237 
1238  Contexts::const_iterator ci;
1239  for (ci = temp.begin(); ci != temp.end(); ++ci) {
1240  PreparedGraphicsObjects *prepared_objects = (*ci).first;
1241  GeomContext *gc = (*ci).second;
1242  prepared_objects->release_geom(gc);
1243  }
1244 
1245  // Now that we've called release_geom() on every known context,
1246  // the _contexts list should have completely emptied itself.
1247  nassertr(_contexts.empty(), num_freed);
1248 
1249  return num_freed;
1250 }
1251 
1252 ////////////////////////////////////////////////////////////////////
1253 // Function: Geom::prepare_now
1254 // Access: Public
1255 // Description: Creates a context for the geom on the particular
1256 // GSG, if it does not already exist. Returns the new
1257 // (or old) GeomContext. This assumes that the
1258 // GraphicsStateGuardian is the currently active
1259 // rendering context and that it is ready to accept new
1260 // geoms. If this is not necessarily the case, you
1261 // should use prepare() instead.
1262 //
1263 // Normally, this is not called directly except by the
1264 // GraphicsStateGuardian; a geom does not need to be
1265 // explicitly prepared by the user before it may be
1266 // rendered.
1267 ////////////////////////////////////////////////////////////////////
1271  Contexts::const_iterator ci;
1272  ci = _contexts.find(prepared_objects);
1273  if (ci != _contexts.end()) {
1274  return (*ci).second;
1275  }
1276 
1277  GeomContext *gc = prepared_objects->prepare_geom_now(this, gsg);
1278  if (gc != (GeomContext *)NULL) {
1279  _contexts[prepared_objects] = gc;
1280  }
1281  return gc;
1282 }
1283 
1284 ////////////////////////////////////////////////////////////////////
1285 // Function: Geom::draw
1286 // Access: Public
1287 // Description: Actually draws the Geom with the indicated GSG, using
1288 // the indicated vertex data (which might have been
1289 // pre-munged to support the GSG's needs).
1290 //
1291 // Returns true if all of the primitives were drawn
1292 // normally, false if there was a problem (for instance,
1293 // some of the data was nonresident). If force is
1294 // passed true, it will wait for the data to become
1295 // resident if necessary.
1296 ////////////////////////////////////////////////////////////////////
1297 bool Geom::
1299  const GeomVertexData *vertex_data, bool force,
1300  Thread *current_thread) const {
1301  GeomPipelineReader geom_reader(this, current_thread);
1302  geom_reader.check_usage_hint();
1303 
1304  GeomVertexDataPipelineReader data_reader(vertex_data, current_thread);
1305  data_reader.check_array_readers();
1306 
1307  return geom_reader.draw(gsg, munger, &data_reader, force);
1308 }
1309 
1310 ////////////////////////////////////////////////////////////////////
1311 // Function: Geom::get_next_modified
1312 // Access: Public, Static
1313 // Description: Returns a monotonically increasing sequence. Each
1314 // time this is called, a new sequence number is
1315 // returned, higher than the previous value.
1316 //
1317 // This is used to ensure that
1318 // GeomVertexArrayData::get_modified() and
1319 // GeomPrimitive::get_modified() update from the same
1320 // space, so that Geom::get_modified() returns a
1321 // meaningful value.
1322 ////////////////////////////////////////////////////////////////////
1325  ++_next_modified;
1326  return _next_modified;
1327 }
1328 
1329 ////////////////////////////////////////////////////////////////////
1330 // Function: Geom::compute_internal_bounds
1331 // Access: Private
1332 // Description: Recomputes the dynamic bounding volume for this Geom.
1333 // This includes all of the vertices.
1334 ////////////////////////////////////////////////////////////////////
1335 void Geom::
1336 compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
1337  int num_vertices = 0;
1338 
1339  // Get the vertex data, after animation.
1340  CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer();
1341  vertex_data = vertex_data->animate_vertices(true, current_thread);
1342 
1343  // Now actually compute the bounding volume. We do this by using
1344  // calc_tight_bounds to determine our box first.
1345  LPoint3 pmin, pmax;
1346  PN_stdfloat sq_center_dist;
1347  bool found_any = false;
1348  do_calc_tight_bounds(pmin, pmax, sq_center_dist, found_any,
1349  vertex_data, false, LMatrix4::ident_mat(),
1350  InternalName::get_vertex(),
1351  cdata, current_thread);
1352 
1353  BoundingVolume::BoundsType btype = cdata->_bounds_type;
1354  if (btype == BoundingVolume::BT_default) {
1355  btype = bounds_type;
1356  }
1357 
1358  if (found_any) {
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
1367  // of the sides. We will use this to determine whether a sphere
1368  // or box is a 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 &&
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
1387  // job 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 <= best_sq_radius) {
1395  // Great. This is as good a sphere as we're going to get.
1396  if (btype == BoundingVolume::BT_best &&
1397  avg_box_area < better_sq_radius * MathNumbers::pi) {
1398  // But the box is better, anyway. Use that instead.
1399  cdata->_internal_bounds = new BoundingBox(pmin, pmax);
1400  break;
1401  }
1402  cdata->_internal_bounds =
1403  new BoundingSphere(aabb_center, csqrt(better_sq_radius));
1404  break;
1405  }
1406  }
1407 
1408  if (btype != BoundingVolume::BT_sphere &&
1409  avg_box_area < sq_center_dist * MathNumbers::pi) {
1410  // A box is probably a tighter fit.
1411  cdata->_internal_bounds = new BoundingBox(pmin, pmax);
1412  break;
1413 
1414  } else if (sq_center_dist <= best_sq_radius) {
1415  // No, but a sphere centered on the origin is apparently
1416  // still better than a sphere around the bounding box.
1417  cdata->_internal_bounds =
1418  new BoundingSphere(LPoint3::origin(), csqrt(sq_center_dist));
1419  break;
1420 
1421  } else if (btype == BoundingVolume::BT_sphere) {
1422  // This is the worst sphere we can make, which is why we will only
1423  // do it when the user specifically requests a sphere.
1424  cdata->_internal_bounds =
1425  new BoundingSphere(aabb_center, csqrt(best_sq_radius));
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();
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 // Function: Geom::do_calc_tight_bounds
1458 // Access: Private
1459 // Description: 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();
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 // Function: Geom::do_calc_sphere_radius
1481 // Access: Private
1482 // Description:
1483 ////////////////////////////////////////////////////////////////////
1484 void Geom::
1485 do_calc_sphere_radius(const LPoint3 &center, PN_stdfloat &sq_radius,
1486  bool &found_any, const GeomVertexData *vertex_data,
1487  const CData *cdata, Thread *current_thread) const {
1488  Primitives::const_iterator pi;
1489  for (pi = cdata->_primitives.begin();
1490  pi != cdata->_primitives.end();
1491  ++pi) {
1492  CPT(GeomPrimitive) prim = (*pi).get_read_pointer();
1493  prim->calc_sphere_radius(center, sq_radius, found_any,
1494  vertex_data, current_thread);
1495  }
1496 }
1497 
1498 ////////////////////////////////////////////////////////////////////
1499 // Function: Geom::clear_prepared
1500 // Access: Private
1501 // Description: Removes the indicated PreparedGraphicsObjects table
1502 // from the Geom's table, without actually releasing
1503 // the geom. This is intended to be called only from
1504 // PreparedGraphicsObjects::release_geom(); it should
1505 // never be called by user code.
1506 ////////////////////////////////////////////////////////////////////
1507 void Geom::
1508 clear_prepared(PreparedGraphicsObjects *prepared_objects) {
1509  Contexts::iterator ci;
1510  ci = _contexts.find(prepared_objects);
1511  if (ci != _contexts.end()) {
1512  _contexts.erase(ci);
1513  } else {
1514  // If this assertion fails, clear_prepared() was given a
1515  // prepared_objects that the geom didn't know about.
1516  nassertv(false);
1517  }
1518 }
1519 
1520 ////////////////////////////////////////////////////////////////////
1521 // Function: Geom::check_will_be_valid
1522 // Access: Private
1523 // Description: Verifies that the all of the primitives within the
1524 // geom reference vertices that actually exist within
1525 // the indicated GeomVertexData (presumably in
1526 // preparation for assigning the geom to use this data).
1527 // Returns true if the data appears to be valid, false
1528 // otherwise.
1529 ////////////////////////////////////////////////////////////////////
1530 bool Geom::
1531 check_will_be_valid(const GeomVertexData *vertex_data) const {
1532  CDReader cdata(_cycler);
1533 
1534  Primitives::const_iterator pi;
1535  for (pi = cdata->_primitives.begin();
1536  pi != cdata->_primitives.end();
1537  ++pi) {
1538  if (!(*pi).get_read_pointer()->check_valid(vertex_data)) {
1539  return false;
1540  }
1541  }
1542 
1543  return true;
1544 }
1545 
1546 ////////////////////////////////////////////////////////////////////
1547 // Function: Geom::reset_usage_hint
1548 // Access: Private
1549 // Description: Recomputes the minimum usage_hint.
1550 ////////////////////////////////////////////////////////////////////
1551 void Geom::
1552 reset_usage_hint(Geom::CData *cdata) {
1553  cdata->_usage_hint = UH_unspecified;
1554  Primitives::const_iterator pi;
1555  for (pi = cdata->_primitives.begin();
1556  pi != cdata->_primitives.end();
1557  ++pi) {
1558  cdata->_usage_hint = min(cdata->_usage_hint,
1559  (*pi).get_read_pointer()->get_usage_hint());
1560  }
1561  cdata->_got_usage_hint = true;
1562 }
1563 
1564 ////////////////////////////////////////////////////////////////////
1565 // Function: Geom::reset_geom_rendering
1566 // Access: Private
1567 // Description: Rederives the _geom_rendering member.
1568 ////////////////////////////////////////////////////////////////////
1569 void Geom::
1570 reset_geom_rendering(Geom::CData *cdata) {
1571  cdata->_geom_rendering = 0;
1572  Primitives::const_iterator pi;
1573  for (pi = cdata->_primitives.begin();
1574  pi != cdata->_primitives.end();
1575  ++pi) {
1576  cdata->_geom_rendering |= (*pi).get_read_pointer()->get_geom_rendering();
1577  }
1578 
1579  if ((cdata->_geom_rendering & GR_point) != 0) {
1580  CPT(GeomVertexData) data = cdata->_data.get_read_pointer();
1581  if (data->has_column(InternalName::get_size())) {
1582  cdata->_geom_rendering |= GR_per_point_size;
1583  }
1584  if (data->has_column(InternalName::get_aspect_ratio())) {
1585  cdata->_geom_rendering |= GR_point_aspect_ratio;
1586  }
1587  if (data->has_column(InternalName::get_rotate())) {
1588  cdata->_geom_rendering |= GR_point_rotate;
1589  }
1590  }
1591 
1592  switch (get_shade_model()) {
1593  case SM_flat_first_vertex:
1594  cdata->_geom_rendering |= GR_flat_first_vertex;
1595  break;
1596 
1597  case SM_flat_last_vertex:
1598  cdata->_geom_rendering |= GR_flat_last_vertex;
1599  break;
1600 
1601  default:
1602  break;
1603  }
1604 }
1605 
1606 ////////////////////////////////////////////////////////////////////
1607 // Function: Geom::combine_primitives
1608 // Access: Private
1609 // Description: Combines two primitives of the same type into a
1610 // single primitive. a_prim is modified to append the
1611 // vertices from b_prim, which is unmodified.
1612 ////////////////////////////////////////////////////////////////////
1613 void Geom::
1614 combine_primitives(GeomPrimitive *a_prim, const GeomPrimitive *b_prim,
1615  Thread *current_thread) {
1616  nassertv(a_prim != b_prim);
1617  nassertv(a_prim->get_type() == b_prim->get_type());
1618 
1619  CPT(GeomPrimitive) b_prim2 = b_prim;
1620 
1621  if (a_prim->get_index_type() != b_prim2->get_index_type()) {
1622  GeomPrimitive::NumericType index_type = max(a_prim->get_index_type(), b_prim2->get_index_type());
1623  a_prim->set_index_type(index_type);
1624  if (b_prim2->get_index_type() != index_type) {
1625  PT(GeomPrimitive) b_prim_copy = b_prim2->make_copy();
1626  b_prim_copy->set_index_type(index_type);
1627  b_prim2 = b_prim_copy;
1628  }
1629  }
1630 
1631  if (!b_prim2->is_indexed()) {
1632  PT(GeomPrimitive) b_prim_copy = b_prim2->make_copy();
1633  b_prim_copy->make_indexed();
1634  b_prim2 = b_prim_copy;
1635  }
1636 
1637  PT(GeomVertexArrayData) a_vertices = a_prim->modify_vertices();
1638  CPT(GeomVertexArrayData) b_vertices = b_prim2->get_vertices();
1639 
1640  if (a_prim->requires_unused_vertices()) {
1641  GeomVertexReader index(b_vertices, 0);
1642  int b_vertex = index.get_data1i();
1643  a_prim->append_unused_vertices(a_vertices, b_vertex);
1644  }
1645 
1646  PT(GeomVertexArrayDataHandle) a_handle = a_vertices->modify_handle(current_thread);
1647  CPT(GeomVertexArrayDataHandle) b_handle = b_vertices->get_handle(current_thread);
1648 
1649  size_t orig_a_vertices = a_handle->get_num_rows();
1650 
1651  a_handle->copy_subdata_from(a_handle->get_data_size_bytes(), 0,
1652  b_handle, 0, b_handle->get_data_size_bytes());
1653  a_prim->clear_minmax();
1654  if (a_prim->is_composite()) {
1655  // Also copy the ends array.
1656  PTA_int a_ends = a_prim->modify_ends();
1657  CPTA_int b_ends = b_prim2->get_ends();
1658  for (size_t i = 0; i < b_ends.size(); ++i) {
1659  a_ends.push_back(b_ends[i] + orig_a_vertices);
1660  }
1661  }
1662 }
1663 
1664 ////////////////////////////////////////////////////////////////////
1665 // Function: Geom::register_with_read_factory
1666 // Access: Public, Static
1667 // Description: Tells the BamReader how to create objects of type
1668 // Geom.
1669 ////////////////////////////////////////////////////////////////////
1670 void Geom::
1672  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
1673 }
1674 
1675 ////////////////////////////////////////////////////////////////////
1676 // Function: Geom::write_datagram
1677 // Access: Public, Virtual
1678 // Description: Writes the contents of this object to the datagram
1679 // for shipping out to a Bam file.
1680 ////////////////////////////////////////////////////////////////////
1681 void Geom::
1683  TypedWritable::write_datagram(manager, dg);
1684 
1685  manager->write_cdata(dg, _cycler);
1686 }
1687 
1688 ////////////////////////////////////////////////////////////////////
1689 // Function: Geom::make_from_bam
1690 // Access: Protected, Static
1691 // Description: This function is called by the BamReader's factory
1692 // when a new object of type Geom is encountered
1693 // in the Bam file. It should create the Geom
1694 // and extract its information from the file.
1695 ////////////////////////////////////////////////////////////////////
1696 TypedWritable *Geom::
1697 make_from_bam(const FactoryParams &params) {
1698  Geom *object = new Geom(NULL);
1699  DatagramIterator scan;
1700  BamReader *manager;
1701 
1702  parse_params(params, scan, manager);
1703  object->fillin(scan, manager);
1704  manager->register_finalize(object);
1705 
1706  return object;
1707 }
1708 
1709 ////////////////////////////////////////////////////////////////////
1710 // Function: Geom::finalize
1711 // Access: Public, Virtual
1712 // Description: Called by the BamReader to perform any final actions
1713 // needed for setting up the object after all objects
1714 // have been read and all pointers have been completed.
1715 ////////////////////////////////////////////////////////////////////
1716 void Geom::
1717 finalize(BamReader *manager) {
1718  CDWriter cdata(_cycler, true);
1719 
1720  // Make sure our GeomVertexData is finalized first. This may result
1721  // in the data getting finalized multiple times, but it doesn't mind
1722  // that.
1723  if (!cdata->_data.is_null()) {
1724  // We shouldn't call get_write_pointer(), which might replicate
1725  // the GeomVertexData unnecessarily.
1726  cdata->_data.get_unsafe_pointer()->finalize(manager);
1727  }
1728 
1729  reset_geom_rendering(cdata);
1730 }
1731 
1732 ////////////////////////////////////////////////////////////////////
1733 // Function: Geom::fillin
1734 // Access: Protected
1735 // Description: This internal function is called by make_from_bam to
1736 // read in all of the relevant data from the BamFile for
1737 // the new Geom.
1738 ////////////////////////////////////////////////////////////////////
1739 void Geom::
1740 fillin(DatagramIterator &scan, BamReader *manager) {
1741  TypedWritable::fillin(scan, manager);
1742 
1743  manager->read_cdata(scan, _cycler);
1744 }
1745 
1746 ////////////////////////////////////////////////////////////////////
1747 // Function: Geom::CDataCache::Destructor
1748 // Access: Public, Virtual
1749 // Description:
1750 ////////////////////////////////////////////////////////////////////
1751 Geom::CDataCache::
1752 ~CDataCache() {
1753  set_result(NULL, NULL);
1754 }
1755 
1756 ////////////////////////////////////////////////////////////////////
1757 // Function: Geom::CDataCache::make_copy
1758 // Access: Public, Virtual
1759 // Description:
1760 ////////////////////////////////////////////////////////////////////
1761 CycleData *Geom::CDataCache::
1762 make_copy() const {
1763  return new CDataCache(*this);
1764 }
1765 
1766 ////////////////////////////////////////////////////////////////////
1767 // Function: Geom::CacheEntry::evict_callback
1768 // Access: Public, Virtual
1769 // Description: Called when the entry is evicted from the cache, this
1770 // should clean up the owning object appropriately.
1771 ////////////////////////////////////////////////////////////////////
1772 void Geom::CacheEntry::
1774  LightMutexHolder holder(_source->_cache_lock);
1775  Cache::iterator ci = _source->_cache.find(&_key);
1776  nassertv(ci != _source->_cache.end());
1777  nassertv((*ci).second == this);
1778  _source->_cache.erase(ci);
1779 }
1780 
1781 ////////////////////////////////////////////////////////////////////
1782 // Function: Geom::CacheEntry::output
1783 // Access: Public, Virtual
1784 // Description:
1785 ////////////////////////////////////////////////////////////////////
1786 void Geom::CacheEntry::
1787 output(ostream &out) const {
1788  out << "geom " << (void *)_source << ", "
1789  << (const void *)_key._modifier;
1790 }
1791 
1792 
1793 ////////////////////////////////////////////////////////////////////
1794 // Function: Geom::CData::make_copy
1795 // Access: Public, Virtual
1796 // Description:
1797 ////////////////////////////////////////////////////////////////////
1798 CycleData *Geom::CData::
1799 make_copy() const {
1800  return new CData(*this);
1801 }
1802 
1803 ////////////////////////////////////////////////////////////////////
1804 // Function: Geom::CData::write_datagram
1805 // Access: Public, Virtual
1806 // Description: Writes the contents of this object to the datagram
1807 // for shipping out to a Bam file.
1808 ////////////////////////////////////////////////////////////////////
1809 void Geom::CData::
1810 write_datagram(BamWriter *manager, Datagram &dg) const {
1811  manager->write_pointer(dg, _data.get_read_pointer());
1812 
1813  dg.add_uint16(_primitives.size());
1814  Primitives::const_iterator pi;
1815  for (pi = _primitives.begin(); pi != _primitives.end(); ++pi) {
1816  manager->write_pointer(dg, (*pi).get_read_pointer());
1817  }
1818 
1819  dg.add_uint8(_primitive_type);
1820  dg.add_uint8(_shade_model);
1821 
1822  // Actually, we shouldn't bother writing out _geom_rendering; we'll
1823  // just throw it away anyway.
1824  dg.add_uint16(_geom_rendering);
1825 
1826  dg.add_uint8(_bounds_type);
1827 }
1828 
1829 ////////////////////////////////////////////////////////////////////
1830 // Function: Geom::CData::complete_pointers
1831 // Access: Public, Virtual
1832 // Description: Receives an array of pointers, one for each time
1833 // manager->read_pointer() was called in fillin().
1834 // Returns the number of pointers processed.
1835 ////////////////////////////////////////////////////////////////////
1836 int Geom::CData::
1837 complete_pointers(TypedWritable **p_list, BamReader *manager) {
1838  int pi = CycleData::complete_pointers(p_list, manager);
1839 
1840  _data = DCAST(GeomVertexData, p_list[pi++]);
1841 
1842  Primitives::iterator pri;
1843  for (pri = _primitives.begin(); pri != _primitives.end(); ++pri) {
1844  (*pri) = DCAST(GeomPrimitive, p_list[pi++]);
1845  }
1846 
1847  return pi;
1848 }
1849 
1850 ////////////////////////////////////////////////////////////////////
1851 // Function: Geom::CData::fillin
1852 // Access: Public, Virtual
1853 // Description: This internal function is called by make_from_bam to
1854 // read in all of the relevant data from the BamFile for
1855 // the new Geom.
1856 ////////////////////////////////////////////////////////////////////
1857 void Geom::CData::
1858 fillin(DatagramIterator &scan, BamReader *manager) {
1859  manager->read_pointer(scan);
1860 
1861  int num_primitives = scan.get_uint16();
1862  _primitives.reserve(num_primitives);
1863  for (int i = 0; i < num_primitives; ++i) {
1864  manager->read_pointer(scan);
1865  _primitives.push_back(NULL);
1866  }
1867 
1868  _primitive_type = (PrimitiveType)scan.get_uint8();
1869  _shade_model = (ShadeModel)scan.get_uint8();
1870 
1871  // To be removed: we no longer read _geom_rendering from the bam
1872  // file; instead, we rederive it in finalize().
1873  scan.get_uint16();
1874 
1875  _got_usage_hint = false;
1876  _modified = Geom::get_next_modified();
1877 
1878  _bounds_type = BoundingVolume::BT_default;
1879  if (manager->get_file_minor_ver() >= 19) {
1880  _bounds_type = (BoundingVolume::BoundsType)scan.get_uint8();
1881  }
1882 }
1883 
1884 ////////////////////////////////////////////////////////////////////
1885 // Function: GeomPipelineReader::check_usage_hint
1886 // Access: Public
1887 // Description: Ensures that the Geom's usage_hint cache has been
1888 // computed.
1889 ////////////////////////////////////////////////////////////////////
1892  if (!_cdata->_got_usage_hint) {
1893  // We'll need to get a fresh pointer, since another thread might
1894  // already have modified the pointer on the object since we
1895  // queried it.
1896  {
1897 #ifdef DO_PIPELINING
1898  unref_delete((CycleData *)_cdata);
1899 #endif
1900  Geom::CDWriter fresh_cdata(((Geom *)_object.p())->_cycler,
1901  false, _current_thread);
1902  ((GeomPipelineReader *)this)->_cdata = fresh_cdata;
1903 #ifdef DO_PIPELINING
1904  _cdata->ref();
1905 #endif
1906  if (!fresh_cdata->_got_usage_hint) {
1907  // The cache is still stale. We have to do the work of
1908  // freshening it.
1909  ((Geom *)_object.p())->reset_usage_hint(fresh_cdata);
1910  nassertv(fresh_cdata->_got_usage_hint);
1911  }
1912 
1913  // When fresh_cdata goes out of scope, its write lock is
1914  // released, and _cdata reverts to our usual convention of an
1915  // unlocked copy of the data.
1916  }
1917  }
1918 
1919  nassertv(_cdata->_got_usage_hint);
1920 }
1921 
1922 ////////////////////////////////////////////////////////////////////
1923 // Function: GeomPipelineReader::check_valid
1924 // Access: Public
1925 // Description:
1926 ////////////////////////////////////////////////////////////////////
1927 bool GeomPipelineReader::
1928 check_valid(const GeomVertexDataPipelineReader *data_reader) const {
1929  Geom::Primitives::const_iterator pi;
1930  for (pi = _cdata->_primitives.begin();
1931  pi != _cdata->_primitives.end();
1932  ++pi) {
1933  CPT(GeomPrimitive) primitive = (*pi).get_read_pointer();
1934  GeomPrimitivePipelineReader reader(primitive, _current_thread);
1935  reader.check_minmax();
1936  if (!reader.check_valid(data_reader)) {
1937  return false;
1938  }
1939  }
1940 
1941  return true;
1942 }
1943 
1944 ////////////////////////////////////////////////////////////////////
1945 // Function: GeomPipelineReader::draw
1946 // Access: Public
1947 // Description: The implementation of Geom::draw().
1948 ////////////////////////////////////////////////////////////////////
1951  const GeomVertexDataPipelineReader *data_reader, bool force) const {
1952  PStatTimer timer(Geom::_draw_primitive_setup_pcollector);
1953  bool all_ok = gsg->begin_draw_primitives(this, munger, data_reader, force);
1954  if (all_ok) {
1955  Geom::Primitives::const_iterator pi;
1956  for (pi = _cdata->_primitives.begin();
1957  pi != _cdata->_primitives.end();
1958  ++pi) {
1959  CPT(GeomPrimitive) primitive = (*pi).get_read_pointer();
1960  GeomPrimitivePipelineReader reader(primitive, _current_thread);
1961  if (reader.get_num_vertices() != 0) {
1962  reader.check_minmax();
1963  nassertr(reader.check_valid(data_reader), false);
1964  if (!primitive->draw(gsg, &reader, force)) {
1965  all_ok = false;
1966  }
1967  }
1968  }
1969  gsg->end_draw_primitives();
1970  }
1971 
1972  return all_ok;
1973 }
float length_squared() const
Returns the square of the vector&#39;s length, cheap and easy.
Definition: lvecBase3.h:749
static const LMatrix4f & ident_mat()
Returns an identity matrix.
Definition: lmatrix.h:903
An axis-aligned bounding box; that is, a minimum and maximum coordinate triple.
Definition: boundingBox.h:31
void add_uint8(PN_uint8 value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:138
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:93
This is a special class object that holds all the information returned by a particular GSG to indicat...
Definition: geomContext.h:39
This is our own Panda specialization on the default STL map.
Definition: pmap.h:52
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:1682
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.
void transform_vertices(const LMatrix4 &mat)
Applies the indicated transform to all of the vertices in the Geom.
Definition: geom.cxx:980
int get_primitive_num_vertices(int n) const
Returns the number of vertices used by the nth primitive.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
Definition: bamReader.cxx:753
void check_usage_hint() const
Ensures that the Geom&#39;s usage_hint cache has been computed.
Definition: geom.cxx:1891
This defines a bounding sphere, consisting of a center and a radius.
Objects of this class are used to convert vertex data from a Geom into a format suitable for passing ...
Definition: geomMunger.h:57
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:438
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:50
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:37
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:63
void reverse_in_place()
Reverses all of the primitives within this Geom, leaving the results in place.
Definition: geom.cxx:537
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
Definition: bamWriter.cxx:398
int get_num_vertices() const
Returns the number of indices used by all the primitives in this object.
void remove_primitive(int i)
Removes the ith primitive from the list.
Definition: geom.cxx:409
PrimitiveType get_primitive_type() const
Returns the fundamental primitive type that is common to all GeomPrimitives added within the Geom...
Definition: geom.I:28
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:100
void add_primitive(const GeomPrimitive *primitive)
Adds a new GeomPrimitive structure to the Geom object.
Definition: geom.cxx:366
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:34
void make_lines_in_place()
Replaces the GeomPrimitives within this Geom with corresponding GeomLines, representing a wireframe o...
Definition: geom.cxx:765
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:99
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:73
int get_num_bytes() const
Returns the number of bytes consumed by the geom and its primitives (but not including its vertex tab...
Definition: geom.cxx:923
void set_primitive(int i, const GeomPrimitive *primitive)
Replaces the ith GeomPrimitive object stored within the Geom with the new object. ...
Definition: geom.cxx:320
PN_uint8 get_uint8()
Extracts an unsigned 8-bit integer.
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:401
static const LPoint3f & origin(CoordinateSystem cs=CS_default)
Returns the origin of the indicated coordinate system.
Definition: lpoint3.h:451
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:575
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:105
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...
PN_uint16 get_uint16()
Extracts an unsigned 16-bit integer.
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:209
static Thread * get_current_thread()
Returns a pointer to the currently-executing Thread object.
Definition: thread.I:145
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:1773
This is an abstract class for any volume in any sense which can be said to define the locality of ref...
A lightweight class that represents a single element that may be timed and/or counted via stats...
bool draw(GraphicsStateGuardianBase *gsg, const GeomMunger *munger, const GeomVertexDataPipelineReader *data_reader, bool force) const
The implementation of Geom::draw().
Definition: geom.cxx:1950
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:634
bool is_geom_queued(const Geom *geom) const
Returns true if the geom has been queued on this GSG, false otherwise.
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:1156
int get_primitive_start(int n) const
Returns the element within the _vertices list at which the nth primitive starts.
virtual Geom * make_copy() const
Returns a newly-allocated Geom that is a shallow copy of this one.
Definition: geom.cxx:118
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
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:1717
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...
This template class calls PipelineCycler::read() in the constructor and PipelineCycler::release_read(...
A container for geometry primitives.
Definition: geom.h:58
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
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:1269
void set_shade_model(ShadeModel shade_model)
Changes the ShadeModel hint for this primitive.
Definition: geomPrimitive.I:45
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:55
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:886
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
void doubleside_in_place()
Doublesides all of the primitives within this Geom, leaving the results in place. ...
Definition: geom.cxx:499
int get_data1i()
Returns the data associated with the read row, expressed as a 1-component value, and advances the rea...
bool check_valid(const GeomVertexData *vertex_data) const
Verifies that the primitive only references vertices that actually exist within the indicated GeomVer...
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:90
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:181
bool check_valid() const
Verifies that the all of the primitives within the geom reference vertices that actually exist within...
Definition: geom.cxx:1012
This base class provides basic reference counting, but also can be used with a CopyOnWritePointer to ...
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:841
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
void set_vertex_data(const GeomVertexData *data)
Replaces the Geom&#39;s underlying vertex data table with a completely new table.
Definition: geom.cxx:183
bool draw(GraphicsStateGuardianBase *gsg, const GeomMunger *munger, 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:1298
ShadeModel get_shade_model() const
Returns the shade model common to all of the individual GeomPrimitives that have been added to the ge...
Definition: geom.I:41
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the geom context only on the indicated object, if it exists there.
Definition: geom.cxx:1209
int get_vertex(int i) const
Returns the ith vertex index in the table.
A thread; that is, a lightweight process.
Definition: thread.h:51
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:1180
int release_all()
Frees the context allocated on all objects for which the geom has been declared.
Definition: geom.cxx:1230
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:882
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:461
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 make_points_in_place()
Replaces the GeomPrimitives within this Geom with corresponding GeomPoints.
Definition: geom.cxx:803
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:52
int make_nonindexed(bool composite_only)
Converts the geom from indexed to nonindexed by duplicating vertices as necessary.
Definition: geom.cxx:252
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:84
static void register_with_read_factory()
Tells the BamReader how to create objects of type Geom.
Definition: geom.cxx:1671
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:1192
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
This is a sequence number that increments monotonically.
Definition: updateSeq.h:43
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:134
Encapsulates the data from a GeomPrimitive, pre-fetched for one stage of the pipeline.
void check_minmax() const
Ensures that the primitive&#39;s minmax cache has been computed.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
int get_primitive_end(int n) const
Returns the element within the _vertices list at which the nth primitive ends.
bool request_resident() const
Returns true if all the primitive arrays are currently resident in memory.
Definition: geom.cxx:949
NumericType get_index_type() const
Returns the numeric type of the index column.
Definition: geomPrimitive.I:79
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:279
void read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:658