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  LPoint3 vertex = mat.xform_point_general(reader.get_data3());
1631 
1632  min_point.set(min(min_point[0], vertex[0]),
1633  min(min_point[1], vertex[1]),
1634  min(min_point[2], vertex[2]));
1635  max_point.set(max(max_point[0], vertex[0]),
1636  max(max_point[1], vertex[1]),
1637  max(max_point[2], vertex[2]));
1638  sq_center_dist = max(sq_center_dist, vertex.length_squared());
1639  }
1640  } else {
1641  // Find the first non-NaN vertex.
1642  while (!found_any && i < cdata->_num_vertices) {
1643  reader.set_row(cdata->_first_vertex + i);
1644  LPoint3 first_vertex = reader.get_data3();
1645  if (!first_vertex.is_nan()) {
1646  min_point = first_vertex;
1647  max_point = first_vertex;
1648  sq_center_dist = first_vertex.length_squared();
1649  found_any = true;
1650  }
1651  ++i;
1652  }
1653 
1654  for (; i < cdata->_num_vertices; ++i) {
1655  reader.set_row_unsafe(cdata->_first_vertex + i);
1656  const LVecBase3 &vertex = reader.get_data3();
1657 
1658  min_point.set(min(min_point[0], vertex[0]),
1659  min(min_point[1], vertex[1]),
1660  min(min_point[2], vertex[2]));
1661  max_point.set(max(max_point[0], vertex[0]),
1662  max(max_point[1], vertex[1]),
1663  max(max_point[2], vertex[2]));
1664  sq_center_dist = max(sq_center_dist, vertex.length_squared());
1665  }
1666  }
1667 
1668  } else {
1669  // Indexed case.
1670  GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0, current_thread);
1671  if (index.is_at_end()) {
1672  return;
1673  }
1674 
1675  int strip_cut_index = get_strip_cut_index(cdata->_index_type);
1676 
1677  if (got_mat) {
1678  // Find the first non-NaN vertex.
1679  while (!found_any && !index.is_at_end()) {
1680  int ii = index.get_data1i();
1681  if (ii != strip_cut_index) {
1682  reader.set_row(ii);
1683  LPoint3 first_vertex = mat.xform_point_general(reader.get_data3());
1684  if (!first_vertex.is_nan()) {
1685  min_point = first_vertex;
1686  max_point = first_vertex;
1687  sq_center_dist = first_vertex.length_squared();
1688  found_any = true;
1689  }
1690  }
1691  }
1692 
1693  while (!index.is_at_end()) {
1694  int ii = index.get_data1i();
1695  if (ii == strip_cut_index) {
1696  continue;
1697  }
1698  reader.set_row_unsafe(ii);
1699  LPoint3 vertex = mat.xform_point_general(reader.get_data3());
1700 
1701  min_point.set(min(min_point[0], vertex[0]),
1702  min(min_point[1], vertex[1]),
1703  min(min_point[2], vertex[2]));
1704  max_point.set(max(max_point[0], vertex[0]),
1705  max(max_point[1], vertex[1]),
1706  max(max_point[2], vertex[2]));
1707  sq_center_dist = max(sq_center_dist, vertex.length_squared());
1708  }
1709  } else {
1710  // Find the first non-NaN vertex.
1711  while (!found_any && !index.is_at_end()) {
1712  int ii = index.get_data1i();
1713  if (ii != strip_cut_index) {
1714  reader.set_row(ii);
1715  LVecBase3 first_vertex = reader.get_data3();
1716  if (!first_vertex.is_nan()) {
1717  min_point = first_vertex;
1718  max_point = first_vertex;
1719  sq_center_dist = first_vertex.length_squared();
1720  found_any = true;
1721  }
1722  }
1723  }
1724 
1725  while (!index.is_at_end()) {
1726  int ii = index.get_data1i();
1727  if (ii == strip_cut_index) {
1728  continue;
1729  }
1730  reader.set_row_unsafe(ii);
1731  const LVecBase3 &vertex = reader.get_data3();
1732 
1733  min_point.set(min(min_point[0], vertex[0]),
1734  min(min_point[1], vertex[1]),
1735  min(min_point[2], vertex[2]));
1736  max_point.set(max(max_point[0], vertex[0]),
1737  max(max_point[1], vertex[1]),
1738  max(max_point[2], vertex[2]));
1739  sq_center_dist = max(sq_center_dist, vertex.length_squared());
1740  }
1741  }
1742  }
1743 }
1744 
1745 /**
1746  * Expands radius so that a sphere with the given center point fits all of the
1747  * vertices.
1748  *
1749  * The center point is assumed to already have been transformed by the matrix,
1750  * if one is given.
1751  */
1753 calc_sphere_radius(const LPoint3 &center, PN_stdfloat &sq_radius,
1754  bool &found_any, const GeomVertexData *vertex_data,
1755  Thread *current_thread) const {
1756  GeomVertexReader reader(vertex_data, InternalName::get_vertex(), current_thread);
1757  if (!reader.has_column()) {
1758  // No vertex data.
1759  return;
1760  }
1761 
1762  if (!found_any) {
1763  sq_radius = 0.0;
1764  }
1765 
1766  CDReader cdata(_cycler, current_thread);
1767 
1768  if (cdata->_vertices.is_null()) {
1769  // Nonindexed case.
1770  nassertv(cdata->_num_vertices != -1);
1771  if (cdata->_num_vertices == 0) {
1772  return;
1773  }
1774  found_any = true;
1775 
1776  for (int i = 0; i < cdata->_num_vertices; ++i) {
1777  reader.set_row_unsafe(cdata->_first_vertex + i);
1778  const LVecBase3 &vertex = reader.get_data3();
1779 
1780  sq_radius = max(sq_radius, (vertex - center).length_squared());
1781  }
1782 
1783  } else {
1784  // Indexed case.
1785  GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0, current_thread);
1786  if (index.is_at_end()) {
1787  return;
1788  }
1789  found_any = true;
1790 
1791  int strip_cut_index = get_strip_cut_index(cdata->_index_type);
1792 
1793  while (!index.is_at_end()) {
1794  int ii = index.get_data1i();
1795  if (ii == strip_cut_index) {
1796  continue;
1797  }
1798  reader.set_row_unsafe(ii);
1799  const LVecBase3 &vertex = reader.get_data3();
1800 
1801  sq_radius = max(sq_radius, (vertex - center).length_squared());
1802  }
1803  }
1804 }
1805 
1806 /**
1807  * Decomposes a complex primitive type into a simpler primitive type, for
1808  * instance triangle strips to triangles, and returns a pointer to the new
1809  * primitive definition. If the decomposition cannot be performed, this might
1810  * return the original object.
1811  *
1812  * This method is useful for application code that wants to iterate through
1813  * the set of triangles on the primitive without having to write handlers for
1814  * each possible kind of primitive type.
1815  */
1816 CPT(GeomPrimitive) GeomPrimitive::
1817 decompose_impl() const {
1818  return this;
1819 }
1820 
1821 /**
1822  * The virtual implementation of rotate().
1823  */
1824 CPT(GeomVertexArrayData) GeomPrimitive::
1825 rotate_impl() const {
1826  // The default implementation doesn't even try to do anything.
1827  nassertr(false, nullptr);
1828  return nullptr;
1829 }
1830 
1831 /**
1832  * The virtual implementation of doubleside().
1833  */
1834 CPT(GeomPrimitive) GeomPrimitive::
1835 doubleside_impl() const {
1836  return this;
1837 }
1838 
1839 /**
1840  * The virtual implementation of reverse().
1841  */
1842 CPT(GeomPrimitive) GeomPrimitive::
1843 reverse_impl() const {
1844  return this;
1845 }
1846 
1847 /**
1848  * Should be redefined to return true in any primitive that implements
1849  * append_unused_vertices().
1850  */
1851 bool GeomPrimitive::
1852 requires_unused_vertices() const {
1853  return false;
1854 }
1855 
1856 /**
1857  * Called when a new primitive is begun (other than the first primitive), this
1858  * should add some degenerate vertices between primitives, if the primitive
1859  * type requires that. The second parameter is the first vertex that begins
1860  * the new primitive.
1861  *
1862  * This method is only called if requires_unused_vertices(), above, returns
1863  * true.
1864  */
1865 void GeomPrimitive::
1866 append_unused_vertices(GeomVertexArrayData *, int) {
1867 }
1868 
1869 /**
1870  * Recomputes the _min_vertex and _max_vertex values if necessary.
1871  */
1872 void GeomPrimitive::
1873 recompute_minmax(GeomPrimitive::CData *cdata) {
1874  if (cdata->_vertices.is_null()) {
1875  // In the nonindexed case, we don't need to do much (the minmax is
1876  // trivial).
1877  nassertv(cdata->_num_vertices != -1);
1878  cdata->_min_vertex = cdata->_first_vertex;
1879  cdata->_max_vertex = cdata->_first_vertex + cdata->_num_vertices - 1;
1880  cdata->_mins.clear();
1881  cdata->_maxs.clear();
1882 
1883  } else {
1884  int num_vertices = cdata->_vertices.get_read_pointer()->get_num_rows();
1885 
1886  if (num_vertices == 0) {
1887  // Or if we don't have any vertices, the minmax is also trivial.
1888  cdata->_min_vertex = 0;
1889  cdata->_max_vertex = 0;
1890  cdata->_mins.clear();
1891  cdata->_maxs.clear();
1892 
1893  } else if (get_num_vertices_per_primitive() == 0) {
1894  // This is a complex primitive type like a triangle strip; compute the
1895  // minmax of each primitive (as well as the overall minmax).
1896  GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
1897 
1898  cdata->_mins = make_index_data();
1899  cdata->_maxs = make_index_data();
1900 
1901  GeomVertexArrayData *mins_data = cdata->_mins.get_write_pointer();
1902  GeomVertexArrayData *maxs_data = cdata->_maxs.get_write_pointer();
1903 
1904  mins_data->unclean_set_num_rows(cdata->_ends.size());
1905  maxs_data->unclean_set_num_rows(cdata->_ends.size());
1906 
1907  GeomVertexWriter mins(mins_data, 0);
1908  GeomVertexWriter maxs(maxs_data, 0);
1909 
1910  int pi = 0;
1911 
1912  unsigned int vertex = index.get_data1i();
1913  cdata->_min_vertex = vertex;
1914  cdata->_max_vertex = vertex;
1915  unsigned int min_prim = vertex;
1916  unsigned int max_prim = vertex;
1917 
1918  int num_unused_vertices = get_num_unused_vertices_per_primitive();
1919 
1920  for (int vi = 1; vi < num_vertices; ++vi) {
1921  nassertv(!index.is_at_end());
1922  nassertv(pi < (int)cdata->_ends.size());
1923 
1924  unsigned int vertex;
1925 
1926  if (vi == cdata->_ends[pi]) {
1927  // Skip unused vertices, since they won't be very relevant and may
1928  // contain a strip-cut index, which would distort the result.
1929  if (num_unused_vertices > 0) {
1930  vi += num_unused_vertices;
1931  index.set_row_unsafe(vi);
1932  }
1933  vertex = index.get_data1i();
1934 
1935  mins.set_data1i(min_prim);
1936  maxs.set_data1i(max_prim);
1937  min_prim = vertex;
1938  max_prim = vertex;
1939  ++pi;
1940 
1941  } else {
1942  vertex = index.get_data1i();
1943  min_prim = min(min_prim, vertex);
1944  max_prim = max(max_prim, vertex);
1945  }
1946 
1947  cdata->_min_vertex = min(cdata->_min_vertex, vertex);
1948  cdata->_max_vertex = max(cdata->_max_vertex, vertex);
1949  }
1950 
1951  mins.set_data1i(min_prim);
1952  maxs.set_data1i(max_prim);
1953  nassertv(mins.get_array_data()->get_num_rows() == (int)cdata->_ends.size());
1954 
1955  } else {
1956  // This is a simple primitive type like a triangle; just compute the
1957  // overall minmax.
1958  GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
1959 
1960  cdata->_mins.clear();
1961  cdata->_maxs.clear();
1962 
1963  unsigned int vertex = index.get_data1i();
1964  cdata->_min_vertex = vertex;
1965  cdata->_max_vertex = vertex;
1966 
1967  for (int vi = 1; vi < num_vertices; ++vi) {
1968  nassertv(!index.is_at_end());
1969  unsigned int vertex = index.get_data1i();
1970  cdata->_min_vertex = min(cdata->_min_vertex, vertex);
1971  cdata->_max_vertex = max(cdata->_max_vertex, vertex);
1972  }
1973  }
1974  }
1975 
1976  cdata->_got_minmax = true;
1977 }
1978 
1979 /**
1980  * The private implementation of make_indexed().
1981  */
1982 void GeomPrimitive::
1983 do_make_indexed(CData *cdata) {
1984  if (cdata->_vertices.is_null()) {
1985  if (gobj_cat.is_debug()) {
1986  gobj_cat.debug()
1987  << this << ".make_indexed()\n";
1988  }
1989 
1990  nassertv(cdata->_num_vertices != -1);
1991  cdata->_vertices = make_index_data();
1992 
1993  GeomVertexArrayData *array_data = cdata->_vertices.get_write_pointer();
1994  array_data->unclean_set_num_rows(cdata->_num_vertices);
1995  GeomVertexWriter index(array_data, 0);
1996 
1997  for (int i = 0; i < cdata->_num_vertices; ++i) {
1998  index.set_data1i(i + cdata->_first_vertex);
1999  }
2000  cdata->_num_vertices = -1;
2001  }
2002 }
2003 
2004 /**
2005  * If the indicated new vertex index won't fit in the specified index type,
2006  * automatically elevates the index type to the next available size.
2007  */
2008 void GeomPrimitive::
2009 consider_elevate_index_type(CData *cdata, int vertex) {
2010  // Note that we reserve the highest possible index of a particular index
2011  // type (ie. -1) because this is commonly used as a strip-cut (also known
2012  // as primitive restart) index.
2013  switch (cdata->_index_type) {
2014  case NT_uint8:
2015  if (vertex >= 0xff) {
2016  do_set_index_type(cdata, NT_uint16);
2017  }
2018  break;
2019 
2020  case NT_uint16:
2021  if (vertex >= 0xffff) {
2022  do_set_index_type(cdata, NT_uint32);
2023  }
2024  break;
2025 
2026  case NT_uint32:
2027  // Not much we can do here.
2028  nassertv(vertex < 0x7fffffff);
2029  break;
2030 
2031  default:
2032  break;
2033  }
2034 }
2035 
2036 /**
2037  * The private implementation of set_index_type().
2038  */
2039 void GeomPrimitive::
2040 do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
2041  int old_strip_cut_index = get_strip_cut_index(cdata->_index_type);
2042  int new_strip_cut_index = get_strip_cut_index(index_type);
2043 
2044  cdata->_index_type = index_type;
2045 
2046  if (gobj_cat.is_debug()) {
2047  gobj_cat.debug()
2048  << this << ".set_index_type(" << index_type << ")\n";
2049  }
2050 
2051  if (!cdata->_vertices.is_null()) {
2052  CPT(GeomVertexArrayFormat) new_format = get_index_format();
2053 
2054  CPT(GeomVertexArrayData) array_obj = cdata->_vertices.get_read_pointer();
2055  if (array_obj->get_array_format() != new_format) {
2056  PT(GeomVertexArrayData) new_vertices = make_index_data();
2057  new_vertices->set_num_rows(array_obj->get_num_rows());
2058 
2059  GeomVertexReader from(array_obj, 0);
2060  GeomVertexWriter to(new_vertices, 0);
2061 
2062  while (!from.is_at_end()) {
2063  int index = from.get_data1i();
2064  if (index == old_strip_cut_index) {
2065  index = new_strip_cut_index;
2066  }
2067  to.set_data1i(index);
2068  }
2069  cdata->_vertices = new_vertices;
2070  cdata->_got_minmax = false;
2071  }
2072  }
2073 }
2074 
2075 /**
2076  * The private implementation of modify_vertices().
2077  */
2078 PT(GeomVertexArrayData) GeomPrimitive::
2079 do_modify_vertices(GeomPrimitive::CData *cdata) {
2080  if (cdata->_vertices.is_null()) {
2081  do_make_indexed(cdata);
2082  }
2083 
2084  PT(GeomVertexArrayData) vertices = cdata->_vertices.get_write_pointer();
2085 
2086  cdata->_modified = Geom::get_next_modified();
2087  cdata->_got_minmax = false;
2088  return vertices;
2089 }
2090 
2091 /**
2092  * Writes the contents of this object to the datagram for shipping out to a
2093  * Bam file.
2094  */
2096 write_datagram(BamWriter *manager, Datagram &dg) {
2097  TypedWritable::write_datagram(manager, dg);
2098 
2099  manager->write_cdata(dg, _cycler);
2100 }
2101 
2102 /**
2103  * Called by the BamReader to perform any final actions needed for setting up
2104  * the object after all objects have been read and all pointers have been
2105  * completed.
2106  */
2108 finalize(BamReader *manager) {
2109  const GeomVertexArrayData *vertices = get_vertices();
2110  if (vertices != nullptr) {
2111  set_usage_hint(vertices->get_usage_hint());
2112  }
2113 }
2114 
2115 /**
2116  * This internal function is called by make_from_bam to read in all of the
2117  * relevant data from the BamFile for the new GeomPrimitive.
2118  */
2119 void GeomPrimitive::
2120 fillin(DatagramIterator &scan, BamReader *manager) {
2121  TypedWritable::fillin(scan, manager);
2122 
2123  manager->read_cdata(scan, _cycler);
2124  manager->register_finalize(this);
2125 }
2126 
2127 /**
2128  *
2129  */
2130 CycleData *GeomPrimitive::CData::
2131 make_copy() const {
2132  return new CData(*this);
2133 }
2134 
2135 /**
2136  * Writes the contents of this object to the datagram for shipping out to a
2137  * Bam file.
2138  */
2139 void GeomPrimitive::CData::
2140 write_datagram(BamWriter *manager, Datagram &dg) const {
2141  dg.add_uint8(_shade_model);
2142  dg.add_int32(_first_vertex);
2143  dg.add_int32(_num_vertices);
2144  dg.add_uint8(_index_type);
2145  dg.add_uint8(_usage_hint);
2146 
2147  manager->write_pointer(dg, _vertices.get_read_pointer());
2148  WRITE_PTA(manager, dg, IPD_int::write_datagram, _ends);
2149 }
2150 
2151 /**
2152  * Receives an array of pointers, one for each time manager->read_pointer()
2153  * was called in fillin(). Returns the number of pointers processed.
2154  */
2155 int GeomPrimitive::CData::
2156 complete_pointers(TypedWritable **p_list, BamReader *manager) {
2157  int pi = CycleData::complete_pointers(p_list, manager);
2158 
2159  _vertices = DCAST(GeomVertexArrayData, p_list[pi++]);
2160 
2161  if (manager->get_file_minor_ver() < 6 && !_vertices.is_null()) {
2162  // Older bam files might have a meaningless number in _num_vertices if the
2163  // primitive is indexed. Nowadays, this number is always considered
2164  // meaningful unless it is -1.
2165  _num_vertices = -1;
2166  }
2167 
2168  return pi;
2169 }
2170 
2171 /**
2172  * This internal function is called by make_from_bam to read in all of the
2173  * relevant data from the BamFile for the new GeomPrimitive.
2174  */
2175 void GeomPrimitive::CData::
2176 fillin(DatagramIterator &scan, BamReader *manager) {
2177  _shade_model = (ShadeModel)scan.get_uint8();
2178  _first_vertex = scan.get_int32();
2179  _num_vertices = scan.get_int32();
2180  _index_type = (NumericType)scan.get_uint8();
2181  _usage_hint = (UsageHint)scan.get_uint8();
2182 
2183  manager->read_pointer(scan);
2184  READ_PTA(manager, scan, IPD_int::read_datagram, _ends);
2185 
2186  _modified = Geom::get_next_modified();
2187  _got_minmax = false;
2188 }
2189 
2190 /**
2191  * Ensures that the primitive's minmax cache has been computed.
2192  */
2194 check_minmax() const {
2195  if (!_cdata->_got_minmax) {
2196  // We'll need to get a fresh pointer, since another thread might already
2197  // have modified the pointer on the object since we queried it.
2198  {
2199 #ifdef DO_PIPELINING
2200  unref_delete((CycleData *)_cdata);
2201 #endif
2202  GeomPrimitive::CDWriter fresh_cdata(((GeomPrimitive *)_object.p())->_cycler,
2203  false, _current_thread);
2204  ((GeomPrimitivePipelineReader *)this)->_cdata = fresh_cdata;
2205 #ifdef DO_PIPELINING
2206  _cdata->ref();
2207 #endif
2208 
2209  if (!fresh_cdata->_got_minmax) {
2210  // The cache is still stale. We have to do the work of freshening it.
2211  ((GeomPrimitive *)_object.p())->recompute_minmax(fresh_cdata);
2212  nassertv(fresh_cdata->_got_minmax);
2213  }
2214 
2215  // When fresh_cdata goes out of scope, its write lock is released, and
2216  // _cdata reverts to our usual convention of an unlocked copy of the
2217  // data.
2218  }
2219  }
2220 
2221  nassertv(_cdata->_got_minmax);
2222 }
2223 
2224 /**
2225  *
2226  */
2227 int GeomPrimitivePipelineReader::
2228 get_first_vertex() const {
2229  if (_vertices.is_null()) {
2230  return _cdata->_first_vertex;
2231  }
2232 
2233  size_t size = _vertices_cdata->_buffer.get_size();
2234  if (size == 0) {
2235  return 0;
2236  }
2237 
2238  GeomVertexReader index(_vertices, 0);
2239  return index.get_data1i();
2240 }
2241 
2242 /**
2243  * Returns the ith vertex index in the table.
2244  */
2246 get_vertex(int i) const {
2247  if (!_vertices.is_null()) {
2248  // The indexed case.
2249  nassertr(i >= 0 && i < get_num_vertices(), -1);
2250 
2251  const unsigned char *ptr = get_read_pointer(true);
2252  switch (_cdata->_index_type) {
2253  case GeomEnums::NT_uint8:
2254  return ((uint8_t *)ptr)[i];
2255  break;
2256  case GeomEnums::NT_uint16:
2257  return ((uint16_t *)ptr)[i];
2258  break;
2259  case GeomEnums::NT_uint32:
2260  return ((uint32_t *)ptr)[i];
2261  break;
2262  default:
2263  nassert_raise("unsupported index type");
2264  return -1;
2265  }
2266 
2267  } else {
2268  // The nonindexed case.
2269  return _cdata->_first_vertex + i;
2270  }
2271 }
2272 
2273 /**
2274  *
2275  */
2276 int GeomPrimitivePipelineReader::
2277 get_num_primitives() const {
2278  int num_vertices_per_primitive = _object->get_num_vertices_per_primitive();
2279 
2280  if (num_vertices_per_primitive == 0) {
2281  // This is a complex primitive type like a triangle strip: each primitive
2282  // uses a different number of vertices.
2283  return _cdata->_ends.size();
2284 
2285  } else {
2286  // This is a simple primitive type like a triangle: each primitive uses
2287  // the same number of vertices.
2288  return (get_num_vertices() / num_vertices_per_primitive);
2289  }
2290 }
2291 
2292 /**
2293  * Turns on all the bits corresponding to the vertices that are referenced
2294  * by this GeomPrimitive.
2295  */
2297 get_referenced_vertices(BitArray &bits) const {
2298  int num_vertices = get_num_vertices();
2299 
2300  if (is_indexed()) {
2301  int strip_cut_index = get_strip_cut_index();
2302  const unsigned char *ptr = get_read_pointer(true);
2303  switch (get_index_type()) {
2304  case GeomEnums::NT_uint8:
2305  for (int vi = 0; vi < num_vertices; ++vi) {
2306  int index = ((const uint8_t *)ptr)[vi];
2307  if (index != strip_cut_index) {
2308  bits.set_bit(index);
2309  }
2310  }
2311  break;
2312  case GeomEnums::NT_uint16:
2313  for (int vi = 0; vi < num_vertices; ++vi) {
2314  int index = ((const uint16_t *)ptr)[vi];
2315  if (index != strip_cut_index) {
2316  bits.set_bit(index);
2317  }
2318  }
2319  break;
2320  case GeomEnums::NT_uint32:
2321  for (int vi = 0; vi < num_vertices; ++vi) {
2322  int index = ((const uint32_t *)ptr)[vi];
2323  if (index != strip_cut_index) {
2324  bits.set_bit(index);
2325  }
2326  }
2327  break;
2328  default:
2329  nassert_raise("unsupported index type");
2330  break;
2331  }
2332  } else {
2333  // Nonindexed case.
2334  bits.set_range(get_first_vertex(), num_vertices);
2335  }
2336 }
2337 
2338 /**
2339  *
2340  */
2341 bool GeomPrimitivePipelineReader::
2342 check_valid(const GeomVertexDataPipelineReader *data_reader) const {
2343  if (get_num_vertices() != 0 &&
2344  data_reader->get_num_arrays() > 0 &&
2345  get_max_vertex() >= data_reader->get_num_rows()) {
2346 
2347 #ifndef NDEBUG
2348  gobj_cat.error()
2349  << get_object()->get_type() << " references vertices up to "
2350  << get_max_vertex() << ", but GeomVertexData has only "
2351  << data_reader->get_num_rows() << " rows!\n";
2352 #endif
2353  return false;
2354  }
2355 
2356  return true;
2357 }
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:2194
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:2096
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:1753
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:2246
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:2297
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:2108
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:39
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