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