Panda3D
geomPrimitive.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 geomPrimitive.cxx
10  * @author drose
11  * @date 2005-03-06
12  */
13 
14 #include "geomPrimitive.h"
15 #include "geom.h"
16 #include "geomPatches.h"
17 #include "geomVertexData.h"
18 #include "geomVertexArrayFormat.h"
19 #include "geomVertexColumn.h"
20 #include "geomVertexReader.h"
21 #include "geomVertexWriter.h"
22 #include "geomVertexRewriter.h"
23 #include "geomPoints.h"
24 #include "geomLines.h"
25 #include "geomTriangles.h"
27 #include "internalName.h"
28 #include "bamReader.h"
29 #include "bamWriter.h"
30 #include "ioPtaDatagramInt.h"
31 #include "indent.h"
32 #include "pStatTimer.h"
33 
34 using std::max;
35 using std::min;
36 
37 TypeHandle GeomPrimitive::_type_handle;
38 TypeHandle GeomPrimitive::CData::_type_handle;
39 TypeHandle GeomPrimitivePipelineReader::_type_handle;
40 
41 PStatCollector GeomPrimitive::_decompose_pcollector("*:Munge:Decompose");
42 PStatCollector GeomPrimitive::_doubleside_pcollector("*:Munge:Doubleside");
43 PStatCollector GeomPrimitive::_reverse_pcollector("*:Munge:Reverse");
44 PStatCollector GeomPrimitive::_rotate_pcollector("*:Munge:Rotate");
45 
46 /**
47  * Constructs an invalid object. Only used when reading from bam.
48  */
49 GeomPrimitive::
50 GeomPrimitive() {
51 }
52 
53 /**
54  * Required to implement CopyOnWriteObject.
55  */
56 PT(CopyOnWriteObject) GeomPrimitive::
57 make_cow_copy() {
58  return make_copy();
59 }
60 
61 /**
62  *
63  */
64 GeomPrimitive::
65 GeomPrimitive(GeomPrimitive::UsageHint usage_hint) {
66  CDWriter cdata(_cycler, true);
67  cdata->_usage_hint = usage_hint;
68 }
69 
70 /**
71  *
72  */
73 GeomPrimitive::
74 GeomPrimitive(const GeomPrimitive &copy) :
75  CopyOnWriteObject(copy),
76  _cycler(copy._cycler)
77 {
78 }
79 
80 /**
81  * The copy assignment operator is not pipeline-safe. This will completely
82  * obliterate all stages of the pipeline, so don't do it for a GeomPrimitive
83  * that is actively being used for rendering.
84  */
86 operator = (const GeomPrimitive &copy) {
87  CopyOnWriteObject::operator = (copy);
88  _cycler = copy._cycler;
89 }
90 
91 /**
92  *
93  */
94 GeomPrimitive::
95 ~GeomPrimitive() {
96  release_all();
97 }
98 
99 /**
100  * Returns the set of GeomRendering bits that represent the rendering
101  * properties required to properly render this primitive.
102  */
103 int GeomPrimitive::
104 get_geom_rendering() const {
105  if (is_indexed()) {
106  return GR_indexed_other;
107  } else {
108  return 0;
109  }
110 }
111 
112 /**
113  * Changes the UsageHint hint for this primitive. See get_usage_hint().
114  *
115  * Don't call this in a downstream thread unless you don't mind it blowing
116  * away other changes you might have recently made in an upstream thread.
117  */
119 set_usage_hint(GeomPrimitive::UsageHint usage_hint) {
120  CDWriter cdata(_cycler, true);
121  cdata->_usage_hint = usage_hint;
122 
123  if (!cdata->_vertices.is_null()) {
124  cdata->_modified = Geom::get_next_modified();
125  cdata->_usage_hint = usage_hint;
126  }
127 }
128 
129 /**
130  * Changes the numeric type of the index column. Normally, this should be
131  * either NT_uint16 or NT_uint32.
132  *
133  * The index type must be large enough to include all of the index values in
134  * the primitive. It may be automatically elevated, if necessary, to a larger
135  * index type, by a subsequent call to add_index() that names an index value
136  * that does not fit in the index type you specify.
137  *
138  * Don't call this in a downstream thread unless you don't mind it blowing
139  * away other changes you might have recently made in an upstream thread.
140  */
142 set_index_type(GeomPrimitive::NumericType index_type) {
143  nassertv(get_max_vertex() <= get_highest_index_value(index_type));
144 
145  CDWriter cdata(_cycler, true);
146  if (cdata->_index_type != index_type) {
147  do_set_index_type(cdata, index_type);
148  }
149 }
150 
151 /**
152  * Adds the indicated vertex to the list of vertex indices used by the
153  * graphics primitive type. To define a primitive, you must call add_vertex()
154  * for each vertex of the new primitive, and then call close_primitive() after
155  * you have specified the last vertex of each primitive.
156  *
157  * Don't call this in a downstream thread unless you don't mind it blowing
158  * away other changes you might have recently made in an upstream thread.
159  */
161 add_vertex(int vertex) {
162  CDWriter cdata(_cycler, true);
163 
164  if (gobj_cat.is_spam()) {
165  gobj_cat.spam()
166  << this << ".add_vertex(" << vertex << ")\n";
167  }
168 
169  consider_elevate_index_type(cdata, vertex);
170 
171  if (requires_unused_vertices()) {
172  int num_primitives = get_num_primitives();
173  if (num_primitives > 0 &&
174  get_num_vertices() == get_primitive_end(num_primitives - 1)) {
175  // If we are beginning a new primitive, give the derived class a chance to
176  // insert some degenerate vertices.
177  if (cdata->_vertices.is_null()) {
178  do_make_indexed(cdata);
179  }
180  append_unused_vertices(cdata->_vertices.get_write_pointer(), vertex);
181  }
182  }
183 
184  if (cdata->_vertices.is_null()) {
185  // The nonindexed case. We can keep the primitive nonindexed only if the
186  // vertex number happens to be the next available vertex.
187  nassertv(cdata->_num_vertices != -1);
188  if (cdata->_num_vertices == 0) {
189  cdata->_first_vertex = vertex;
190  cdata->_num_vertices = 1;
191  cdata->_modified = Geom::get_next_modified();
192  cdata->_got_minmax = false;
193  return;
194 
195  } else if (vertex == cdata->_first_vertex + cdata->_num_vertices) {
196  ++cdata->_num_vertices;
197  cdata->_modified = Geom::get_next_modified();
198  cdata->_got_minmax = false;
199  return;
200  }
201 
202  // Otherwise, we need to suddenly become an indexed primitive.
203  do_make_indexed(cdata);
204  }
205 
206  {
207  GeomVertexArrayDataHandle handle(cdata->_vertices.get_write_pointer(),
209  int num_rows = handle.get_num_rows();
210  handle.set_num_rows(num_rows + 1);
211 
212  unsigned char *ptr = handle.get_write_pointer();
213  switch (cdata->_index_type) {
214  case GeomEnums::NT_uint8:
215  ((uint8_t *)ptr)[num_rows] = vertex;
216  break;
217  case GeomEnums::NT_uint16:
218  ((uint16_t *)ptr)[num_rows] = vertex;
219  break;
220  case GeomEnums::NT_uint32:
221  ((uint32_t *)ptr)[num_rows] = vertex;
222  break;
223  default:
224  nassert_raise("unsupported index type");
225  break;
226  }
227  }
228 
229  cdata->_modified = Geom::get_next_modified();
230  cdata->_got_minmax = false;
231 }
232 
233 /**
234  * Adds a consecutive sequence of vertices, beginning at start, to the
235  * primitive.
236  *
237  * Don't call this in a downstream thread unless you don't mind it blowing
238  * away other changes you might have recently made in an upstream thread.
239  */
241 add_consecutive_vertices(int start, int num_vertices) {
242  if (num_vertices == 0) {
243  return;
244  }
245  int end = (start + num_vertices) - 1;
246 
247  CDWriter cdata(_cycler, true);
248 
249  consider_elevate_index_type(cdata, end);
250 
251  int num_primitives = get_num_primitives();
252  if (num_primitives > 0 &&
253  get_num_vertices() == get_primitive_end(num_primitives - 1)) {
254  // If we are beginning a new primitive, give the derived class a chance to
255  // insert some degenerate vertices.
256  if (cdata->_vertices.is_null()) {
257  do_make_indexed(cdata);
258  }
259  append_unused_vertices(cdata->_vertices.get_write_pointer(), start);
260  }
261 
262  if (cdata->_vertices.is_null()) {
263  // The nonindexed case. We can keep the primitive nonindexed only if the
264  // vertex number happens to be the next available vertex.
265  nassertv(cdata->_num_vertices != -1);
266  if (cdata->_num_vertices == 0) {
267  cdata->_first_vertex = start;
268  cdata->_num_vertices = num_vertices;
269  cdata->_modified = Geom::get_next_modified();
270  cdata->_got_minmax = false;
271  return;
272 
273  } else if (start == cdata->_first_vertex + cdata->_num_vertices) {
274  cdata->_num_vertices += num_vertices;
275  cdata->_modified = Geom::get_next_modified();
276  cdata->_got_minmax = false;
277  return;
278  }
279 
280  // Otherwise, we need to suddenly become an indexed primitive.
281  do_make_indexed(cdata);
282  }
283 
284  PT(GeomVertexArrayData) array_obj = cdata->_vertices.get_write_pointer();
285  int old_num_rows = array_obj->get_num_rows();
286  array_obj->set_num_rows(old_num_rows + num_vertices);
287 
288  GeomVertexWriter index(array_obj, 0);
289  index.set_row_unsafe(old_num_rows);
290 
291  for (int v = start; v <= end; ++v) {
292  index.set_data1i(v);
293  }
294 
295  cdata->_modified = Geom::get_next_modified();
296  cdata->_got_minmax = false;
297 }
298 
299 /**
300  * Adds the next n vertices in sequence, beginning from the last vertex added
301  * to the primitive + 1.
302  *
303  * This is most useful when you are building up a primitive and a
304  * GeomVertexData at the same time, and you just want the primitive to
305  * reference the first n vertices from the data, then the next n, and so on.
306  */
308 add_next_vertices(int num_vertices) {
309  if (get_num_vertices() == 0) {
310  add_consecutive_vertices(0, num_vertices);
311  } else {
312  add_consecutive_vertices(get_vertex(get_num_vertices() - 1) + 1, num_vertices);
313  }
314 }
315 
316 /**
317  * This ensures that enough memory space for n vertices is allocated, so that
318  * you may increase the number of vertices to n without causing a new memory
319  * allocation. This is a performance optimization only; it is especially
320  * useful when you know ahead of time that you will be adding n vertices to
321  * the primitive.
322  *
323  * Note that the total you specify here should also include implicit vertices
324  * which may be added at each close_primitive() call, according to
325  * get_num_unused_vertices_per_primitive().
326  *
327  * Note also that making this call will implicitly make the primitive indexed
328  * if it is not already, which could result in a performance *penalty*. If
329  * you would prefer not to lose the nonindexed nature of your existing
330  * GeomPrimitives, check is_indexed() before making this call.
331  */
333 reserve_num_vertices(int num_vertices) {
334  if (gobj_cat.is_debug()) {
335  gobj_cat.debug()
336  << this << ".reserve_num_vertices(" << num_vertices << ")\n";
337  }
338 
339  CDWriter cdata(_cycler, true);
340  consider_elevate_index_type(cdata, num_vertices);
341  do_make_indexed(cdata);
342  PT(GeomVertexArrayData) array_obj = cdata->_vertices.get_write_pointer();
343  array_obj->reserve_num_rows(num_vertices);
344 }
345 
346 /**
347  * Indicates that the previous n calls to add_vertex(), since the last call to
348  * close_primitive(), have fully defined a new primitive. Returns true if
349  * successful, false otherwise.
350  *
351  * Don't call this in a downstream thread unless you don't mind it blowing
352  * away other changes you might have recently made in an upstream thread.
353  */
355 close_primitive() {
356  int num_vertices_per_primitive = get_num_vertices_per_primitive();
357 
358  CDWriter cdata(_cycler, true);
359  if (num_vertices_per_primitive == 0) {
360  // This is a complex primitive type like a triangle strip: each primitive
361  // uses a different number of vertices.
362 #ifndef NDEBUG
363  int num_added;
364  if (cdata->_ends.empty()) {
365  num_added = get_num_vertices();
366  } else {
367  num_added = get_num_vertices() - cdata->_ends.back();
369  }
370  nassertr(num_added >= get_min_num_vertices_per_primitive(), false);
371 #endif
372  if (cdata->_ends.get_ref_count() > 1) {
373  PTA_int new_ends;
374  new_ends.v() = cdata->_ends.v();
375  cdata->_ends = new_ends;
376  }
377  cdata->_ends.push_back(get_num_vertices());
378 
379  } else {
380 #ifndef NDEBUG
381  // This is a simple primitive type like a triangle: each primitive uses
382  // the same number of vertices. Assert that we added the correct number
383  // of vertices.
384  int num_vertices_per_primitive = get_num_vertices_per_primitive();
385  int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive();
386 
387  int num_vertices = get_num_vertices();
388  nassertr((num_vertices + num_unused_vertices_per_primitive) % (num_vertices_per_primitive + num_unused_vertices_per_primitive) == 0, false)
389 #endif
390  }
391 
392  cdata->_modified = Geom::get_next_modified();
393 
394  return true;
395 }
396 
397 /**
398  * Removes all of the vertices and primitives from the object, so they can be
399  * re-added.
400  *
401  * Don't call this in a downstream thread unless you don't mind it blowing
402  * away other changes you might have recently made in an upstream thread.
403  */
405 clear_vertices() {
406  CDWriter cdata(_cycler, true);
407  cdata->_first_vertex = 0;
408  cdata->_num_vertices = 0;
409 
410  // Since we might have automatically elevated the index type by adding
411  // vertices, we should automatically lower it again when we call
412  // clear_vertices().
413  cdata->_index_type = NT_uint16;
414 
415  cdata->_vertices.clear();
416  cdata->_ends.clear();
417  cdata->_mins.clear();
418  cdata->_maxs.clear();
419  cdata->_modified = Geom::get_next_modified();
420  cdata->_got_minmax = false;
421 }
422 
423 /**
424  * Adds the indicated offset to all vertices used by the primitive.
425  *
426  * Don't call this in a downstream thread unless you don't mind it blowing
427  * away other changes you might have recently made in an upstream thread.
428  */
430 offset_vertices(int offset) {
431  if (offset == 0) {
432  return;
433  }
434 
435  if (is_indexed()) {
436  CDWriter cdata(_cycler, true);
437 
438  if (!cdata->_got_minmax) {
439  recompute_minmax(cdata);
440  nassertv(cdata->_got_minmax);
441  }
442 
443  consider_elevate_index_type(cdata, cdata->_max_vertex + offset);
444 
445  int strip_cut_index = get_strip_cut_index(cdata->_index_type);
446 
447  GeomVertexRewriter index(do_modify_vertices(cdata), 0);
448  while (!index.is_at_end()) {
449  int vertex = index.get_data1i();
450 
451  if (vertex != strip_cut_index) {
452  index.set_data1i(vertex + offset);
453  }
454  }
455 
456  } else {
457  CDWriter cdata(_cycler, true);
458 
459  cdata->_first_vertex += offset;
460  cdata->_modified = Geom::get_next_modified();
461  cdata->_got_minmax = false;
462 
463  consider_elevate_index_type(cdata,
464  cdata->_first_vertex + cdata->_num_vertices - 1);
465  }
466 }
467 
468 /**
469  * Adds the indicated offset to the indicated segment of vertices used by the
470  * primitive. Unlike the other version of offset_vertices, this makes the
471  * geometry indexed if it isn't already.
472  *
473  * Note that end_row indicates one past the last row that should be offset.
474  * In other words, the number of vertices touched is (end_row - begin_row).
475  *
476  * Don't call this in a downstream thread unless you don't mind it blowing
477  * away other changes you might have recently made in an upstream thread.
478  */
480 offset_vertices(int offset, int begin_row, int end_row) {
481  if (offset == 0 || end_row <= begin_row) {
482  return;
483  }
484 
485  nassertv(begin_row >= 0 && end_row >= 0);
486  nassertv(end_row <= get_num_vertices());
487 
488  if (!is_indexed() && (begin_row > 0 || end_row < get_num_vertices())) {
489  // Make it indexed unless the whole array was specified.
490  make_indexed();
491  }
492 
493  if (is_indexed()) {
494  CDWriter cdata(_cycler, true);
495 
496  int strip_cut_index = get_strip_cut_index(cdata->_index_type);
497 
498  // Calculate the maximum vertex over our range.
499  int max_vertex = 0;
500  {
501  GeomVertexReader index_r(cdata->_vertices.get_read_pointer(), 0);
502  index_r.set_row_unsafe(begin_row);
503  for (int j = begin_row; j < end_row; ++j) {
504  int vertex = index_r.get_data1i();
505  if (vertex != strip_cut_index) {
506  max_vertex = max(max_vertex, vertex);
507  }
508  }
509  }
510 
511  consider_elevate_index_type(cdata, max_vertex + offset);
512 
513  GeomVertexRewriter index(do_modify_vertices(cdata), 0);
514  index.set_row_unsafe(begin_row);
515  for (int j = begin_row; j < end_row; ++j) {
516  int vertex = index.get_data1i();
517  if (vertex != strip_cut_index) {
518  index.set_data1i(vertex + offset);
519  }
520  }
521 
522  } else {
523  // The supplied values cover all vertices, so we don't need to make it
524  // indexed.
525  CDWriter cdata(_cycler, true);
526 
527  cdata->_first_vertex += offset;
528  cdata->_modified = Geom::get_next_modified();
529  cdata->_got_minmax = false;
530 
531  consider_elevate_index_type(cdata,
532  cdata->_first_vertex + cdata->_num_vertices - 1);
533  }
534 }
535 
536 /**
537  * Converts the primitive from indexed to nonindexed by duplicating vertices
538  * as necessary into the indicated dest GeomVertexData. Note: does not
539  * support primitives with strip cut indices.
540  */
542 make_nonindexed(GeomVertexData *dest, const GeomVertexData *source) {
543  Thread *current_thread = Thread::get_current_thread();
544 
545  int num_vertices, dest_start;
546  {
547  GeomPrimitivePipelineReader reader(this, current_thread);
548  num_vertices = reader.get_num_vertices();
549  int strip_cut_index = reader.get_strip_cut_index();
550 
551  GeomVertexDataPipelineWriter data_writer(dest, false, current_thread);
552  data_writer.check_array_writers();
553  dest_start = data_writer.get_num_rows();
554  data_writer.set_num_rows(dest_start + num_vertices);
555 
556  GeomVertexDataPipelineReader data_reader(source, current_thread);
557  data_reader.check_array_readers();
558 
559  for (int i = 0; i < num_vertices; ++i) {
560  int v = reader.get_vertex(i);
561  nassertd(v != strip_cut_index) continue;
562  data_writer.copy_row_from(dest_start + i, data_reader, v);
563  }
564  }
565 
566  set_nonindexed_vertices(dest_start, num_vertices);
567 }
568 
569 /**
570  * Packs the vertices used by the primitive from the indicated source array
571  * onto the end of the indicated destination array.
572  */
574 pack_vertices(GeomVertexData *dest, const GeomVertexData *source) {
575  Thread *current_thread = Thread::get_current_thread();
576  if (!is_indexed()) {
577  // If the primitive is nonindexed, packing is the same as converting
578  // (again) to nonindexed.
579  make_nonindexed(dest, source);
580 
581  } else {
582  // The indexed case: build up a new index as we go.
583  CPT(GeomVertexArrayData) orig_vertices = get_vertices();
584  PT(GeomVertexArrayData) new_vertices = make_index_data();
585  GeomVertexWriter index(new_vertices, 0);
586  typedef pmap<int, int> CopiedIndices;
587  CopiedIndices copied_indices;
588 
589  int num_vertices = get_num_vertices();
590  int dest_start = dest->get_num_rows();
591  int strip_cut_index = get_strip_cut_index();
592 
593  for (int i = 0; i < num_vertices; ++i) {
594  int v = get_vertex(i);
595  if (v == strip_cut_index) {
596  continue;
597  }
598 
599  // Try to add the relation { v : size() }. If that succeeds, great; if
600  // it doesn't, look up whatever we previously added for v.
601  std::pair<CopiedIndices::iterator, bool> result =
602  copied_indices.insert(CopiedIndices::value_type(v, (int)copied_indices.size()));
603  int v2 = (*result.first).second + dest_start;
604  index.add_data1i(v2);
605 
606  if (result.second) {
607  // This is the first time we've seen vertex v.
608  dest->copy_row_from(v2, source, v, current_thread);
609  }
610  }
611 
612  set_vertices(new_vertices);
613  }
614 }
615 
616 /**
617  * Converts the primitive from nonindexed form to indexed form. This will
618  * simply create an index table that is numbered consecutively from
619  * get_first_vertex(); it does not automatically collapse together identical
620  * vertices that may have been split apart by a previous call to
621  * make_nonindexed().
622  *
623  * Don't call this in a downstream thread unless you don't mind it blowing
624  * away other changes you might have recently made in an upstream thread.
625  */
627 make_indexed() {
628  CDWriter cdata(_cycler, true);
629  do_make_indexed(cdata);
630 }
631 
632 /**
633  * Returns the element within the _vertices list at which the nth primitive
634  * starts.
635  *
636  * If i is one more than the highest valid primitive vertex, the return value
637  * will be one more than the last valid vertex. Thus, it is generally true
638  * that the vertices used by a particular primitive i are the set
639  * get_primitive_start(n) <= vi < get_primitive_start(n + 1) (although this
640  * range also includes the unused vertices between primitives).
641  */
643 get_primitive_start(int n) const {
644  int num_vertices_per_primitive = get_num_vertices_per_primitive();
645  int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive();
646 
647  if (num_vertices_per_primitive == 0) {
648  // This is a complex primitive type like a triangle strip: each primitive
649  // uses a different number of vertices.
650  CDReader cdata(_cycler);
651  nassertr(n >= 0 && n <= (int)cdata->_ends.size(), -1);
652  if (n == 0) {
653  return 0;
654  } else {
655  return cdata->_ends[n - 1] + num_unused_vertices_per_primitive;
656  }
657 
658  } else {
659  // This is a simple primitive type like a triangle: each primitive uses
660  // the same number of vertices.
661  return n * (num_vertices_per_primitive + num_unused_vertices_per_primitive);
662  }
663 }
664 
665 /**
666  * Returns the element within the _vertices list at which the nth primitive
667  * ends. This is one past the last valid element for the nth primitive.
668  */
670 get_primitive_end(int n) const {
671  int num_vertices_per_primitive = get_num_vertices_per_primitive();
672 
673  if (num_vertices_per_primitive == 0) {
674  // This is a complex primitive type like a triangle strip: each primitive
675  // uses a different number of vertices.
676  CDReader cdata(_cycler);
677  nassertr(n >= 0 && n < (int)cdata->_ends.size(), -1);
678  return cdata->_ends[n];
679 
680  } else {
681  // This is a simple primitive type like a triangle: each primitive uses
682  // the same number of vertices.
683  int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive();
684  return n * (num_vertices_per_primitive + num_unused_vertices_per_primitive) + num_vertices_per_primitive;
685  }
686 }
687 
688 /**
689  * Returns the number of vertices used by the nth primitive. This is the same
690  * thing as get_primitive_end(n) - get_primitive_start(n).
691  */
693 get_primitive_num_vertices(int n) const {
694  int num_vertices_per_primitive = get_num_vertices_per_primitive();
695 
696  if (num_vertices_per_primitive == 0) {
697  // This is a complex primitive type like a triangle strip: each primitive
698  // uses a different number of vertices.
699  CDReader cdata(_cycler);
700  nassertr(n >= 0 && n < (int)cdata->_ends.size(), 0);
701  if (n == 0) {
702  return cdata->_ends[0];
703  } else {
704  int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive();
705  return cdata->_ends[n] - cdata->_ends[n - 1] - num_unused_vertices_per_primitive;
706  }
707 
708  } else {
709  // This is a simple primitive type like a triangle: each primitive uses
710  // the same number of vertices.
711  return num_vertices_per_primitive;
712  }
713 }
714 
715 /**
716  * Returns the number of vertices used by all of the primitives. This is the
717  * same as summing get_primitive_num_vertices(n) for n in
718  * get_num_primitives(). It is like get_num_vertices except that it excludes
719  * all of the degenerate vertices and strip-cut indices.
720  */
722 get_num_used_vertices() const {
723  int num_primitives = get_num_primitives();
724 
725  if (num_primitives > 0) {
726  return get_num_vertices() - ((num_primitives - 1) *
728  } else {
729  return 0;
730  }
731 }
732 
733 /**
734  * Returns the minimum vertex index number used by the nth primitive in this
735  * object.
736  */
738 get_primitive_min_vertex(int n) const {
739  if (is_indexed()) {
740  CPT(GeomVertexArrayData) mins = get_mins();
741  nassertr(n >= 0 && n < mins->get_num_rows(), -1);
742 
743  GeomVertexReader index(mins, 0);
744  index.set_row_unsafe(n);
745  return index.get_data1i();
746  } else {
747  return get_primitive_start(n);
748  }
749 }
750 
751 /**
752  * Returns the maximum vertex index number used by the nth primitive in this
753  * object.
754  */
756 get_primitive_max_vertex(int n) const {
757  if (is_indexed()) {
758  CPT(GeomVertexArrayData) maxs = get_maxs();
759  nassertr(n >= 0 && n < maxs->get_num_rows(), -1);
760 
761  GeomVertexReader index(maxs, 0);
762  index.set_row_unsafe(n);
763  return index.get_data1i();
764  } else {
765  return get_primitive_end(n) - 1;
766  }
767 }
768 
769 /**
770  * Decomposes a complex primitive type into a simpler primitive type, for
771  * instance triangle strips to triangles, and returns a pointer to the new
772  * primitive definition. If the decomposition cannot be performed, this might
773  * return the original object.
774  *
775  * This method is useful for application code that wants to iterate through
776  * the set of triangles on the primitive without having to write handlers for
777  * each possible kind of primitive type.
778  */
779 CPT(GeomPrimitive) GeomPrimitive::
780 decompose() const {
781  if (gobj_cat.is_debug()) {
782  gobj_cat.debug()
783  << "Decomposing " << get_type() << ": " << (void *)this << "\n";
784  }
785 
786  PStatTimer timer(_decompose_pcollector);
787  return decompose_impl();
788 }
789 
790 /**
791  * Returns a new primitive with the shade_model reversed (if it is flat
792  * shaded), if possible. If the primitive type cannot be rotated, returns the
793  * original primitive, unrotated.
794  *
795  * If the current shade_model indicates flat_vertex_last, this should bring
796  * the last vertex to the first position; if it indicates flat_vertex_first,
797  * this should bring the first vertex to the last position.
798  */
799 CPT(GeomPrimitive) GeomPrimitive::
800 rotate() const {
801  if (gobj_cat.is_debug()) {
802  gobj_cat.debug()
803  << "Rotating " << get_type() << ": " << (void *)this << "\n";
804  }
805 
806  PStatTimer timer(_rotate_pcollector);
807  CPT(GeomVertexArrayData) rotated_vertices = rotate_impl();
808 
809  if (rotated_vertices == nullptr) {
810  // This primitive type can't be rotated.
811  return this;
812  }
813 
814  PT(GeomPrimitive) new_prim = make_copy();
815  new_prim->set_vertices(rotated_vertices);
816 
817  switch (get_shade_model()) {
818  case SM_flat_first_vertex:
819  new_prim->set_shade_model(SM_flat_last_vertex);
820  break;
821 
822  case SM_flat_last_vertex:
823  new_prim->set_shade_model(SM_flat_first_vertex);
824  break;
825 
826  default:
827  break;
828  }
829 
830  return new_prim;
831 }
832 
833 /**
834  * Duplicates triangles in the primitive so that each triangle is back-to-back
835  * with another triangle facing in the opposite direction. Note that this
836  * doesn't affect vertex normals, so this operation alone won't work in the
837  * presence of lighting (but see SceneGraphReducer::doubleside()).
838  *
839  * Also see CullFaceAttrib, which can enable rendering of both sides of a
840  * triangle without having to duplicate it (but which doesn't necessarily work
841  * in the presence of lighting).
842  */
843 CPT(GeomPrimitive) GeomPrimitive::
844 doubleside() const {
845  if (gobj_cat.is_debug()) {
846  gobj_cat.debug()
847  << "Doublesiding " << get_type() << ": " << (void *)this << "\n";
848  }
849 
850  PStatTimer timer(_doubleside_pcollector);
851  return doubleside_impl();
852 }
853 
854 /**
855  * Reverses the winding order in the primitive so that each triangle is facing
856  * in the opposite direction it was originally. Note that this doesn't affect
857  * vertex normals, so this operation alone won't work in the presence of
858  * lighting (but see SceneGraphReducer::reverse()).
859  *
860  * Also see CullFaceAttrib, which can change the visible direction of a
861  * triangle without having to duplicate it (but which doesn't necessarily work
862  * in the presence of lighting).
863  */
864 CPT(GeomPrimitive) GeomPrimitive::
865 reverse() const {
866  if (gobj_cat.is_debug()) {
867  gobj_cat.debug()
868  << "Reversing " << get_type() << ": " << (void *)this << "\n";
869  }
870 
871  PStatTimer timer(_reverse_pcollector);
872  return reverse_impl();
873 }
874 
875 /**
876  * Returns a new primitive that is compatible with the indicated shade model,
877  * if possible, or NULL if this is not possible.
878  *
879  * In most cases, this will return either NULL or the original primitive. In
880  * the case of a SM_flat_first_vertex vs. a SM_flat_last_vertex (or vice-
881  * versa), however, it will return a rotated primitive.
882  */
883 CPT(GeomPrimitive) GeomPrimitive::
884 match_shade_model(GeomPrimitive::ShadeModel shade_model) const {
885  ShadeModel this_shade_model = get_shade_model();
886  if (this_shade_model == shade_model) {
887  // Trivially compatible.
888  return this;
889  }
890 
891  if (this_shade_model == SM_uniform || shade_model == SM_uniform) {
892  // SM_uniform is compatible with anything.
893  return this;
894  }
895 
896  if ((this_shade_model == SM_flat_first_vertex && shade_model == SM_flat_last_vertex) ||
897  (this_shade_model == SM_flat_last_vertex && shade_model == SM_flat_first_vertex)) {
898  // Needs to be rotated.
899  CPT(GeomPrimitive) rotated = rotate();
900  if (rotated.p() == this) {
901  // Oops, can't be rotated, sorry.
902  return nullptr;
903  }
904  return rotated;
905  }
906 
907  // Not compatible, sorry.
908  return nullptr;
909 }
910 
911 /**
912  * Returns a new GeomPoints primitive that represents each of the vertices in
913  * the original primitive, rendered exactly once. If the original primitive
914  * is already a GeomPoints primitive, returns the original primitive
915  * unchanged.
916  */
917 CPT(GeomPrimitive) GeomPrimitive::
918 make_points() const {
919  if (is_exact_type(GeomPoints::get_class_type())) {
920  return this;
921  }
922 
923  // First, get a list of all of the vertices referenced by the original
924  // primitive.
925  BitArray bits;
926  {
928  reader.get_referenced_vertices(bits);
929  }
930 
931  // Now construct a new index array with just those bits.
932  PT(GeomVertexArrayData) new_vertices = make_index_data();
933  new_vertices->unclean_set_num_rows(bits.get_num_on_bits());
934 
935  GeomVertexWriter new_index(new_vertices, 0);
936  int p = bits.get_lowest_on_bit();
937  while (p != -1) {
938  while (bits.get_bit(p)) {
939  new_index.set_data1i(p);
940  ++p;
941  }
942  int q = bits.get_next_higher_different_bit(p);
943  if (q == p) {
944  break;
945  }
946  p = q;
947  }
948 
949  PT(GeomPrimitive) points = new GeomPoints(UH_dynamic);
950  points->set_vertices(new_vertices);
951 
952  return points;
953 }
954 
955 /**
956  * Returns a new GeomLines primitive that represents each of the edges in the
957  * original primitive rendered as a line. If the original primitive is
958  * already a GeomLines primitive, returns the original primitive unchanged.
959  */
960 CPT(GeomPrimitive) GeomPrimitive::
961 make_lines() const {
962  if (is_exact_type(GeomLines::get_class_type())) {
963  return this;
964  }
965 
966  PrimitiveType prim_type = get_primitive_type();
967  if (prim_type == PT_lines) {
968  // It's a line strip, just decompose it.
969  return decompose();
970 
971  } else if (prim_type != PT_polygons && prim_type != PT_patches) {
972  // Don't know how to represent this in wireframe.
973  return this;
974  }
975 
976  if (prim_type == PT_polygons && !is_exact_type(GeomTriangles::get_class_type())) {
977  // Decompose tristrips. We could probably make this more efficient by
978  // making a specific implementation of make_lines for GeomTristrips.
979  return decompose()->make_lines();
980  }
981 
982  // Iterate through the primitives.
983  int num_primitives = get_num_primitives();
984  int verts_per_prim = get_num_vertices_per_primitive();
985 
986  PT(GeomVertexArrayData) new_vertices = make_index_data();
987  new_vertices->unclean_set_num_rows(num_primitives * verts_per_prim * 2);
988 
989  GeomVertexWriter new_index(new_vertices, 0);
990 
991  for (int i = 0; i < num_primitives; ++i) {
992  int begin = get_primitive_start(i);
993  int end = get_primitive_end(i);
994  if (begin == end) {
995  continue;
996  }
997  for (int vi = begin; vi < end - 1; vi++) {
998  new_index.set_data1i(get_vertex(vi));
999  new_index.set_data1i(get_vertex(vi + 1));
1000  }
1001  new_index.set_data1i(get_vertex(end - 1));
1002  new_index.set_data1i(get_vertex(begin));
1003  }
1004 
1005  PT(GeomPrimitive) lines = new GeomLines(UH_dynamic);
1006  lines->set_vertices(new_vertices);
1007 
1008  return lines;
1009 }
1010 
1011 /**
1012  * Decomposes a complex primitive type into a simpler primitive type, for
1013  * instance triangle strips to triangles, puts these in a new GeomPatches
1014  * object and returns a pointer to the new primitive definition. If the
1015  * decomposition cannot be performed, this might return the original object.
1016  *
1017  * This method is useful for application code that wants to use tesselation
1018  * shaders on arbitrary geometry.
1019  */
1020 CPT(GeomPrimitive) GeomPrimitive::
1021 make_patches() const {
1022  if (is_exact_type(GeomPatches::get_class_type())) {
1023  return this;
1024  }
1025 
1026  CPT(GeomPrimitive) prim = decompose_impl();
1027  int num_vertices_per_patch = prim->get_num_vertices_per_primitive();
1028 
1029  PT(GeomPrimitive) patches = new GeomPatches(num_vertices_per_patch, get_usage_hint());
1030 
1031  if (prim->is_indexed()) {
1032  patches->set_vertices(prim->get_vertices());
1033  } else {
1034  patches->set_nonindexed_vertices(prim->get_first_vertex(),
1035  prim->get_num_vertices());
1036  }
1037 
1038  return patches;
1039 }
1040 
1041 /**
1042  * Adds adjacency information to this primitive. May return null if this type
1043  * of geometry does not support adjacency information.
1044  *
1045  * @since 1.10.0
1046  */
1047 CPT(GeomPrimitive) GeomPrimitive::
1048 make_adjacency() const {
1049  return nullptr;
1050 }
1051 
1052 /**
1053  * Returns the number of bytes consumed by the primitive and its index
1054  * table(s).
1055  */
1056 int GeomPrimitive::
1057 get_num_bytes() const {
1058  CDReader cdata(_cycler);
1059  int num_bytes = cdata->_ends.size() * sizeof(int) + sizeof(GeomPrimitive);
1060  if (!cdata->_vertices.is_null()) {
1061  num_bytes += cdata->_vertices.get_read_pointer()->get_data_size_bytes();
1062  }
1063 
1064  return num_bytes;
1065 }
1066 
1067 /**
1068  * Returns true if the primitive data is currently resident in memory. If
1069  * this returns false, the primitive data will be brought back into memory
1070  * shortly; try again later.
1071  */
1072 bool GeomPrimitive::
1073 request_resident(Thread *current_thread) const {
1074  CDReader cdata(_cycler, current_thread);
1075 
1076  bool resident = true;
1077 
1078  if (!cdata->_vertices.is_null() &&
1079  !cdata->_vertices.get_read_pointer(current_thread)->request_resident(current_thread)) {
1080  resident = false;
1081  }
1082 
1083  if (is_composite() && cdata->_got_minmax) {
1084  if (!cdata->_mins.is_null() &&
1085  !cdata->_mins.get_read_pointer(current_thread)->request_resident(current_thread)) {
1086  resident = false;
1087  }
1088  if (!cdata->_maxs.is_null() &&
1089  !cdata->_maxs.get_read_pointer(current_thread)->request_resident(current_thread)) {
1090  resident = false;
1091  }
1092  }
1093 
1094  return resident;
1095 }
1096 
1097 /**
1098  *
1099  */
1100 void GeomPrimitive::
1101 output(std::ostream &out) const {
1102  out << get_type() << ", " << get_num_primitives()
1103  << ", " << get_num_vertices();
1104 }
1105 
1106 /**
1107  *
1108  */
1109 void GeomPrimitive::
1110 write(std::ostream &out, int indent_level) const {
1111  indent(out, indent_level)
1112  << get_type();
1113  if (is_indexed()) {
1114  out << " (indexed)";
1115  } else {
1116  out << " (nonindexed)";
1117  }
1118  out << ":\n";
1119  int num_primitives = get_num_primitives();
1120  int num_vertices = get_num_vertices();
1121  int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive();
1122  for (int i = 0; i < num_primitives; ++i) {
1123  indent(out, indent_level + 2)
1124  << "[";
1125  int begin = get_primitive_start(i);
1126  int end = get_primitive_end(i);
1127  for (int vi = begin; vi < end; vi++) {
1128  out << " " << get_vertex(vi);
1129  }
1130  out << " ]";
1131  if (end < num_vertices) {
1132  for (int ui = 0; ui < num_unused_vertices_per_primitive; ++ui) {
1133  if (end + ui < num_vertices) {
1134  out << " " << get_vertex(end + ui);
1135  } else {
1136  out << " ?";
1137  }
1138  }
1139  }
1140  out << "\n";
1141  }
1142 }
1143 
1144 /**
1145  * Returns a modifiable pointer to the vertex index list, so application code
1146  * can directly fiddle with this data. Use with caution, since there are no
1147  * checks that the data will be left in a stable state.
1148  *
1149  * If this is called on a nonindexed primitive, it will implicitly be
1150  * converted to an indexed primitive.
1151  *
1152  * If num_vertices is not -1, it specifies an artificial limit to the number
1153  * of vertices in the array. Otherwise, all of the vertices in the array will
1154  * be used.
1155  *
1156  * Don't call this in a downstream thread unless you don't mind it blowing
1157  * away other changes you might have recently made in an upstream thread.
1158  *
1159  * This method is intended for low-level usage only. There are higher-level
1160  * methods for more common usage. We recommend you do not use this method
1161  * directly. If you do, be sure you know what you are doing!
1162  */
1163 PT(GeomVertexArrayData) GeomPrimitive::
1164 modify_vertices(int num_vertices) {
1165  CDWriter cdata(_cycler, true);
1166  PT(GeomVertexArrayData) vertices = do_modify_vertices(cdata);
1167  cdata->_num_vertices = num_vertices;
1168  return vertices;
1169 }
1170 
1171 /**
1172  * Completely replaces the vertex index list with a new table. Chances are
1173  * good that you should also replace the ends list with set_ends() at the same
1174  * time.
1175  *
1176  * If num_vertices is not -1, it specifies an artificial limit to the number
1177  * of vertices in the array. Otherwise, all of the vertices in the array will
1178  * be used.
1179  *
1180  * Don't call this in a downstream thread unless you don't mind it blowing
1181  * away other changes you might have recently made in an upstream thread.
1182  *
1183  * This method is intended for low-level usage only. There are higher-level
1184  * methods for more common usage. We recommend you do not use this method
1185  * directly. If you do, be sure you know what you are doing!
1186  */
1188 set_vertices(const GeomVertexArrayData *vertices, int num_vertices) {
1189  CDWriter cdata(_cycler, true);
1190  cdata->_vertices = (GeomVertexArrayData *)vertices;
1191  cdata->_num_vertices = num_vertices;
1192 
1193  // Validate the format and make sure to copy its numeric type.
1194  const GeomVertexArrayFormat *format = vertices->get_array_format();
1195  nassertv(format->get_num_columns() == 1);
1196  cdata->_index_type = format->get_column(0)->get_numeric_type();
1197 
1198  cdata->_modified = Geom::get_next_modified();
1199  cdata->_got_minmax = false;
1200 }
1201 
1202 /**
1203  * Sets the primitive up as a nonindexed primitive, using the indicated vertex
1204  * range.
1205  *
1206  * Don't call this in a downstream thread unless you don't mind it blowing
1207  * away other changes you might have recently made in an upstream thread.
1208  *
1209  * This method is intended for low-level usage only. There are higher-level
1210  * methods for more common usage. We recommend you do not use this method
1211  * directly. If you do, be sure you know what you are doing!
1212  */
1214 set_nonindexed_vertices(int first_vertex, int num_vertices) {
1215  nassertv(num_vertices != -1);
1216  CDWriter cdata(_cycler, true);
1217  cdata->_vertices = nullptr;
1218  cdata->_first_vertex = first_vertex;
1219  cdata->_num_vertices = num_vertices;
1220 
1221  cdata->_modified = Geom::get_next_modified();
1222  cdata->_got_minmax = false;
1223 
1224  // Force the minmax to be recomputed.
1225  recompute_minmax(cdata);
1226 }
1227 
1228 /**
1229  * Returns a modifiable pointer to the primitive ends array, so application
1230  * code can directly fiddle with this data. Use with caution, since there are
1231  * no checks that the data will be left in a stable state.
1232  *
1233  * Note that simple primitive types, like triangles, do not have a ends array:
1234  * since all the primitives have the same number of vertices, it is not
1235  * needed.
1236  *
1237  * Don't call this in a downstream thread unless you don't mind it blowing
1238  * away other changes you might have recently made in an upstream thread.
1239  *
1240  * This method is intended for low-level usage only. There are higher-level
1241  * methods for more common usage. We recommend you do not use this method
1242  * directly. If you do, be sure you know what you are doing!
1243  */
1245 modify_ends() {
1246  CDWriter cdata(_cycler, true);
1247 
1248  cdata->_modified = Geom::get_next_modified();
1249  cdata->_got_minmax = false;
1250 
1251  if (cdata->_ends.get_ref_count() > 1) {
1252  PTA_int new_ends;
1253  new_ends.v() = cdata->_ends.v();
1254  cdata->_ends = new_ends;
1255  }
1256  return cdata->_ends;
1257 }
1258 
1259 /**
1260  * Completely replaces the primitive ends array with a new table. Chances are
1261  * good that you should also replace the vertices list with set_vertices() at
1262  * the same time.
1263  *
1264  * Note that simple primitive types, like triangles, do not have a ends array:
1265  * since all the primitives have the same number of vertices, it is not
1266  * needed.
1267  *
1268  * Don't call this in a downstream thread unless you don't mind it blowing
1269  * away other changes you might have recently made in an upstream thread.
1270  *
1271  * This method is intended for low-level usage only. There are higher-level
1272  * methods for more common usage. We recommend you do not use this method
1273  * directly. If you do, be sure you know what you are doing!
1274  */
1276 set_ends(PTA_int ends) {
1277  CDWriter cdata(_cycler, true);
1278  cdata->_ends = ends;
1279 
1280  cdata->_modified = Geom::get_next_modified();
1281  cdata->_got_minmax = false;
1282 }
1283 
1284 /**
1285  * Explicitly specifies the minimum and maximum vertices, as well as the lists
1286  * of per-component min and max.
1287  *
1288  * Use this method with extreme caution. It's generally better to let the
1289  * GeomPrimitive compute these explicitly, unless for some reason you can do
1290  * it faster and you absolutely need the speed improvement.
1291  *
1292  * Note that any modification to the vertex array will normally cause this to
1293  * be recomputed, unless you set it immediately again.
1294  *
1295  * This method is intended for low-level usage only. There are higher-level
1296  * methods for more common usage. We recommend you do not use this method
1297  * directly. If you do, be sure you know what you are doing!
1298  */
1300 set_minmax(int min_vertex, int max_vertex,
1302  CDWriter cdata(_cycler, true);
1303  cdata->_min_vertex = min_vertex;
1304  cdata->_max_vertex = max_vertex;
1305  cdata->_mins = mins;
1306  cdata->_maxs = maxs;
1307 
1308  cdata->_modified = Geom::get_next_modified();
1309  cdata->_got_minmax = true;
1310 }
1311 
1312 /**
1313  * Undoes a previous call to set_minmax(), and allows the minimum and maximum
1314  * values to be recomputed normally.
1315  *
1316  * This method is intended for low-level usage only. There are higher-level
1317  * methods for more common usage. We recommend you do not use this method
1318  * directly. If you do, be sure you know what you are doing!
1319  */
1321 clear_minmax() {
1322  CDWriter cdata(_cycler, true);
1323  cdata->_got_minmax = false;
1324 }
1325 
1326 /**
1327  * If the primitive type is a simple type in which all primitives have the
1328  * same number of vertices, like triangles, returns the number of vertices per
1329  * primitive. If the primitive type is a more complex type in which different
1330  * primitives might have different numbers of vertices, for instance a
1331  * triangle strip, returns 0.
1332  *
1333  * This method is intended for low-level usage only. There are higher-level
1334  * methods for more common usage. We recommend you do not use this method
1335  * directly. If you do, be sure you know what you are doing!
1336  */
1337 int GeomPrimitive::
1339  return 0;
1340 }
1341 
1342 /**
1343  * Returns the minimum number of vertices that must be added before
1344  * close_primitive() may legally be called.
1345  *
1346  * This method is intended for low-level usage only. There are higher-level
1347  * methods for more common usage. We recommend you do not use this method
1348  * directly. If you do, be sure you know what you are doing!
1349  */
1350 int GeomPrimitive::
1352  return 3;
1353 }
1354 
1355 /**
1356  * Returns the number of vertices that are added between primitives that
1357  * aren't, strictly speaking, part of the primitives themselves. This is
1358  * used, for instance, to define degenerate triangles to connect otherwise
1359  * disconnected triangle strips.
1360  *
1361  * This method is intended for low-level usage only. There are higher-level
1362  * methods for more common usage. We recommend you do not use this method
1363  * directly. If you do, be sure you know what you are doing!
1364  */
1365 int GeomPrimitive::
1367  return 0;
1368 }
1369 
1370 /**
1371  * Indicates that the data should be enqueued to be prepared in the indicated
1372  * prepared_objects at the beginning of the next frame. This will ensure the
1373  * data is already loaded into the GSG if it is expected to be rendered soon.
1374  *
1375  * Use this function instead of prepare_now() to preload datas from a user
1376  * interface standpoint.
1377  */
1379 prepare(PreparedGraphicsObjects *prepared_objects) {
1380  if (is_indexed()) {
1381  prepared_objects->enqueue_index_buffer(this);
1382  }
1383 }
1384 
1385 /**
1386  * Returns true if the data has already been prepared or enqueued for
1387  * preparation on the indicated GSG, false otherwise.
1388  */
1390 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
1391  Contexts::const_iterator ci;
1392  ci = _contexts.find(prepared_objects);
1393  if (ci != _contexts.end()) {
1394  return true;
1395  }
1396  return prepared_objects->is_index_buffer_queued(this);
1397 }
1398 
1399 /**
1400  * Creates a context for the data on the particular GSG, if it does not
1401  * already exist. Returns the new (or old) IndexBufferContext. This assumes
1402  * that the GraphicsStateGuardian is the currently active rendering context
1403  * and that it is ready to accept new datas. If this is not necessarily the
1404  * case, you should use prepare() instead.
1405  *
1406  * Normally, this is not called directly except by the GraphicsStateGuardian;
1407  * a data does not need to be explicitly prepared by the user before it may be
1408  * rendered.
1409  */
1411 prepare_now(PreparedGraphicsObjects *prepared_objects,
1413  nassertr(is_indexed(), nullptr);
1414 
1415  Contexts::const_iterator ci;
1416  ci = _contexts.find(prepared_objects);
1417  if (ci != _contexts.end()) {
1418  return (*ci).second;
1419  }
1420 
1421  IndexBufferContext *ibc = prepared_objects->prepare_index_buffer_now(this, gsg);
1422  if (ibc != nullptr) {
1423  _contexts[prepared_objects] = ibc;
1424  }
1425  return ibc;
1426 }
1427 
1428 /**
1429  * Frees the data context only on the indicated object, if it exists there.
1430  * Returns true if it was released, false if it had not been prepared.
1431  */
1433 release(PreparedGraphicsObjects *prepared_objects) {
1434  Contexts::iterator ci;
1435  ci = _contexts.find(prepared_objects);
1436  if (ci != _contexts.end()) {
1437  IndexBufferContext *ibc = (*ci).second;
1438  prepared_objects->release_index_buffer(ibc);
1439  return true;
1440  }
1441 
1442  // Maybe it wasn't prepared yet, but it's about to be.
1443  return prepared_objects->dequeue_index_buffer(this);
1444 }
1445 
1446 /**
1447  * Frees the context allocated on all objects for which the data has been
1448  * declared. Returns the number of contexts which have been freed.
1449  */
1451 release_all() {
1452  // We have to traverse a copy of the _contexts list, because the
1453  // PreparedGraphicsObjects object will call clear_prepared() in response to
1454  // each release_index_buffer(), and we don't want to be modifying the
1455  // _contexts list while we're traversing it.
1456  Contexts temp = _contexts;
1457  int num_freed = (int)_contexts.size();
1458 
1459  Contexts::const_iterator ci;
1460  for (ci = temp.begin(); ci != temp.end(); ++ci) {
1461  PreparedGraphicsObjects *prepared_objects = (*ci).first;
1462  IndexBufferContext *ibc = (*ci).second;
1463  prepared_objects->release_index_buffer(ibc);
1464  }
1465 
1466  // Now that we've called release_index_buffer() on every known context, the
1467  // _contexts list should have completely emptied itself.
1468  nassertr(_contexts.empty(), num_freed);
1469 
1470  return num_freed;
1471 }
1472 
1473 /**
1474  * Returns a registered GeomVertexArrayFormat of the indicated unsigned
1475  * integer numeric type for storing index values.
1476  */
1478 get_index_format(NumericType index_type) {
1479  switch (index_type) {
1480  case NT_uint8:
1481  {
1482  static CPT(GeomVertexArrayFormat) cformat = nullptr;
1483  if (cformat == nullptr) {
1484  cformat = make_index_format(NT_uint8);
1485  }
1486  return cformat;
1487  }
1488  case NT_uint16:
1489  {
1490  static CPT(GeomVertexArrayFormat) cformat = nullptr;
1491  if (cformat == nullptr) {
1492  cformat = make_index_format(NT_uint16);
1493  }
1494  return cformat;
1495  }
1496  case NT_uint32:
1497  {
1498  static CPT(GeomVertexArrayFormat) cformat = nullptr;
1499  if (cformat == nullptr) {
1500  cformat = make_index_format(NT_uint32);
1501  }
1502  return cformat;
1503  }
1504 
1505  default:
1506  gobj_cat.error()
1507  << "Not a valid index type: " << index_type << "\n";
1508  return nullptr;
1509  }
1510 
1511  return nullptr;
1512 }
1513 
1514 /**
1515  * Removes the indicated PreparedGraphicsObjects table from the data array's
1516  * table, without actually releasing the data array. This is intended to be
1517  * called only from PreparedGraphicsObjects::release_index_buffer(); it should
1518  * never be called by user code.
1519  */
1520 void GeomPrimitive::
1521 clear_prepared(PreparedGraphicsObjects *prepared_objects) {
1522  Contexts::iterator ci;
1523  ci = _contexts.find(prepared_objects);
1524  if (ci != _contexts.end()) {
1525  _contexts.erase(ci);
1526  } else {
1527  // If this assertion fails, clear_prepared() was given a prepared_objects
1528  // which the data array didn't know about.
1529  nassert_raise("unknown PreparedGraphicsObjects");
1530  }
1531 }
1532 
1533 /**
1534  * Returns the largest index value that can be stored in an index of the
1535  * indicated type, minus one (to leave room for a potential strip cut index)
1536  */
1537 int GeomPrimitive::
1538 get_highest_index_value(NumericType index_type) {
1539  // Reserve the highest possible index because implementations use this as a
1540  // strip-cut index.
1541  switch (index_type) {
1542  case NT_uint8:
1543  return 0xff - 1;
1544 
1545  case NT_uint16:
1546  return 0xffff - 1;
1547 
1548  case NT_uint32:
1549  // We don't actually allow use of the sign bit, since all of our functions
1550  // receive an "int" instead of an "unsigned int".
1551  return 0x7fffffff - 1;
1552 
1553  default:
1554  return 0;
1555  }
1556 }
1557 
1558 /**
1559  * Returns the index of the indicated type that is reserved for use as a strip
1560  * cut index, if enabled for the primitive. When the renderer encounters this
1561  * index, it will restart the primitive. This is guaranteed not to point to
1562  * an actual vertex.
1563  */
1564 int GeomPrimitive::
1565 get_strip_cut_index(NumericType index_type) {
1566  // Reserve the highest possible index because implementations use this as a
1567  // strip-cut index.
1568  switch (index_type) {
1569  case NT_uint8:
1570  return 0xff;
1571 
1572  case NT_uint16:
1573  return 0xffff;
1574 
1575  case NT_uint32:
1576  default:
1577  return -1;
1578  }
1579 }
1580 
1581 /**
1582  * Expands min_point and max_point to include all of the vertices in the Geom,
1583  * if any (or the data of any point type, for instance, texture coordinates--
1584  * based on the column name). found_any is set true if any points are found.
1585  * It is the caller's responsibility to initialize min_point, max_point, and
1586  * found_any before calling this function. It also sets sq_center_dist, which
1587  * is the square of the maximum distance of the points to the center. This
1588  * can be useful when deciding whether a sphere volume might be more
1589  * appropriate.
1590  */
1592 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
1593  PN_stdfloat &sq_center_dist, bool &found_any,
1594  const GeomVertexData *vertex_data,
1595  bool got_mat, const LMatrix4 &mat,
1596  const InternalName *column_name,
1597  Thread *current_thread) const {
1598  GeomVertexReader reader(vertex_data, column_name, current_thread);
1599  if (!reader.has_column()) {
1600  // No vertex data.
1601  return;
1602  }
1603 
1604  CDReader cdata(_cycler, current_thread);
1605  int i = 0;
1606 
1607  if (cdata->_vertices.is_null()) {
1608  // Nonindexed case.
1609  nassertv(cdata->_num_vertices != -1);
1610  if (cdata->_num_vertices == 0) {
1611  return;
1612  }
1613 
1614  if (got_mat) {
1615  // Find the first non-NaN vertex.
1616  while (!found_any && i < cdata->_num_vertices) {
1617  reader.set_row(cdata->_first_vertex + i);
1618  LPoint3 first_vertex = mat.xform_point_general(reader.get_data3());
1619  if (!first_vertex.is_nan()) {
1620  min_point = first_vertex;
1621  max_point = first_vertex;
1622  sq_center_dist = first_vertex.length_squared();
1623  found_any = true;
1624  }
1625  ++i;
1626  }
1627 
1628  for (; i < cdata->_num_vertices; ++i) {
1629  reader.set_row_unsafe(cdata->_first_vertex + i);
1630  nassertv(!reader.is_at_end());
1631 
1632  LPoint3 vertex = mat.xform_point_general(reader.get_data3());
1633 
1634  min_point.set(min(min_point[0], vertex[0]),
1635  min(min_point[1], vertex[1]),
1636  min(min_point[2], vertex[2]));
1637  max_point.set(max(max_point[0], vertex[0]),
1638  max(max_point[1], vertex[1]),
1639  max(max_point[2], vertex[2]));
1640  sq_center_dist = max(sq_center_dist, vertex.length_squared());
1641  }
1642  } else {
1643  // Find the first non-NaN vertex.
1644  while (!found_any && i < cdata->_num_vertices) {
1645  reader.set_row(cdata->_first_vertex + i);
1646  LPoint3 first_vertex = reader.get_data3();
1647  if (!first_vertex.is_nan()) {
1648  min_point = first_vertex;
1649  max_point = first_vertex;
1650  sq_center_dist = first_vertex.length_squared();
1651  found_any = true;
1652  }
1653  ++i;
1654  }
1655 
1656  for (; i < cdata->_num_vertices; ++i) {
1657  reader.set_row_unsafe(cdata->_first_vertex + i);
1658  nassertv(!reader.is_at_end());
1659 
1660  const LVecBase3 &vertex = reader.get_data3();
1661 
1662  min_point.set(min(min_point[0], vertex[0]),
1663  min(min_point[1], vertex[1]),
1664  min(min_point[2], vertex[2]));
1665  max_point.set(max(max_point[0], vertex[0]),
1666  max(max_point[1], vertex[1]),
1667  max(max_point[2], vertex[2]));
1668  sq_center_dist = max(sq_center_dist, vertex.length_squared());
1669  }
1670  }
1671 
1672  } else {
1673  // Indexed case.
1674  GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0, current_thread);
1675  if (index.is_at_end()) {
1676  return;
1677  }
1678 
1679  int strip_cut_index = get_strip_cut_index(cdata->_index_type);
1680 
1681  if (got_mat) {
1682  // Find the first non-NaN vertex.
1683  while (!found_any && !index.is_at_end()) {
1684  int ii = index.get_data1i();
1685  if (ii != strip_cut_index) {
1686  reader.set_row(ii);
1687  LPoint3 first_vertex = mat.xform_point_general(reader.get_data3());
1688  if (!first_vertex.is_nan()) {
1689  min_point = first_vertex;
1690  max_point = first_vertex;
1691  sq_center_dist = first_vertex.length_squared();
1692  found_any = true;
1693  }
1694  }
1695  }
1696 
1697  while (!index.is_at_end()) {
1698  int ii = index.get_data1i();
1699  if (ii == strip_cut_index) {
1700  continue;
1701  }
1702  reader.set_row_unsafe(ii);
1703  nassertv(!reader.is_at_end());
1704 
1705  LPoint3 vertex = mat.xform_point_general(reader.get_data3());
1706 
1707  min_point.set(min(min_point[0], vertex[0]),
1708  min(min_point[1], vertex[1]),
1709  min(min_point[2], vertex[2]));
1710  max_point.set(max(max_point[0], vertex[0]),
1711  max(max_point[1], vertex[1]),
1712  max(max_point[2], vertex[2]));
1713  sq_center_dist = max(sq_center_dist, vertex.length_squared());
1714  }
1715  } else {
1716  // Find the first non-NaN vertex.
1717  while (!found_any && !index.is_at_end()) {
1718  int ii = index.get_data1i();
1719  if (ii != strip_cut_index) {
1720  reader.set_row(ii);
1721  LVecBase3 first_vertex = reader.get_data3();
1722  if (!first_vertex.is_nan()) {
1723  min_point = first_vertex;
1724  max_point = first_vertex;
1725  sq_center_dist = first_vertex.length_squared();
1726  found_any = true;
1727  }
1728  }
1729  }
1730 
1731  while (!index.is_at_end()) {
1732  int ii = index.get_data1i();
1733  if (ii == strip_cut_index) {
1734  continue;
1735  }
1736  reader.set_row_unsafe(ii);
1737  nassertv(!reader.is_at_end());
1738 
1739  const LVecBase3 &vertex = reader.get_data3();
1740 
1741  min_point.set(min(min_point[0], vertex[0]),
1742  min(min_point[1], vertex[1]),
1743  min(min_point[2], vertex[2]));
1744  max_point.set(max(max_point[0], vertex[0]),
1745  max(max_point[1], vertex[1]),
1746  max(max_point[2], vertex[2]));
1747  sq_center_dist = max(sq_center_dist, vertex.length_squared());
1748  }
1749  }
1750  }
1751 }
1752 
1753 /**
1754  * Expands radius so that a sphere with the given center point fits all of the
1755  * vertices.
1756  *
1757  * The center point is assumed to already have been transformed by the matrix,
1758  * if one is given.
1759  */
1761 calc_sphere_radius(const LPoint3 &center, PN_stdfloat &sq_radius,
1762  bool &found_any, const GeomVertexData *vertex_data,
1763  Thread *current_thread) const {
1764  GeomVertexReader reader(vertex_data, InternalName::get_vertex(), current_thread);
1765  if (!reader.has_column()) {
1766  // No vertex data.
1767  return;
1768  }
1769 
1770  if (!found_any) {
1771  sq_radius = 0.0;
1772  }
1773 
1774  CDReader cdata(_cycler, current_thread);
1775 
1776  if (cdata->_vertices.is_null()) {
1777  // Nonindexed case.
1778  nassertv(cdata->_num_vertices != -1);
1779  if (cdata->_num_vertices == 0) {
1780  return;
1781  }
1782  found_any = true;
1783 
1784  for (int i = 0; i < cdata->_num_vertices; ++i) {
1785  reader.set_row_unsafe(cdata->_first_vertex + i);
1786  const LVecBase3 &vertex = reader.get_data3();
1787 
1788  sq_radius = max(sq_radius, (vertex - center).length_squared());
1789  }
1790 
1791  } else {
1792  // Indexed case.
1793  GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0, current_thread);
1794  if (index.is_at_end()) {
1795  return;
1796  }
1797  found_any = true;
1798 
1799  int strip_cut_index = get_strip_cut_index(cdata->_index_type);
1800 
1801  while (!index.is_at_end()) {
1802  int ii = index.get_data1i();
1803  if (ii == strip_cut_index) {
1804  continue;
1805  }
1806  reader.set_row_unsafe(ii);
1807  const LVecBase3 &vertex = reader.get_data3();
1808 
1809  sq_radius = max(sq_radius, (vertex - center).length_squared());
1810  }
1811  }
1812 }
1813 
1814 /**
1815  * Decomposes a complex primitive type into a simpler primitive type, for
1816  * instance triangle strips to triangles, and returns a pointer to the new
1817  * primitive definition. If the decomposition cannot be performed, this might
1818  * return the original object.
1819  *
1820  * This method is useful for application code that wants to iterate through
1821  * the set of triangles on the primitive without having to write handlers for
1822  * each possible kind of primitive type.
1823  */
1824 CPT(GeomPrimitive) GeomPrimitive::
1825 decompose_impl() const {
1826  return this;
1827 }
1828 
1829 /**
1830  * The virtual implementation of rotate().
1831  */
1832 CPT(GeomVertexArrayData) GeomPrimitive::
1833 rotate_impl() const {
1834  // The default implementation doesn't even try to do anything.
1835  nassertr(false, nullptr);
1836  return nullptr;
1837 }
1838 
1839 /**
1840  * The virtual implementation of doubleside().
1841  */
1842 CPT(GeomPrimitive) GeomPrimitive::
1843 doubleside_impl() const {
1844  return this;
1845 }
1846 
1847 /**
1848  * The virtual implementation of reverse().
1849  */
1850 CPT(GeomPrimitive) GeomPrimitive::
1851 reverse_impl() const {
1852  return this;
1853 }
1854 
1855 /**
1856  * Should be redefined to return true in any primitive that implements
1857  * append_unused_vertices().
1858  */
1859 bool GeomPrimitive::
1860 requires_unused_vertices() const {
1861  return false;
1862 }
1863 
1864 /**
1865  * Called when a new primitive is begun (other than the first primitive), this
1866  * should add some degenerate vertices between primitives, if the primitive
1867  * type requires that. The second parameter is the first vertex that begins
1868  * the new primitive.
1869  *
1870  * This method is only called if requires_unused_vertices(), above, returns
1871  * true.
1872  */
1873 void GeomPrimitive::
1874 append_unused_vertices(GeomVertexArrayData *, int) {
1875 }
1876 
1877 /**
1878  * Recomputes the _min_vertex and _max_vertex values if necessary.
1879  */
1880 void GeomPrimitive::
1881 recompute_minmax(GeomPrimitive::CData *cdata) {
1882  if (cdata->_vertices.is_null()) {
1883  // In the nonindexed case, we don't need to do much (the minmax is
1884  // trivial).
1885  nassertv(cdata->_num_vertices != -1);
1886  cdata->_min_vertex = cdata->_first_vertex;
1887  cdata->_max_vertex = cdata->_first_vertex + cdata->_num_vertices - 1;
1888  cdata->_mins.clear();
1889  cdata->_maxs.clear();
1890 
1891  } else {
1892  int num_vertices = cdata->_vertices.get_read_pointer()->get_num_rows();
1893 
1894  if (num_vertices == 0) {
1895  // Or if we don't have any vertices, the minmax is also trivial.
1896  cdata->_min_vertex = 0;
1897  cdata->_max_vertex = 0;
1898  cdata->_mins.clear();
1899  cdata->_maxs.clear();
1900 
1901  } else if (get_num_vertices_per_primitive() == 0) {
1902  // This is a complex primitive type like a triangle strip; compute the
1903  // minmax of each primitive (as well as the overall minmax).
1904  GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
1905 
1906  cdata->_mins = make_index_data();
1907  cdata->_maxs = make_index_data();
1908 
1909  GeomVertexArrayData *mins_data = cdata->_mins.get_write_pointer();
1910  GeomVertexArrayData *maxs_data = cdata->_maxs.get_write_pointer();
1911 
1912  mins_data->unclean_set_num_rows(cdata->_ends.size());
1913  maxs_data->unclean_set_num_rows(cdata->_ends.size());
1914 
1915  GeomVertexWriter mins(mins_data, 0);
1916  GeomVertexWriter maxs(maxs_data, 0);
1917 
1918  int pi = 0;
1919 
1920  unsigned int vertex = index.get_data1i();
1921  cdata->_min_vertex = vertex;
1922  cdata->_max_vertex = vertex;
1923  unsigned int min_prim = vertex;
1924  unsigned int max_prim = vertex;
1925 
1926  int num_unused_vertices = get_num_unused_vertices_per_primitive();
1927 
1928  for (int vi = 1; vi < num_vertices; ++vi) {
1929  nassertv(!index.is_at_end());
1930  nassertv(pi < (int)cdata->_ends.size());
1931 
1932  unsigned int vertex;
1933 
1934  if (vi == cdata->_ends[pi]) {
1935  // Skip unused vertices, since they won't be very relevant and may
1936  // contain a strip-cut index, which would distort the result.
1937  if (num_unused_vertices > 0) {
1938  vi += num_unused_vertices;
1939  index.set_row_unsafe(vi);
1940  }
1941  vertex = index.get_data1i();
1942 
1943  mins.set_data1i(min_prim);
1944  maxs.set_data1i(max_prim);
1945  min_prim = vertex;
1946  max_prim = vertex;
1947  ++pi;
1948 
1949  } else {
1950  vertex = index.get_data1i();
1951  min_prim = min(min_prim, vertex);
1952  max_prim = max(max_prim, vertex);
1953  }
1954 
1955  cdata->_min_vertex = min(cdata->_min_vertex, vertex);
1956  cdata->_max_vertex = max(cdata->_max_vertex, vertex);
1957  }
1958 
1959  mins.set_data1i(min_prim);
1960  maxs.set_data1i(max_prim);
1961  nassertv(mins.get_array_data()->get_num_rows() == (int)cdata->_ends.size());
1962 
1963  } else {
1964  // This is a simple primitive type like a triangle; just compute the
1965  // overall minmax.
1966  GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
1967 
1968  cdata->_mins.clear();
1969  cdata->_maxs.clear();
1970 
1971  unsigned int vertex = index.get_data1i();
1972  cdata->_min_vertex = vertex;
1973  cdata->_max_vertex = vertex;
1974 
1975  for (int vi = 1; vi < num_vertices; ++vi) {
1976  nassertv(!index.is_at_end());
1977  unsigned int vertex = index.get_data1i();
1978  cdata->_min_vertex = min(cdata->_min_vertex, vertex);
1979  cdata->_max_vertex = max(cdata->_max_vertex, vertex);
1980  }
1981  }
1982  }
1983 
1984  cdata->_got_minmax = true;
1985 }
1986 
1987 /**
1988  * The private implementation of make_indexed().
1989  */
1990 void GeomPrimitive::
1991 do_make_indexed(CData *cdata) {
1992  if (cdata->_vertices.is_null()) {
1993  if (gobj_cat.is_debug()) {
1994  gobj_cat.debug()
1995  << this << ".make_indexed()\n";
1996  }
1997 
1998  nassertv(cdata->_num_vertices != -1);
1999  cdata->_vertices = make_index_data();
2000 
2001  GeomVertexArrayData *array_data = cdata->_vertices.get_write_pointer();
2002  array_data->unclean_set_num_rows(cdata->_num_vertices);
2003  GeomVertexWriter index(array_data, 0);
2004 
2005  for (int i = 0; i < cdata->_num_vertices; ++i) {
2006  index.set_data1i(i + cdata->_first_vertex);
2007  }
2008  cdata->_num_vertices = -1;
2009  }
2010 }
2011 
2012 /**
2013  * If the indicated new vertex index won't fit in the specified index type,
2014  * automatically elevates the index type to the next available size.
2015  */
2016 void GeomPrimitive::
2017 consider_elevate_index_type(CData *cdata, int vertex) {
2018  // Note that we reserve the highest possible index of a particular index
2019  // type (ie. -1) because this is commonly used as a strip-cut (also known
2020  // as primitive restart) index.
2021  switch (cdata->_index_type) {
2022  case NT_uint8:
2023  if (vertex >= 0xff) {
2024  do_set_index_type(cdata, NT_uint16);
2025  }
2026  break;
2027 
2028  case NT_uint16:
2029  if (vertex >= 0xffff) {
2030  do_set_index_type(cdata, NT_uint32);
2031  }
2032  break;
2033 
2034  case NT_uint32:
2035  // Not much we can do here.
2036  nassertv(vertex < 0x7fffffff);
2037  break;
2038 
2039  default:
2040  break;
2041  }
2042 }
2043 
2044 /**
2045  * The private implementation of set_index_type().
2046  */
2047 void GeomPrimitive::
2048 do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
2049  int old_strip_cut_index = get_strip_cut_index(cdata->_index_type);
2050  int new_strip_cut_index = get_strip_cut_index(index_type);
2051 
2052  cdata->_index_type = index_type;
2053 
2054  if (gobj_cat.is_debug()) {
2055  gobj_cat.debug()
2056  << this << ".set_index_type(" << index_type << ")\n";
2057  }
2058 
2059  if (!cdata->_vertices.is_null()) {
2060  CPT(GeomVertexArrayFormat) new_format = get_index_format();
2061 
2062  CPT(GeomVertexArrayData) array_obj = cdata->_vertices.get_read_pointer();
2063  if (array_obj->get_array_format() != new_format) {
2064  PT(GeomVertexArrayData) new_vertices = make_index_data();
2065  new_vertices->set_num_rows(array_obj->get_num_rows());
2066 
2067  GeomVertexReader from(array_obj, 0);
2068  GeomVertexWriter to(new_vertices, 0);
2069 
2070  while (!from.is_at_end()) {
2071  int index = from.get_data1i();
2072  if (index == old_strip_cut_index) {
2073  index = new_strip_cut_index;
2074  }
2075  to.set_data1i(index);
2076  }
2077  cdata->_vertices = new_vertices;
2078  cdata->_got_minmax = false;
2079  }
2080  }
2081 }
2082 
2083 /**
2084  * The private implementation of modify_vertices().
2085  */
2086 PT(GeomVertexArrayData) GeomPrimitive::
2087 do_modify_vertices(GeomPrimitive::CData *cdata) {
2088  if (cdata->_vertices.is_null()) {
2089  do_make_indexed(cdata);
2090  }
2091 
2092  PT(GeomVertexArrayData) vertices = cdata->_vertices.get_write_pointer();
2093 
2094  cdata->_modified = Geom::get_next_modified();
2095  cdata->_got_minmax = false;
2096  return vertices;
2097 }
2098 
2099 /**
2100  * Writes the contents of this object to the datagram for shipping out to a
2101  * Bam file.
2102  */
2104 write_datagram(BamWriter *manager, Datagram &dg) {
2105  TypedWritable::write_datagram(manager, dg);
2106 
2107  manager->write_cdata(dg, _cycler);
2108 }
2109 
2110 /**
2111  * Called by the BamReader to perform any final actions needed for setting up
2112  * the object after all objects have been read and all pointers have been
2113  * completed.
2114  */
2116 finalize(BamReader *manager) {
2117  const GeomVertexArrayData *vertices = get_vertices();
2118  if (vertices != nullptr) {
2119  set_usage_hint(vertices->get_usage_hint());
2120  }
2121 }
2122 
2123 /**
2124  * This internal function is called by make_from_bam to read in all of the
2125  * relevant data from the BamFile for the new GeomPrimitive.
2126  */
2127 void GeomPrimitive::
2128 fillin(DatagramIterator &scan, BamReader *manager) {
2129  TypedWritable::fillin(scan, manager);
2130 
2131  manager->read_cdata(scan, _cycler);
2132  manager->register_finalize(this);
2133 }
2134 
2135 /**
2136  *
2137  */
2138 CycleData *GeomPrimitive::CData::
2139 make_copy() const {
2140  return new CData(*this);
2141 }
2142 
2143 /**
2144  * Writes the contents of this object to the datagram for shipping out to a
2145  * Bam file.
2146  */
2147 void GeomPrimitive::CData::
2148 write_datagram(BamWriter *manager, Datagram &dg) const {
2149  dg.add_uint8(_shade_model);
2150  dg.add_int32(_first_vertex);
2151  dg.add_int32(_num_vertices);
2152  dg.add_uint8(_index_type);
2153  dg.add_uint8(_usage_hint);
2154 
2155  manager->write_pointer(dg, _vertices.get_read_pointer());
2156  WRITE_PTA(manager, dg, IPD_int::write_datagram, _ends);
2157 }
2158 
2159 /**
2160  * Receives an array of pointers, one for each time manager->read_pointer()
2161  * was called in fillin(). Returns the number of pointers processed.
2162  */
2163 int GeomPrimitive::CData::
2164 complete_pointers(TypedWritable **p_list, BamReader *manager) {
2165  int pi = CycleData::complete_pointers(p_list, manager);
2166 
2167  _vertices = DCAST(GeomVertexArrayData, p_list[pi++]);
2168 
2169  if (manager->get_file_minor_ver() < 6 && !_vertices.is_null()) {
2170  // Older bam files might have a meaningless number in _num_vertices if the
2171  // primitive is indexed. Nowadays, this number is always considered
2172  // meaningful unless it is -1.
2173  _num_vertices = -1;
2174  }
2175 
2176  return pi;
2177 }
2178 
2179 /**
2180  * This internal function is called by make_from_bam to read in all of the
2181  * relevant data from the BamFile for the new GeomPrimitive.
2182  */
2183 void GeomPrimitive::CData::
2184 fillin(DatagramIterator &scan, BamReader *manager) {
2185  _shade_model = (ShadeModel)scan.get_uint8();
2186  _first_vertex = scan.get_int32();
2187  _num_vertices = scan.get_int32();
2188  _index_type = (NumericType)scan.get_uint8();
2189  _usage_hint = (UsageHint)scan.get_uint8();
2190 
2191  manager->read_pointer(scan);
2192  READ_PTA(manager, scan, IPD_int::read_datagram, _ends);
2193 
2194  _modified = Geom::get_next_modified();
2195  _got_minmax = false;
2196 }
2197 
2198 /**
2199  * Ensures that the primitive's minmax cache has been computed.
2200  */
2202 check_minmax() const {
2203  if (!_cdata->_got_minmax) {
2204  // We'll need to get a fresh pointer, since another thread might already
2205  // have modified the pointer on the object since we queried it.
2206  {
2207 #ifdef DO_PIPELINING
2208  unref_delete((CycleData *)_cdata);
2209 #endif
2210  GeomPrimitive::CDWriter fresh_cdata(((GeomPrimitive *)_object.p())->_cycler,
2211  false, _current_thread);
2212  ((GeomPrimitivePipelineReader *)this)->_cdata = fresh_cdata;
2213 #ifdef DO_PIPELINING
2214  _cdata->ref();
2215 #endif
2216 
2217  if (!fresh_cdata->_got_minmax) {
2218  // The cache is still stale. We have to do the work of freshening it.
2219  ((GeomPrimitive *)_object.p())->recompute_minmax(fresh_cdata);
2220  nassertv(fresh_cdata->_got_minmax);
2221  }
2222 
2223  // When fresh_cdata goes out of scope, its write lock is released, and
2224  // _cdata reverts to our usual convention of an unlocked copy of the
2225  // data.
2226  }
2227  }
2228 
2229  nassertv(_cdata->_got_minmax);
2230 }
2231 
2232 /**
2233  *
2234  */
2235 int GeomPrimitivePipelineReader::
2236 get_first_vertex() const {
2237  if (_vertices.is_null()) {
2238  return _cdata->_first_vertex;
2239  }
2240 
2241  size_t size = _vertices_cdata->_buffer.get_size();
2242  if (size == 0) {
2243  return 0;
2244  }
2245 
2246  GeomVertexReader index(_vertices, 0);
2247  return index.get_data1i();
2248 }
2249 
2250 /**
2251  * Returns the ith vertex index in the table.
2252  */
2254 get_vertex(int i) const {
2255  if (!_vertices.is_null()) {
2256  // The indexed case.
2257  nassertr(i >= 0 && i < get_num_vertices(), -1);
2258 
2259  const unsigned char *ptr = get_read_pointer(true);
2260  switch (_cdata->_index_type) {
2261  case GeomEnums::NT_uint8:
2262  return ((uint8_t *)ptr)[i];
2263  break;
2264  case GeomEnums::NT_uint16:
2265  return ((uint16_t *)ptr)[i];
2266  break;
2267  case GeomEnums::NT_uint32:
2268  return ((uint32_t *)ptr)[i];
2269  break;
2270  default:
2271  nassert_raise("unsupported index type");
2272  return -1;
2273  }
2274 
2275  } else {
2276  // The nonindexed case.
2277  return _cdata->_first_vertex + i;
2278  }
2279 }
2280 
2281 /**
2282  *
2283  */
2284 int GeomPrimitivePipelineReader::
2285 get_num_primitives() const {
2286  int num_vertices_per_primitive = _object->get_num_vertices_per_primitive();
2287 
2288  if (num_vertices_per_primitive == 0) {
2289  // This is a complex primitive type like a triangle strip: each primitive
2290  // uses a different number of vertices.
2291  return _cdata->_ends.size();
2292 
2293  } else {
2294  // This is a simple primitive type like a triangle: each primitive uses
2295  // the same number of vertices.
2296  return (get_num_vertices() / num_vertices_per_primitive);
2297  }
2298 }
2299 
2300 /**
2301  * Turns on all the bits corresponding to the vertices that are referenced
2302  * by this GeomPrimitive.
2303  */
2305 get_referenced_vertices(BitArray &bits) const {
2306  int num_vertices = get_num_vertices();
2307 
2308  if (is_indexed()) {
2309  int strip_cut_index = get_strip_cut_index();
2310  const unsigned char *ptr = get_read_pointer(true);
2311  switch (get_index_type()) {
2312  case GeomEnums::NT_uint8:
2313  for (int vi = 0; vi < num_vertices; ++vi) {
2314  int index = ((const uint8_t *)ptr)[vi];
2315  if (index != strip_cut_index) {
2316  bits.set_bit(index);
2317  }
2318  }
2319  break;
2320  case GeomEnums::NT_uint16:
2321  for (int vi = 0; vi < num_vertices; ++vi) {
2322  int index = ((const uint16_t *)ptr)[vi];
2323  if (index != strip_cut_index) {
2324  bits.set_bit(index);
2325  }
2326  }
2327  break;
2328  case GeomEnums::NT_uint32:
2329  for (int vi = 0; vi < num_vertices; ++vi) {
2330  int index = ((const uint32_t *)ptr)[vi];
2331  if (index != strip_cut_index) {
2332  bits.set_bit(index);
2333  }
2334  }
2335  break;
2336  default:
2337  nassert_raise("unsupported index type");
2338  break;
2339  }
2340  } else {
2341  // Nonindexed case.
2342  bits.set_range(get_first_vertex(), num_vertices);
2343  }
2344 }
2345 
2346 /**
2347  *
2348  */
2349 bool GeomPrimitivePipelineReader::
2350 check_valid(const GeomVertexDataPipelineReader *data_reader) const {
2351  if (get_num_vertices() != 0 &&
2352  data_reader->get_num_arrays() > 0 &&
2353  get_max_vertex() >= data_reader->get_num_rows()) {
2354 
2355 #ifndef NDEBUG
2356  gobj_cat.error()
2357  << get_object()->get_type() << " references vertices up to "
2358  << get_max_vertex() << ", but GeomVertexData has only "
2359  << data_reader->get_num_rows() << " rows!\n";
2360 #endif
2361  return false;
2362  }
2363 
2364  return true;
2365 }
geomVertexData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomPrimitive::set_vertices
void set_vertices(const GeomVertexArrayData *vertices, int num_vertices=-1)
Completely replaces the vertex index list with a new table.
Definition: geomPrimitive.cxx:1188
GeomPrimitivePipelineReader::check_minmax
void check_minmax() const
Ensures that the primitive's minmax cache has been computed.
Definition: geomPrimitive.cxx:2202
indent
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
PreparedGraphicsObjects
A table of objects that are saved within the graphics context for reference by handle later.
Definition: preparedGraphicsObjects.h:58
GeomPrimitive::add_next_vertices
void add_next_vertices(int num_vertices)
Adds the next n vertices in sequence, beginning from the last vertex added to the primitive + 1.
Definition: geomPrimitive.cxx:308
GeomPrimitive::get_num_used_vertices
int get_num_used_vertices() const
Returns the number of vertices used by all of the primitives.
Definition: geomPrimitive.cxx:722
GeomVertexArrayData
This is the data for one array of a GeomVertexData structure.
Definition: geomVertexArrayData.h:58
GeomPrimitive::clear_minmax
void clear_minmax()
Undoes a previous call to set_minmax(), and allows the minimum and maximum values to be recomputed no...
Definition: geomPrimitive.cxx:1321
Geom::make_copy
virtual Geom * make_copy() const
Returns a newly-allocated Geom that is a shallow copy of this one.
Definition: geom.cxx:100
CycleData
A single page of data maintained by a PipelineCycler.
Definition: cycleData.h:50
DatagramIterator::get_int32
int32_t get_int32()
Extracts a signed 32-bit integer.
Definition: datagramIterator.I:107
geomVertexWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
internalName.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomPrimitive::modify_ends
PTA_int modify_ends()
Returns a modifiable pointer to the primitive ends array, so application code can directly fiddle wit...
Definition: geomPrimitive.cxx:1245
Geom::get_primitive_type
get_primitive_type
Returns the fundamental primitive type that is common to all GeomPrimitives added within the Geom.
Definition: geom.h:74
PreparedGraphicsObjects::is_index_buffer_queued
bool is_index_buffer_queued(const GeomPrimitive *data) const
Returns true if the index buffer has been queued on this GSG, false otherwise.
Definition: preparedGraphicsObjects.cxx:1097
GeomPrimitive::set_index_type
void set_index_type(NumericType index_type)
Changes the numeric type of the index column.
Definition: geomPrimitive.cxx:142
GeomPrimitive::get_num_vertices_per_primitive
get_num_vertices_per_primitive
If the primitive type is a simple type in which all primitives have the same number of vertices,...
Definition: geomPrimitive.h:194
BitArray::get_num_on_bits
int get_num_on_bits() const
Returns the number of bits that are set to 1 in the array.
Definition: bitArray.cxx:296
GeomPrimitive::operator=
void operator=(const GeomPrimitive &copy)
The copy assignment operator is not pipeline-safe.
Definition: geomPrimitive.cxx:86
GeomVertexReader::get_data1i
int get_data1i()
Returns the data associated with the read row, expressed as a 1-component value, and advances the rea...
Definition: geomVertexReader.I:631
GeomVertexRewriter
This object provides the functionality of both a GeomVertexReader and a GeomVertexWriter,...
Definition: geomVertexRewriter.h:33
GeomVertexData
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
Definition: geomVertexData.h:68
GeomPrimitive::get_primitive_max_vertex
int get_primitive_max_vertex(int n) const
Returns the maximum vertex index number used by the nth primitive in this object.
Definition: geomPrimitive.cxx:756
GeomVertexArrayFormat::get_column
get_column
Returns the specification with the indicated name, or NULL if the name is not used.
Definition: geomVertexArrayFormat.h:106
BitArray::get_lowest_on_bit
int get_lowest_on_bit() const
Returns the index of the lowest 1 bit in the array.
Definition: bitArray.cxx:332
GeomPrimitive::release_all
int release_all()
Frees the context allocated on all objects for which the data has been declared.
Definition: geomPrimitive.cxx:1451
GeomVertexReader::has_column
bool has_column() const
Returns true if a valid data type has been successfully set, or false if the data type does not exist...
Definition: geomVertexReader.I:284
Datagram::add_uint8
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
geomVertexReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pmap< int, int >
IndexBufferContext
This is a special class object that holds all the information returned by a particular GSG to indicat...
Definition: indexBufferContext.h:33
BamReader
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
GeomVertexArrayFormat::get_num_columns
get_num_columns
Returns the number of different columns in the array.
Definition: geomVertexArrayFormat.h:106
preparedGraphicsObjects.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
unref_delete
void unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
Definition: referenceCount.I:344
GeomVertexArrayData::get_array_format
get_array_format
Returns the format object that describes this array.
Definition: geomVertexArrayData.h:76
GeomPrimitive::get_strip_cut_index
get_strip_cut_index
Returns the index of the indicated type that is reserved for use as a strip cut index,...
Definition: geomPrimitive.h:176
GeomPoints
Defines a series of disconnected points.
Definition: geomPoints.h:23
pStatTimer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomPrimitive::get_num_unused_vertices_per_primitive
get_num_unused_vertices_per_primitive
Returns the number of vertices that are added between primitives that aren't, strictly speaking,...
Definition: geomPrimitive.h:196
GeomPrimitive::reserve_num_vertices
void reserve_num_vertices(int num_vertices)
This ensures that enough memory space for n vertices is allocated, so that you may increase the numbe...
Definition: geomPrimitive.cxx:333
GeomPrimitive::get_geom_rendering
get_geom_rendering
Returns the set of GeomRendering bits that represent the rendering properties required to properly re...
Definition: geomPrimitive.h:73
BamWriter
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
GeomVertexWriter
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
Definition: geomVertexWriter.h:55
GeomPrimitive::get_primitive_end
int get_primitive_end(int n) const
Returns the element within the _vertices list at which the nth primitive ends.
Definition: geomPrimitive.cxx:670
BamWriter::write_pointer
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
InternalName
Encodes a string name in a hash table, mapping it to a pointer.
Definition: internalName.h:38
GeomVertexReader
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
Definition: geomVertexReader.h:47
PreparedGraphicsObjects::prepare_index_buffer_now
IndexBufferContext * prepare_index_buffer_now(GeomPrimitive *data, GraphicsStateGuardianBase *gsg)
Immediately creates a new IndexBufferContext for the indicated data and returns it.
Definition: preparedGraphicsObjects.cxx:1250
geomLines.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexRewriter::set_row_unsafe
void set_row_unsafe(int row)
Sets the start row to the indicated value, without internal checks.
Definition: geomVertexRewriter.I:257
geomVertexArrayFormat.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomPrimitive::make_nonindexed
void make_nonindexed(GeomVertexData *dest, const GeomVertexData *source)
Converts the primitive from indexed to nonindexed by duplicating vertices as necessary into the indic...
Definition: geomPrimitive.cxx:542
PreparedGraphicsObjects::enqueue_index_buffer
void enqueue_index_buffer(GeomPrimitive *data)
Indicates that a buffer would like to be put on the list to be prepared when the GSG is next ready to...
Definition: preparedGraphicsObjects.cxx:1086
bamReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomPrimitive::get_vertex
get_vertex
Returns the ith vertex index in the table.
Definition: geomPrimitive.h:99
Geom::get_next_modified
static UpdateSeq get_next_modified()
Returns a monotonically increasing sequence.
Definition: geom.cxx:1324
TypedWritable
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
GeomPrimitive::pack_vertices
void pack_vertices(GeomVertexData *dest, const GeomVertexData *source)
Packs the vertices used by the primitive from the indicated source array onto the end of the indicate...
Definition: geomPrimitive.cxx:574
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
PreparedGraphicsObjects::dequeue_index_buffer
bool dequeue_index_buffer(GeomPrimitive *data)
Removes a buffer from the queued list of data arrays to be prepared.
Definition: preparedGraphicsObjects.cxx:1114
GeomVertexDataPipelineWriter::copy_row_from
void copy_row_from(int dest_row, const GeomVertexDataPipelineReader &source, int source_row)
Copies a single row of the data from the other array into the indicated row of this array.
Definition: geomVertexData.cxx:2594
GeomPrimitive::write_datagram
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: geomPrimitive.cxx:2104
GeomPrimitive::calc_sphere_radius
void calc_sphere_radius(const LPoint3 &center, PN_stdfloat &sq_radius, bool &found_any, const GeomVertexData *vertex_data, Thread *current_thread) const
Expands radius so that a sphere with the given center point fits all of the vertices.
Definition: geomPrimitive.cxx:1761
GeomPrimitive::get_primitive_start
int get_primitive_start(int n) const
Returns the element within the _vertices list at which the nth primitive starts.
Definition: geomPrimitive.cxx:643
ioPtaDatagramInt.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Thread::get_current_thread
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
PStatTimer
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
geomVertexColumn.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomPrimitive::get_index_format
const GeomVertexArrayFormat * get_index_format() const
Returns a registered format appropriate for using to store the index table.
Definition: geomPrimitive.I:389
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
GeomPrimitive::add_vertex
void add_vertex(int vertex)
Adds the indicated vertex to the list of vertex indices used by the graphics primitive type.
Definition: geomPrimitive.cxx:161
GeomVertexReader::is_at_end
bool is_at_end() const
Returns true if the reader is currently at the end of the list of vertices, false otherwise.
Definition: geomVertexReader.I:362
BamReader::register_finalize
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
GeomVertexData::get_num_rows
int get_num_rows() const
Returns the number of rows stored within all the arrays.
Definition: geomVertexData.I:62
GeomPrimitive::prepare_now
IndexBufferContext * prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the data on the particular GSG, if it does not already exist.
Definition: geomPrimitive.cxx:1411
GeomPrimitive::offset_vertices
void offset_vertices(int offset)
Adds the indicated offset to all vertices used by the primitive.
Definition: geomPrimitive.cxx:430
PreparedGraphicsObjects::release_index_buffer
void release_index_buffer(IndexBufferContext *ibc)
Indicates that a data context, created by a previous call to prepare_index_buffer(),...
Definition: preparedGraphicsObjects.cxx:1144
GeomVertexRewriter::is_at_end
bool is_at_end() const
Returns true if the reader or writer is currently at the end of the list of vertices,...
Definition: geomVertexRewriter.I:291
BamReader::read_cdata
void read_cdata(DatagramIterator &scan, PipelineCyclerBase &cycler)
Reads in the indicated CycleData object.
Definition: bamReader.cxx:695
CycleDataWriter
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
Definition: cycleDataWriter.h:34
GeomPrimitivePipelineReader::get_vertex
int get_vertex(int i) const
Returns the ith vertex index in the table.
Definition: geomPrimitive.cxx:2254
GeomPrimitive::get_num_vertices
get_num_vertices
Returns the number of indices used by all the primitives in this object.
Definition: geomPrimitive.h:99
BitArray::get_next_higher_different_bit
int get_next_higher_different_bit(int low_bit) const
Returns the index of the next bit in the array, above low_bit, whose value is different that the valu...
Definition: bitArray.cxx:413
GeomPrimitive::get_primitive_min_vertex
int get_primitive_min_vertex(int n) const
Returns the minimum vertex index number used by the nth primitive in this object.
Definition: geomPrimitive.cxx:738
TypedWritable::write_datagram
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: typedWritable.cxx:54
GeomPrimitive::get_num_primitives
int get_num_primitives() const
Returns the number of individual primitives stored within this object.
Definition: geomPrimitive.I:126
CycleDataReader
This template class calls PipelineCycler::read_unlocked(), and then provides a transparent read-only ...
Definition: cycleDataReader.h:35
GeomPrimitive::release
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the data context only on the indicated object, if it exists there.
Definition: geomPrimitive.cxx:1433
PStatCollector
A lightweight class that represents a single element that may be timed and/or counted via stats.
Definition: pStatCollector.h:43
CopyOnWriteObject
This base class provides basic reference counting, but also can be used with a CopyOnWritePointer to ...
Definition: copyOnWriteObject.h:41
geomVertexRewriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
geomPrimitive.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomPrimitive::calc_tight_bounds
void calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, PN_stdfloat &sq_center_dist, bool &found_any, const GeomVertexData *vertex_data, bool got_mat, const LMatrix4 &mat, const InternalName *column_name, Thread *current_thread) const
Expands min_point and max_point to include all of the vertices in the Geom, if any (or the data of an...
Definition: geomPrimitive.cxx:1592
geomTriangles.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexData::copy_row_from
void copy_row_from(int dest_row, const GeomVertexData *source, int source_row, Thread *current_thread)
Copies a single row of the data from the other array into the indicated row of this array.
Definition: geomVertexData.cxx:687
GeomVertexWriter::add_data1i
void add_data1i(int data)
Sets the write row to a particular 1-component value, and advances the write row.
Definition: geomVertexWriter.I:1228
GeomPrimitive::clear_vertices
void clear_vertices()
Removes all of the vertices and primitives from the object, so they can be re-added.
Definition: geomPrimitive.cxx:405
geom.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomVertexWriter::set_row_unsafe
void set_row_unsafe(int row)
Sets the start row to the indicated value, without internal checks.
Definition: geomVertexWriter.I:285
GeomPrimitive::get_max_vertex
int get_max_vertex() const
Returns the maximum vertex index number used by all the primitives in this object.
Definition: geomPrimitive.I:192
GeomPrimitive::get_shade_model
get_shade_model
Returns the ShadeModel hint for this primitive.
Definition: geomPrimitive.h:77
GeomVertexArrayDataHandle
This data object is returned by GeomVertexArrayData::get_handle() or modify_handle().
Definition: geomVertexArrayData.h:250
GeomVertexReader::get_data3
const LVecBase3 & get_data3()
Returns the data associated with the read row, expressed as a 3-component value, and advances the rea...
Definition: geomVertexReader.I:577
GeomPrimitive::set_minmax
void set_minmax(int min_vertex, int max_vertex, GeomVertexArrayData *mins, GeomVertexArrayData *maxs)
Explicitly specifies the minimum and maximum vertices, as well as the lists of per-component min and ...
Definition: geomPrimitive.cxx:1300
BamWriter::write_cdata
void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler)
Writes out the indicated CycleData object.
Definition: bamWriter.cxx:425
geomPatches.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomPrimitive::set_usage_hint
void set_usage_hint(UsageHint usage_hint)
Changes the UsageHint hint for this primitive.
Definition: geomPrimitive.cxx:119
Datagram::add_int32
void add_int32(int32_t value)
Adds a signed 32-bit integer to the datagram.
Definition: datagram.I:67
GeomVertexReader::set_row
void set_row(int row)
Sets the start row to the indicated value.
Definition: geomVertexReader.I:330
BitArray::get_bit
bool get_bit(int index) const
Returns true if the nth bit is set, false if it is cleared.
Definition: bitArray.I:99
GeomVertexArrayData::get_usage_hint
get_usage_hint
Returns the usage hint that describes to the rendering backend how often the vertex data will be modi...
Definition: geomVertexArrayData.h:80
GeomPrimitive::add_consecutive_vertices
void add_consecutive_vertices(int start, int num_vertices)
Adds a consecutive sequence of vertices, beginning at start, to the primitive.
Definition: geomPrimitive.cxx:241
GeomLines
Defines a series of disconnected line segments.
Definition: geomLines.h:23
GeomVertexWriter::set_data1i
void set_data1i(int data)
Sets the write row to a particular 1-component value, and advances the write row.
Definition: geomVertexWriter.I:730
GeomPrimitive::is_composite
bool is_composite() const
Returns true if the primitive is a composite primitive such as a tristrip or trifan,...
Definition: geomPrimitive.I:74
BamReader::read_pointer
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
BitArray::set_bit
void set_bit(int index)
Sets the nth bit on.
Definition: bitArray.I:115
GeomPrimitive::set_ends
void set_ends(PTA_int ends)
Completely replaces the primitive ends array with a new table.
Definition: geomPrimitive.cxx:1276
GeomPrimitive::close_primitive
bool close_primitive()
Indicates that the previous n calls to add_vertex(), since the last call to close_primitive(),...
Definition: geomPrimitive.cxx:355
GraphicsStateGuardianBase
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
Definition: graphicsStateGuardianBase.h:110
geomPoints.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
CPT
CPT(GeomPrimitive) GeomPrimitive
Decomposes a complex primitive type into a simpler primitive type, for instance triangle strips to tr...
Definition: geomPrimitive.cxx:779
GeomPrimitive::set_nonindexed_vertices
void set_nonindexed_vertices(int first_vertex, int num_vertices)
Sets the primitive up as a nonindexed primitive, using the indicated vertex range.
Definition: geomPrimitive.cxx:1214
GeomVertexReader::set_row_unsafe
void set_row_unsafe(int row)
Sets the start row to the indicated value, without internal checks.
Definition: geomVertexReader.I:316
GeomPrimitive::get_min_num_vertices_per_primitive
get_min_num_vertices_per_primitive
Returns the minimum number of vertices that must be added before close_primitive() may legally be cal...
Definition: geomPrimitive.h:195
BamReader::get_file_minor_ver
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
GeomPrimitive::prepare
void prepare(PreparedGraphicsObjects *prepared_objects)
Indicates that the data should be enqueued to be prepared in the indicated prepared_objects at the be...
Definition: geomPrimitive.cxx:1379
indent.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GeomPrimitivePipelineReader
Encapsulates the data from a GeomPrimitive, pre-fetched for one stage of the pipeline.
Definition: geomPrimitive.h:352
GeomPrimitivePipelineReader::get_referenced_vertices
void get_referenced_vertices(BitArray &bits) const
Turns on all the bits corresponding to the vertices that are referenced by this GeomPrimitive.
Definition: geomPrimitive.cxx:2305
DatagramIterator::get_uint8
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
Definition: datagramIterator.I:72
TypedWritable::fillin
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...
Definition: typedWritable.cxx:103
GeomPrimitive::is_indexed
bool is_indexed() const
Returns true if the primitive is indexed, false otherwise.
Definition: geomPrimitive.I:86
bamWriter.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT
PT(CopyOnWriteObject) GeomPrimitive
Required to implement CopyOnWriteObject.
Definition: geomPrimitive.cxx:56
GeomPrimitive::is_prepared
bool is_prepared(PreparedGraphicsObjects *prepared_objects) const
Returns true if the data has already been prepared or enqueued for preparation on the indicated GSG,...
Definition: geomPrimitive.cxx:1390
GeomPrimitive::finalize
virtual void finalize(BamReader *manager)
Called by the BamReader to perform any final actions needed for setting up the object after all objec...
Definition: geomPrimitive.cxx:2116
TypedObject::is_exact_type
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:38
Thread
A thread; that is, a lightweight process.
Definition: thread.h:46
GeomVertexArrayData::unclean_set_num_rows
bool unclean_set_num_rows(int n)
This method behaves like set_num_rows(), except the new data is not initialized.
Definition: geomVertexArrayData.I:84
GeomPrimitive::get_usage_hint
get_usage_hint
Returns the usage hint for this primitive.
Definition: geomPrimitive.h:81
CycleData::complete_pointers
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
GeomVertexDataPipelineWriter
Encapsulates the data from a GeomVertexData, pre-fetched for one stage of the pipeline.
Definition: geomVertexData.h:508
GeomPrimitive::make_indexed
void make_indexed()
Converts the primitive from nonindexed form to indexed form.
Definition: geomPrimitive.cxx:627
BitArray::set_range
void set_range(int low_bit, int size)
Sets the indicated range of bits on.
Definition: bitArray.cxx:195
GeomVertexArrayFormat
This describes the structure of a single array within a Geom data.
Definition: geomVertexArrayFormat.h:47
BitArray
A dynamic array with an unlimited number of bits.
Definition: bitArray.h:40
GeomVertexArrayDataHandle::get_write_pointer
unsigned char * get_write_pointer()
Returns a writable pointer to the beginning of the actual data stream.
Definition: geomVertexArrayData.cxx:605
GeomPrimitive
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
GeomVertexDataPipelineReader
Encapsulates the data from a GeomVertexData, pre-fetched for one stage of the pipeline.
Definition: geomVertexData.h:442
GeomPrimitive::get_primitive_num_vertices
int get_primitive_num_vertices(int n) const
Returns the number of vertices used by the nth primitive.
Definition: geomPrimitive.cxx:693
GeomPatches
Defines a series of "patches", fixed-size groupings of vertices that must be processed by a tessellat...
Definition: geomPatches.h:24