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  * @since 1.10.0
1043  */
1044 CPT(GeomPrimitive) GeomPrimitive::
1045 make_adjacency() const {
1046  return nullptr;
1047 }
1048 
1049 /**
1050  * Returns the number of bytes consumed by the primitive and its index
1051  * table(s).
1052  */
1053 int GeomPrimitive::
1054 get_num_bytes() const {
1055  CDReader cdata(_cycler);
1056  int num_bytes = cdata->_ends.size() * sizeof(int) + sizeof(GeomPrimitive);
1057  if (!cdata->_vertices.is_null()) {
1058  num_bytes += cdata->_vertices.get_read_pointer()->get_data_size_bytes();
1059  }
1060 
1061  return num_bytes;
1062 }
1063 
1064 /**
1065  * Returns true if the primitive data is currently resident in memory. If
1066  * this returns false, the primitive data will be brought back into memory
1067  * shortly; try again later.
1068  */
1069 bool GeomPrimitive::
1070 request_resident(Thread *current_thread) const {
1071  CDReader cdata(_cycler, current_thread);
1072 
1073  bool resident = true;
1074 
1075  if (!cdata->_vertices.is_null() &&
1076  !cdata->_vertices.get_read_pointer(current_thread)->request_resident(current_thread)) {
1077  resident = false;
1078  }
1079 
1080  if (is_composite() && cdata->_got_minmax) {
1081  if (!cdata->_mins.is_null() &&
1082  !cdata->_mins.get_read_pointer(current_thread)->request_resident(current_thread)) {
1083  resident = false;
1084  }
1085  if (!cdata->_maxs.is_null() &&
1086  !cdata->_maxs.get_read_pointer(current_thread)->request_resident(current_thread)) {
1087  resident = false;
1088  }
1089  }
1090 
1091  return resident;
1092 }
1093 
1094 /**
1095  *
1096  */
1097 void GeomPrimitive::
1098 output(std::ostream &out) const {
1099  out << get_type() << ", " << get_num_primitives()
1100  << ", " << get_num_vertices();
1101 }
1102 
1103 /**
1104  *
1105  */
1106 void GeomPrimitive::
1107 write(std::ostream &out, int indent_level) const {
1108  indent(out, indent_level)
1109  << get_type();
1110  if (is_indexed()) {
1111  out << " (indexed)";
1112  } else {
1113  out << " (nonindexed)";
1114  }
1115  out << ":\n";
1116  int num_primitives = get_num_primitives();
1117  int num_vertices = get_num_vertices();
1118  int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive();
1119  for (int i = 0; i < num_primitives; ++i) {
1120  indent(out, indent_level + 2)
1121  << "[";
1122  int begin = get_primitive_start(i);
1123  int end = get_primitive_end(i);
1124  for (int vi = begin; vi < end; vi++) {
1125  out << " " << get_vertex(vi);
1126  }
1127  out << " ]";
1128  if (end < num_vertices) {
1129  for (int ui = 0; ui < num_unused_vertices_per_primitive; ++ui) {
1130  if (end + ui < num_vertices) {
1131  out << " " << get_vertex(end + ui);
1132  } else {
1133  out << " ?";
1134  }
1135  }
1136  }
1137  out << "\n";
1138  }
1139 }
1140 
1141 /**
1142  * Returns a modifiable pointer to the vertex index list, so application code
1143  * can directly fiddle with this data. Use with caution, since there are no
1144  * checks that the data will be left in a stable state.
1145  *
1146  * If this is called on a nonindexed primitive, it will implicitly be
1147  * converted to an indexed primitive.
1148  *
1149  * If num_vertices is not -1, it specifies an artificial limit to the number
1150  * of vertices in the array. Otherwise, all of the vertices in the array will
1151  * be used.
1152  *
1153  * Don't call this in a downstream thread unless you don't mind it blowing
1154  * away other changes you might have recently made in an upstream thread.
1155  *
1156  * This method is intended for low-level usage only. There are higher-level
1157  * methods for more common usage. We recommend you do not use this method
1158  * directly. If you do, be sure you know what you are doing!
1159  */
1160 PT(GeomVertexArrayData) GeomPrimitive::
1161 modify_vertices(int num_vertices) {
1162  CDWriter cdata(_cycler, true);
1163  PT(GeomVertexArrayData) vertices = do_modify_vertices(cdata);
1164  cdata->_num_vertices = num_vertices;
1165  return vertices;
1166 }
1167 
1168 /**
1169  * Completely replaces the vertex index list with a new table. Chances are
1170  * good that you should also replace the ends list with set_ends() at the same
1171  * time.
1172  *
1173  * If num_vertices is not -1, it specifies an artificial limit to the number
1174  * of vertices in the array. Otherwise, all of the vertices in the array will
1175  * be used.
1176  *
1177  * Don't call this in a downstream thread unless you don't mind it blowing
1178  * away other changes you might have recently made in an upstream thread.
1179  *
1180  * This method is intended for low-level usage only. There are higher-level
1181  * methods for more common usage. We recommend you do not use this method
1182  * directly. If you do, be sure you know what you are doing!
1183  */
1184 void GeomPrimitive::
1185 set_vertices(const GeomVertexArrayData *vertices, int num_vertices) {
1186  CDWriter cdata(_cycler, true);
1187  cdata->_vertices = (GeomVertexArrayData *)vertices;
1188  cdata->_num_vertices = num_vertices;
1189 
1190  // Validate the format and make sure to copy its numeric type.
1191  const GeomVertexArrayFormat *format = vertices->get_array_format();
1192  nassertv(format->get_num_columns() == 1);
1193  cdata->_index_type = format->get_column(0)->get_numeric_type();
1194 
1195  cdata->_modified = Geom::get_next_modified();
1196  cdata->_got_minmax = false;
1197 }
1198 
1199 /**
1200  * Sets the primitive up as a nonindexed primitive, using the indicated vertex
1201  * range.
1202  *
1203  * Don't call this in a downstream thread unless you don't mind it blowing
1204  * away other changes you might have recently made in an upstream thread.
1205  *
1206  * This method is intended for low-level usage only. There are higher-level
1207  * methods for more common usage. We recommend you do not use this method
1208  * directly. If you do, be sure you know what you are doing!
1209  */
1210 void GeomPrimitive::
1211 set_nonindexed_vertices(int first_vertex, int num_vertices) {
1212  nassertv(num_vertices != -1);
1213  CDWriter cdata(_cycler, true);
1214  cdata->_vertices = nullptr;
1215  cdata->_first_vertex = first_vertex;
1216  cdata->_num_vertices = num_vertices;
1217 
1218  cdata->_modified = Geom::get_next_modified();
1219  cdata->_got_minmax = false;
1220 
1221  // Force the minmax to be recomputed.
1222  recompute_minmax(cdata);
1223 }
1224 
1225 /**
1226  * Returns a modifiable pointer to the primitive ends array, so application
1227  * code can directly fiddle with this data. Use with caution, since there are
1228  * no checks that the data will be left in a stable state.
1229  *
1230  * Note that simple primitive types, like triangles, do not have a ends array:
1231  * since all the primitives have the same number of vertices, it is not
1232  * needed.
1233  *
1234  * Don't call this in a downstream thread unless you don't mind it blowing
1235  * away other changes you might have recently made in an upstream thread.
1236  *
1237  * This method is intended for low-level usage only. There are higher-level
1238  * methods for more common usage. We recommend you do not use this method
1239  * directly. If you do, be sure you know what you are doing!
1240  */
1241 PTA_int GeomPrimitive::
1243  CDWriter cdata(_cycler, true);
1244 
1245  cdata->_modified = Geom::get_next_modified();
1246  cdata->_got_minmax = false;
1247 
1248  if (cdata->_ends.get_ref_count() > 1) {
1249  PTA_int new_ends;
1250  new_ends.v() = cdata->_ends.v();
1251  cdata->_ends = new_ends;
1252  }
1253  return cdata->_ends;
1254 }
1255 
1256 /**
1257  * Completely replaces the primitive ends array with a new table. Chances are
1258  * good that you should also replace the vertices list with set_vertices() at
1259  * the same time.
1260  *
1261  * Note that simple primitive types, like triangles, do not have a ends array:
1262  * since all the primitives have the same number of vertices, it is not
1263  * needed.
1264  *
1265  * Don't call this in a downstream thread unless you don't mind it blowing
1266  * away other changes you might have recently made in an upstream thread.
1267  *
1268  * This method is intended for low-level usage only. There are higher-level
1269  * methods for more common usage. We recommend you do not use this method
1270  * directly. If you do, be sure you know what you are doing!
1271  */
1272 void GeomPrimitive::
1273 set_ends(PTA_int ends) {
1274  CDWriter cdata(_cycler, true);
1275  cdata->_ends = ends;
1276 
1277  cdata->_modified = Geom::get_next_modified();
1278  cdata->_got_minmax = false;
1279 }
1280 
1281 /**
1282  * Explicitly specifies the minimum and maximum vertices, as well as the lists
1283  * of per-component min and max.
1284  *
1285  * Use this method with extreme caution. It's generally better to let the
1286  * GeomPrimitive compute these explicitly, unless for some reason you can do
1287  * it faster and you absolutely need the speed improvement.
1288  *
1289  * Note that any modification to the vertex array will normally cause this to
1290  * be recomputed, unless you set it immediately again.
1291  *
1292  * This method is intended for low-level usage only. There are higher-level
1293  * methods for more common usage. We recommend you do not use this method
1294  * directly. If you do, be sure you know what you are doing!
1295  */
1296 void GeomPrimitive::
1297 set_minmax(int min_vertex, int max_vertex,
1299  CDWriter cdata(_cycler, true);
1300  cdata->_min_vertex = min_vertex;
1301  cdata->_max_vertex = max_vertex;
1302  cdata->_mins = mins;
1303  cdata->_maxs = maxs;
1304 
1305  cdata->_modified = Geom::get_next_modified();
1306  cdata->_got_minmax = true;
1307 }
1308 
1309 /**
1310  * Undoes a previous call to set_minmax(), and allows the minimum and maximum
1311  * values to be recomputed normally.
1312  *
1313  * This method is intended for low-level usage only. There are higher-level
1314  * methods for more common usage. We recommend you do not use this method
1315  * directly. If you do, be sure you know what you are doing!
1316  */
1317 void GeomPrimitive::
1319  CDWriter cdata(_cycler, true);
1320  cdata->_got_minmax = false;
1321 }
1322 
1323 /**
1324  * If the primitive type is a simple type in which all primitives have the
1325  * same number of vertices, like triangles, returns the number of vertices per
1326  * primitive. If the primitive type is a more complex type in which different
1327  * primitives might have different numbers of vertices, for instance a
1328  * triangle strip, returns 0.
1329  *
1330  * This method is intended for low-level usage only. There are higher-level
1331  * methods for more common usage. We recommend you do not use this method
1332  * directly. If you do, be sure you know what you are doing!
1333  */
1334 int GeomPrimitive::
1335 get_num_vertices_per_primitive() const {
1336  return 0;
1337 }
1338 
1339 /**
1340  * Returns the minimum number of vertices that must be added before
1341  * close_primitive() may legally be called.
1342  *
1343  * This method is intended for low-level usage only. There are higher-level
1344  * methods for more common usage. We recommend you do not use this method
1345  * directly. If you do, be sure you know what you are doing!
1346  */
1347 int GeomPrimitive::
1348 get_min_num_vertices_per_primitive() const {
1349  return 3;
1350 }
1351 
1352 /**
1353  * Returns the number of vertices that are added between primitives that
1354  * aren't, strictly speaking, part of the primitives themselves. This is
1355  * used, for instance, to define degenerate triangles to connect otherwise
1356  * disconnected triangle strips.
1357  *
1358  * This method is intended for low-level usage only. There are higher-level
1359  * methods for more common usage. We recommend you do not use this method
1360  * directly. If you do, be sure you know what you are doing!
1361  */
1362 int GeomPrimitive::
1363 get_num_unused_vertices_per_primitive() const {
1364  return 0;
1365 }
1366 
1367 /**
1368  * Indicates that the data should be enqueued to be prepared in the indicated
1369  * prepared_objects at the beginning of the next frame. This will ensure the
1370  * data is already loaded into the GSG if it is expected to be rendered soon.
1371  *
1372  * Use this function instead of prepare_now() to preload datas from a user
1373  * interface standpoint.
1374  */
1375 void GeomPrimitive::
1376 prepare(PreparedGraphicsObjects *prepared_objects) {
1377  if (is_indexed()) {
1378  prepared_objects->enqueue_index_buffer(this);
1379  }
1380 }
1381 
1382 /**
1383  * Returns true if the data has already been prepared or enqueued for
1384  * preparation on the indicated GSG, false otherwise.
1385  */
1386 bool GeomPrimitive::
1387 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
1388  Contexts::const_iterator ci;
1389  ci = _contexts.find(prepared_objects);
1390  if (ci != _contexts.end()) {
1391  return true;
1392  }
1393  return prepared_objects->is_index_buffer_queued(this);
1394 }
1395 
1396 /**
1397  * Creates a context for the data on the particular GSG, if it does not
1398  * already exist. Returns the new (or old) IndexBufferContext. This assumes
1399  * that the GraphicsStateGuardian is the currently active rendering context
1400  * and that it is ready to accept new datas. If this is not necessarily the
1401  * case, you should use prepare() instead.
1402  *
1403  * Normally, this is not called directly except by the GraphicsStateGuardian;
1404  * a data does not need to be explicitly prepared by the user before it may be
1405  * rendered.
1406  */
1410  nassertr(is_indexed(), nullptr);
1411 
1412  Contexts::const_iterator ci;
1413  ci = _contexts.find(prepared_objects);
1414  if (ci != _contexts.end()) {
1415  return (*ci).second;
1416  }
1417 
1418  IndexBufferContext *ibc = prepared_objects->prepare_index_buffer_now(this, gsg);
1419  if (ibc != nullptr) {
1420  _contexts[prepared_objects] = ibc;
1421  }
1422  return ibc;
1423 }
1424 
1425 /**
1426  * Frees the data context only on the indicated object, if it exists there.
1427  * Returns true if it was released, false if it had not been prepared.
1428  */
1429 bool GeomPrimitive::
1430 release(PreparedGraphicsObjects *prepared_objects) {
1431  Contexts::iterator ci;
1432  ci = _contexts.find(prepared_objects);
1433  if (ci != _contexts.end()) {
1434  IndexBufferContext *ibc = (*ci).second;
1435  prepared_objects->release_index_buffer(ibc);
1436  return true;
1437  }
1438 
1439  // Maybe it wasn't prepared yet, but it's about to be.
1440  return prepared_objects->dequeue_index_buffer(this);
1441 }
1442 
1443 /**
1444  * Frees the context allocated on all objects for which the data has been
1445  * declared. Returns the number of contexts which have been freed.
1446  */
1447 int GeomPrimitive::
1449  // We have to traverse a copy of the _contexts list, because the
1450  // PreparedGraphicsObjects object will call clear_prepared() in response to
1451  // each release_index_buffer(), and we don't want to be modifying the
1452  // _contexts list while we're traversing it.
1453  Contexts temp = _contexts;
1454  int num_freed = (int)_contexts.size();
1455 
1456  Contexts::const_iterator ci;
1457  for (ci = temp.begin(); ci != temp.end(); ++ci) {
1458  PreparedGraphicsObjects *prepared_objects = (*ci).first;
1459  IndexBufferContext *ibc = (*ci).second;
1460  prepared_objects->release_index_buffer(ibc);
1461  }
1462 
1463  // Now that we've called release_index_buffer() on every known context, the
1464  // _contexts list should have completely emptied itself.
1465  nassertr(_contexts.empty(), num_freed);
1466 
1467  return num_freed;
1468 }
1469 
1470 /**
1471  * Returns a registered GeomVertexArrayFormat of the indicated unsigned
1472  * integer numeric type for storing index values.
1473  */
1475 get_index_format(NumericType index_type) {
1476  switch (index_type) {
1477  case NT_uint8:
1478  {
1479  static CPT(GeomVertexArrayFormat) cformat = nullptr;
1480  if (cformat == nullptr) {
1481  cformat = make_index_format(NT_uint8);
1482  }
1483  return cformat;
1484  }
1485  case NT_uint16:
1486  {
1487  static CPT(GeomVertexArrayFormat) cformat = nullptr;
1488  if (cformat == nullptr) {
1489  cformat = make_index_format(NT_uint16);
1490  }
1491  return cformat;
1492  }
1493  case NT_uint32:
1494  {
1495  static CPT(GeomVertexArrayFormat) cformat = nullptr;
1496  if (cformat == nullptr) {
1497  cformat = make_index_format(NT_uint32);
1498  }
1499  return cformat;
1500  }
1501 
1502  default:
1503  gobj_cat.error()
1504  << "Not a valid index type: " << index_type << "\n";
1505  return nullptr;
1506  }
1507 
1508  return nullptr;
1509 }
1510 
1511 /**
1512  * Removes the indicated PreparedGraphicsObjects table from the data array's
1513  * table, without actually releasing the data array. This is intended to be
1514  * called only from PreparedGraphicsObjects::release_index_buffer(); it should
1515  * never be called by user code.
1516  */
1517 void GeomPrimitive::
1518 clear_prepared(PreparedGraphicsObjects *prepared_objects) {
1519  Contexts::iterator ci;
1520  ci = _contexts.find(prepared_objects);
1521  if (ci != _contexts.end()) {
1522  _contexts.erase(ci);
1523  } else {
1524  // If this assertion fails, clear_prepared() was given a prepared_objects
1525  // which the data array didn't know about.
1526  nassert_raise("unknown PreparedGraphicsObjects");
1527  }
1528 }
1529 
1530 /**
1531  * Returns the largest index value that can be stored in an index of the
1532  * indicated type, minus one (to leave room for a potential strip cut index)
1533  */
1534 int GeomPrimitive::
1535 get_highest_index_value(NumericType index_type) {
1536  // Reserve the highest possible index because implementations use this as a
1537  // strip-cut index.
1538  switch (index_type) {
1539  case NT_uint8:
1540  return 0xff - 1;
1541 
1542  case NT_uint16:
1543  return 0xffff - 1;
1544 
1545  case NT_uint32:
1546  // We don't actually allow use of the sign bit, since all of our functions
1547  // receive an "int" instead of an "unsigned int".
1548  return 0x7fffffff - 1;
1549 
1550  default:
1551  return 0;
1552  }
1553 }
1554 
1555 /**
1556  * Returns the index of the indicated type that is reserved for use as a strip
1557  * cut index, if enabled for the primitive. When the renderer encounters this
1558  * index, it will restart the primitive. This is guaranteed not to point to
1559  * an actual vertex.
1560  */
1561 int GeomPrimitive::
1562 get_strip_cut_index(NumericType index_type) {
1563  // Reserve the highest possible index because implementations use this as a
1564  // strip-cut index.
1565  switch (index_type) {
1566  case NT_uint8:
1567  return 0xff;
1568 
1569  case NT_uint16:
1570  return 0xffff;
1571 
1572  case NT_uint32:
1573  default:
1574  return -1;
1575  }
1576 }
1577 
1578 /**
1579  * Expands min_point and max_point to include all of the vertices in the Geom,
1580  * if any (or the data of any point type, for instance, texture coordinates--
1581  * based on the column name). found_any is set true if any points are found.
1582  * It is the caller's responsibility to initialize min_point, max_point, and
1583  * found_any before calling this function. It also sets sq_center_dist, which
1584  * is the square of the maximum distance of the points to the center. This
1585  * can be useful when deciding whether a sphere volume might be more
1586  * appropriate.
1587  */
1588 void GeomPrimitive::
1589 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
1590  PN_stdfloat &sq_center_dist, bool &found_any,
1591  const GeomVertexData *vertex_data,
1592  bool got_mat, const LMatrix4 &mat,
1593  const InternalName *column_name,
1594  Thread *current_thread) const {
1595  GeomVertexReader reader(vertex_data, column_name, current_thread);
1596  if (!reader.has_column()) {
1597  // No vertex data.
1598  return;
1599  }
1600 
1601  CDReader cdata(_cycler, current_thread);
1602  int i = 0;
1603 
1604  if (cdata->_vertices.is_null()) {
1605  // Nonindexed case.
1606  nassertv(cdata->_num_vertices != -1);
1607  if (cdata->_num_vertices == 0) {
1608  return;
1609  }
1610 
1611  if (got_mat) {
1612  // Find the first non-NaN vertex.
1613  while (!found_any && i < cdata->_num_vertices) {
1614  reader.set_row(cdata->_first_vertex + i);
1615  LPoint3 first_vertex = mat.xform_point(reader.get_data3());
1616  if (!first_vertex.is_nan()) {
1617  min_point = first_vertex;
1618  max_point = first_vertex;
1619  sq_center_dist = first_vertex.length_squared();
1620  found_any = true;
1621  }
1622  ++i;
1623  }
1624 
1625  for (; i < cdata->_num_vertices; ++i) {
1626  reader.set_row_unsafe(cdata->_first_vertex + i);
1627  LPoint3 vertex = mat.xform_point(reader.get_data3());
1628 
1629  min_point.set(min(min_point[0], vertex[0]),
1630  min(min_point[1], vertex[1]),
1631  min(min_point[2], vertex[2]));
1632  max_point.set(max(max_point[0], vertex[0]),
1633  max(max_point[1], vertex[1]),
1634  max(max_point[2], vertex[2]));
1635  sq_center_dist = max(sq_center_dist, vertex.length_squared());
1636  }
1637  } else {
1638  // Find the first non-NaN vertex.
1639  while (!found_any && i < cdata->_num_vertices) {
1640  reader.set_row(cdata->_first_vertex + i);
1641  LPoint3 first_vertex = reader.get_data3();
1642  if (!first_vertex.is_nan()) {
1643  min_point = first_vertex;
1644  max_point = first_vertex;
1645  sq_center_dist = first_vertex.length_squared();
1646  found_any = true;
1647  }
1648  ++i;
1649  }
1650 
1651  for (; i < cdata->_num_vertices; ++i) {
1652  reader.set_row_unsafe(cdata->_first_vertex + i);
1653  const LVecBase3 &vertex = reader.get_data3();
1654 
1655  min_point.set(min(min_point[0], vertex[0]),
1656  min(min_point[1], vertex[1]),
1657  min(min_point[2], vertex[2]));
1658  max_point.set(max(max_point[0], vertex[0]),
1659  max(max_point[1], vertex[1]),
1660  max(max_point[2], vertex[2]));
1661  sq_center_dist = max(sq_center_dist, vertex.length_squared());
1662  }
1663  }
1664 
1665  } else {
1666  // Indexed case.
1667  GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0, current_thread);
1668  if (index.is_at_end()) {
1669  return;
1670  }
1671 
1672  int strip_cut_index = get_strip_cut_index(cdata->_index_type);
1673 
1674  if (got_mat) {
1675  // Find the first non-NaN vertex.
1676  while (!found_any && !index.is_at_end()) {
1677  int ii = index.get_data1i();
1678  if (ii != strip_cut_index) {
1679  reader.set_row(ii);
1680  LPoint3 first_vertex = mat.xform_point(reader.get_data3());
1681  if (!first_vertex.is_nan()) {
1682  min_point = first_vertex;
1683  max_point = first_vertex;
1684  sq_center_dist = first_vertex.length_squared();
1685  found_any = true;
1686  }
1687  }
1688  }
1689 
1690  while (!index.is_at_end()) {
1691  int ii = index.get_data1i();
1692  if (ii == strip_cut_index) {
1693  continue;
1694  }
1695  reader.set_row_unsafe(ii);
1696  LPoint3 vertex = mat.xform_point(reader.get_data3());
1697 
1698  min_point.set(min(min_point[0], vertex[0]),
1699  min(min_point[1], vertex[1]),
1700  min(min_point[2], vertex[2]));
1701  max_point.set(max(max_point[0], vertex[0]),
1702  max(max_point[1], vertex[1]),
1703  max(max_point[2], vertex[2]));
1704  sq_center_dist = max(sq_center_dist, vertex.length_squared());
1705  }
1706  } else {
1707  // Find the first non-NaN vertex.
1708  while (!found_any && !index.is_at_end()) {
1709  int ii = index.get_data1i();
1710  if (ii != strip_cut_index) {
1711  reader.set_row(ii);
1712  LVecBase3 first_vertex = reader.get_data3();
1713  if (!first_vertex.is_nan()) {
1714  min_point = first_vertex;
1715  max_point = first_vertex;
1716  sq_center_dist = first_vertex.length_squared();
1717  found_any = true;
1718  }
1719  }
1720  }
1721 
1722  while (!index.is_at_end()) {
1723  int ii = index.get_data1i();
1724  if (ii == strip_cut_index) {
1725  continue;
1726  }
1727  reader.set_row_unsafe(ii);
1728  const LVecBase3 &vertex = reader.get_data3();
1729 
1730  min_point.set(min(min_point[0], vertex[0]),
1731  min(min_point[1], vertex[1]),
1732  min(min_point[2], vertex[2]));
1733  max_point.set(max(max_point[0], vertex[0]),
1734  max(max_point[1], vertex[1]),
1735  max(max_point[2], vertex[2]));
1736  sq_center_dist = max(sq_center_dist, vertex.length_squared());
1737  }
1738  }
1739  }
1740 }
1741 
1742 /**
1743  * Expands radius so that a sphere with the given center point fits all of the
1744  * vertices.
1745  *
1746  * The center point is assumed to already have been transformed by the matrix,
1747  * if one is given.
1748  */
1749 void GeomPrimitive::
1750 calc_sphere_radius(const LPoint3 &center, PN_stdfloat &sq_radius,
1751  bool &found_any, const GeomVertexData *vertex_data,
1752  Thread *current_thread) const {
1753  GeomVertexReader reader(vertex_data, InternalName::get_vertex(), current_thread);
1754  if (!reader.has_column()) {
1755  // No vertex data.
1756  return;
1757  }
1758 
1759  if (!found_any) {
1760  sq_radius = 0.0;
1761  }
1762 
1763  CDReader cdata(_cycler, current_thread);
1764 
1765  if (cdata->_vertices.is_null()) {
1766  // Nonindexed case.
1767  nassertv(cdata->_num_vertices != -1);
1768  if (cdata->_num_vertices == 0) {
1769  return;
1770  }
1771  found_any = true;
1772 
1773  for (int i = 0; i < cdata->_num_vertices; ++i) {
1774  reader.set_row_unsafe(cdata->_first_vertex + i);
1775  const LVecBase3 &vertex = reader.get_data3();
1776 
1777  sq_radius = max(sq_radius, (vertex - center).length_squared());
1778  }
1779 
1780  } else {
1781  // Indexed case.
1782  GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0, current_thread);
1783  if (index.is_at_end()) {
1784  return;
1785  }
1786  found_any = true;
1787 
1788  int strip_cut_index = get_strip_cut_index(cdata->_index_type);
1789 
1790  while (!index.is_at_end()) {
1791  int ii = index.get_data1i();
1792  if (ii == strip_cut_index) {
1793  continue;
1794  }
1795  reader.set_row_unsafe(ii);
1796  const LVecBase3 &vertex = reader.get_data3();
1797 
1798  sq_radius = max(sq_radius, (vertex - center).length_squared());
1799  }
1800  }
1801 }
1802 
1803 /**
1804  * Decomposes a complex primitive type into a simpler primitive type, for
1805  * instance triangle strips to triangles, and returns a pointer to the new
1806  * primitive definition. If the decomposition cannot be performed, this might
1807  * return the original object.
1808  *
1809  * This method is useful for application code that wants to iterate through
1810  * the set of triangles on the primitive without having to write handlers for
1811  * each possible kind of primitive type.
1812  */
1813 CPT(GeomPrimitive) GeomPrimitive::
1814 decompose_impl() const {
1815  return this;
1816 }
1817 
1818 /**
1819  * The virtual implementation of rotate().
1820  */
1821 CPT(GeomVertexArrayData) GeomPrimitive::
1822 rotate_impl() const {
1823  // The default implementation doesn't even try to do anything.
1824  nassertr(false, nullptr);
1825  return nullptr;
1826 }
1827 
1828 /**
1829  * The virtual implementation of doubleside().
1830  */
1831 CPT(GeomPrimitive) GeomPrimitive::
1832 doubleside_impl() const {
1833  return this;
1834 }
1835 
1836 /**
1837  * The virtual implementation of reverse().
1838  */
1839 CPT(GeomPrimitive) GeomPrimitive::
1840 reverse_impl() const {
1841  return this;
1842 }
1843 
1844 /**
1845  * Should be redefined to return true in any primitive that implements
1846  * append_unused_vertices().
1847  */
1848 bool GeomPrimitive::
1849 requires_unused_vertices() const {
1850  return false;
1851 }
1852 
1853 /**
1854  * Called when a new primitive is begun (other than the first primitive), this
1855  * should add some degenerate vertices between primitives, if the primitive
1856  * type requires that. The second parameter is the first vertex that begins
1857  * the new primitive.
1858  *
1859  * This method is only called if requires_unused_vertices(), above, returns
1860  * true.
1861  */
1862 void GeomPrimitive::
1863 append_unused_vertices(GeomVertexArrayData *, int) {
1864 }
1865 
1866 /**
1867  * Recomputes the _min_vertex and _max_vertex values if necessary.
1868  */
1869 void GeomPrimitive::
1870 recompute_minmax(GeomPrimitive::CData *cdata) {
1871  if (cdata->_vertices.is_null()) {
1872  // In the nonindexed case, we don't need to do much (the minmax is
1873  // trivial).
1874  nassertv(cdata->_num_vertices != -1);
1875  cdata->_min_vertex = cdata->_first_vertex;
1876  cdata->_max_vertex = cdata->_first_vertex + cdata->_num_vertices - 1;
1877  cdata->_mins.clear();
1878  cdata->_maxs.clear();
1879 
1880  } else {
1881  int num_vertices = cdata->_vertices.get_read_pointer()->get_num_rows();
1882 
1883  if (num_vertices == 0) {
1884  // Or if we don't have any vertices, the minmax is also trivial.
1885  cdata->_min_vertex = 0;
1886  cdata->_max_vertex = 0;
1887  cdata->_mins.clear();
1888  cdata->_maxs.clear();
1889 
1890  } else if (get_num_vertices_per_primitive() == 0) {
1891  // This is a complex primitive type like a triangle strip; compute the
1892  // minmax of each primitive (as well as the overall minmax).
1893  GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
1894 
1895  cdata->_mins = make_index_data();
1896  cdata->_maxs = make_index_data();
1897 
1898  GeomVertexArrayData *mins_data = cdata->_mins.get_write_pointer();
1899  GeomVertexArrayData *maxs_data = cdata->_maxs.get_write_pointer();
1900 
1901  mins_data->unclean_set_num_rows(cdata->_ends.size());
1902  maxs_data->unclean_set_num_rows(cdata->_ends.size());
1903 
1904  GeomVertexWriter mins(mins_data, 0);
1905  GeomVertexWriter maxs(maxs_data, 0);
1906 
1907  int pi = 0;
1908 
1909  unsigned int vertex = index.get_data1i();
1910  cdata->_min_vertex = vertex;
1911  cdata->_max_vertex = vertex;
1912  unsigned int min_prim = vertex;
1913  unsigned int max_prim = vertex;
1914 
1915  int num_unused_vertices = get_num_unused_vertices_per_primitive();
1916 
1917  for (int vi = 1; vi < num_vertices; ++vi) {
1918  nassertv(!index.is_at_end());
1919  nassertv(pi < (int)cdata->_ends.size());
1920 
1921  unsigned int vertex;
1922 
1923  if (vi == cdata->_ends[pi]) {
1924  // Skip unused vertices, since they won't be very relevant and may
1925  // contain a strip-cut index, which would distort the result.
1926  if (num_unused_vertices > 0) {
1927  vi += num_unused_vertices;
1928  index.set_row_unsafe(vi);
1929  }
1930  vertex = index.get_data1i();
1931 
1932  mins.set_data1i(min_prim);
1933  maxs.set_data1i(max_prim);
1934  min_prim = vertex;
1935  max_prim = vertex;
1936  ++pi;
1937 
1938  } else {
1939  vertex = index.get_data1i();
1940  min_prim = min(min_prim, vertex);
1941  max_prim = max(max_prim, vertex);
1942  }
1943 
1944  cdata->_min_vertex = min(cdata->_min_vertex, vertex);
1945  cdata->_max_vertex = max(cdata->_max_vertex, vertex);
1946  }
1947 
1948  mins.set_data1i(min_prim);
1949  maxs.set_data1i(max_prim);
1950  nassertv(mins.get_array_data()->get_num_rows() == (int)cdata->_ends.size());
1951 
1952  } else {
1953  // This is a simple primitive type like a triangle; just compute the
1954  // overall minmax.
1955  GeomVertexReader index(cdata->_vertices.get_read_pointer(), 0);
1956 
1957  cdata->_mins.clear();
1958  cdata->_maxs.clear();
1959 
1960  unsigned int vertex = index.get_data1i();
1961  cdata->_min_vertex = vertex;
1962  cdata->_max_vertex = vertex;
1963 
1964  for (int vi = 1; vi < num_vertices; ++vi) {
1965  nassertv(!index.is_at_end());
1966  unsigned int vertex = index.get_data1i();
1967  cdata->_min_vertex = min(cdata->_min_vertex, vertex);
1968  cdata->_max_vertex = max(cdata->_max_vertex, vertex);
1969  }
1970  }
1971  }
1972 
1973  cdata->_got_minmax = true;
1974 }
1975 
1976 /**
1977  * The private implementation of make_indexed().
1978  */
1979 void GeomPrimitive::
1980 do_make_indexed(CData *cdata) {
1981  if (cdata->_vertices.is_null()) {
1982  if (gobj_cat.is_debug()) {
1983  gobj_cat.debug()
1984  << this << ".make_indexed()\n";
1985  }
1986 
1987  nassertv(cdata->_num_vertices != -1);
1988  cdata->_vertices = make_index_data();
1989 
1990  GeomVertexArrayData *array_data = cdata->_vertices.get_write_pointer();
1991  array_data->unclean_set_num_rows(cdata->_num_vertices);
1992  GeomVertexWriter index(array_data, 0);
1993 
1994  for (int i = 0; i < cdata->_num_vertices; ++i) {
1995  index.set_data1i(i + cdata->_first_vertex);
1996  }
1997  cdata->_num_vertices = -1;
1998  }
1999 }
2000 
2001 /**
2002  * If the indicated new vertex index won't fit in the specified index type,
2003  * automatically elevates the index type to the next available size.
2004  */
2005 void GeomPrimitive::
2006 consider_elevate_index_type(CData *cdata, int vertex) {
2007  // Note that we reserve the highest possible index of a particular index
2008  // type (ie. -1) because this is commonly used as a strip-cut (also known
2009  // as primitive restart) index.
2010  switch (cdata->_index_type) {
2011  case NT_uint8:
2012  if (vertex >= 0xff) {
2013  do_set_index_type(cdata, NT_uint16);
2014  }
2015  break;
2016 
2017  case NT_uint16:
2018  if (vertex >= 0xffff) {
2019  do_set_index_type(cdata, NT_uint32);
2020  }
2021  break;
2022 
2023  case NT_uint32:
2024  // Not much we can do here.
2025  nassertv(vertex < 0x7fffffff);
2026  break;
2027 
2028  default:
2029  break;
2030  }
2031 }
2032 
2033 /**
2034  * The private implementation of set_index_type().
2035  */
2036 void GeomPrimitive::
2037 do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
2038  int old_strip_cut_index = get_strip_cut_index(cdata->_index_type);
2039  int new_strip_cut_index = get_strip_cut_index(index_type);
2040 
2041  cdata->_index_type = index_type;
2042 
2043  if (gobj_cat.is_debug()) {
2044  gobj_cat.debug()
2045  << this << ".set_index_type(" << index_type << ")\n";
2046  }
2047 
2048  if (!cdata->_vertices.is_null()) {
2049  CPT(GeomVertexArrayFormat) new_format = get_index_format();
2050 
2051  CPT(GeomVertexArrayData) array_obj = cdata->_vertices.get_read_pointer();
2052  if (array_obj->get_array_format() != new_format) {
2053  PT(GeomVertexArrayData) new_vertices = make_index_data();
2054  new_vertices->set_num_rows(array_obj->get_num_rows());
2055 
2056  GeomVertexReader from(array_obj, 0);
2057  GeomVertexWriter to(new_vertices, 0);
2058 
2059  while (!from.is_at_end()) {
2060  int index = from.get_data1i();
2061  if (index == old_strip_cut_index) {
2062  index = new_strip_cut_index;
2063  }
2064  to.set_data1i(index);
2065  }
2066  cdata->_vertices = new_vertices;
2067  cdata->_got_minmax = false;
2068  }
2069  }
2070 }
2071 
2072 /**
2073  * The private implementation of modify_vertices().
2074  */
2075 PT(GeomVertexArrayData) GeomPrimitive::
2076 do_modify_vertices(GeomPrimitive::CData *cdata) {
2077  if (cdata->_vertices.is_null()) {
2078  do_make_indexed(cdata);
2079  }
2080 
2081  PT(GeomVertexArrayData) vertices = cdata->_vertices.get_write_pointer();
2082 
2083  cdata->_modified = Geom::get_next_modified();
2084  cdata->_got_minmax = false;
2085  return vertices;
2086 }
2087 
2088 /**
2089  * Writes the contents of this object to the datagram for shipping out to a
2090  * Bam file.
2091  */
2092 void GeomPrimitive::
2094  TypedWritable::write_datagram(manager, dg);
2095 
2096  manager->write_cdata(dg, _cycler);
2097 }
2098 
2099 /**
2100  * Called by the BamReader to perform any final actions needed for setting up
2101  * the object after all objects have been read and all pointers have been
2102  * completed.
2103  */
2104 void GeomPrimitive::
2105 finalize(BamReader *manager) {
2106  const GeomVertexArrayData *vertices = get_vertices();
2107  if (vertices != nullptr) {
2108  set_usage_hint(vertices->get_usage_hint());
2109  }
2110 }
2111 
2112 /**
2113  * This internal function is called by make_from_bam to read in all of the
2114  * relevant data from the BamFile for the new GeomPrimitive.
2115  */
2116 void GeomPrimitive::
2117 fillin(DatagramIterator &scan, BamReader *manager) {
2118  TypedWritable::fillin(scan, manager);
2119 
2120  manager->read_cdata(scan, _cycler);
2121  manager->register_finalize(this);
2122 }
2123 
2124 /**
2125  *
2126  */
2127 CycleData *GeomPrimitive::CData::
2128 make_copy() const {
2129  return new CData(*this);
2130 }
2131 
2132 /**
2133  * Writes the contents of this object to the datagram for shipping out to a
2134  * Bam file.
2135  */
2136 void GeomPrimitive::CData::
2137 write_datagram(BamWriter *manager, Datagram &dg) const {
2138  dg.add_uint8(_shade_model);
2139  dg.add_int32(_first_vertex);
2140  dg.add_int32(_num_vertices);
2141  dg.add_uint8(_index_type);
2142  dg.add_uint8(_usage_hint);
2143 
2144  manager->write_pointer(dg, _vertices.get_read_pointer());
2145  WRITE_PTA(manager, dg, IPD_int::write_datagram, _ends);
2146 }
2147 
2148 /**
2149  * Receives an array of pointers, one for each time manager->read_pointer()
2150  * was called in fillin(). Returns the number of pointers processed.
2151  */
2152 int GeomPrimitive::CData::
2153 complete_pointers(TypedWritable **p_list, BamReader *manager) {
2154  int pi = CycleData::complete_pointers(p_list, manager);
2155 
2156  _vertices = DCAST(GeomVertexArrayData, p_list[pi++]);
2157 
2158  if (manager->get_file_minor_ver() < 6 && !_vertices.is_null()) {
2159  // Older bam files might have a meaningless number in _num_vertices if the
2160  // primitive is indexed. Nowadays, this number is always considered
2161  // meaningful unless it is -1.
2162  _num_vertices = -1;
2163  }
2164 
2165  return pi;
2166 }
2167 
2168 /**
2169  * This internal function is called by make_from_bam to read in all of the
2170  * relevant data from the BamFile for the new GeomPrimitive.
2171  */
2172 void GeomPrimitive::CData::
2173 fillin(DatagramIterator &scan, BamReader *manager) {
2174  _shade_model = (ShadeModel)scan.get_uint8();
2175  _first_vertex = scan.get_int32();
2176  _num_vertices = scan.get_int32();
2177  _index_type = (NumericType)scan.get_uint8();
2178  _usage_hint = (UsageHint)scan.get_uint8();
2179 
2180  manager->read_pointer(scan);
2181  READ_PTA(manager, scan, IPD_int::read_datagram, _ends);
2182 
2183  _modified = Geom::get_next_modified();
2184  _got_minmax = false;
2185 }
2186 
2187 /**
2188  * Ensures that the primitive's minmax cache has been computed.
2189  */
2191 check_minmax() const {
2192  if (!_cdata->_got_minmax) {
2193  // We'll need to get a fresh pointer, since another thread might already
2194  // have modified the pointer on the object since we queried it.
2195  {
2196 #ifdef DO_PIPELINING
2197  unref_delete((CycleData *)_cdata);
2198 #endif
2199  GeomPrimitive::CDWriter fresh_cdata(((GeomPrimitive *)_object.p())->_cycler,
2200  false, _current_thread);
2201  ((GeomPrimitivePipelineReader *)this)->_cdata = fresh_cdata;
2202 #ifdef DO_PIPELINING
2203  _cdata->ref();
2204 #endif
2205 
2206  if (!fresh_cdata->_got_minmax) {
2207  // The cache is still stale. We have to do the work of freshening it.
2208  ((GeomPrimitive *)_object.p())->recompute_minmax(fresh_cdata);
2209  nassertv(fresh_cdata->_got_minmax);
2210  }
2211 
2212  // When fresh_cdata goes out of scope, its write lock is released, and
2213  // _cdata reverts to our usual convention of an unlocked copy of the
2214  // data.
2215  }
2216  }
2217 
2218  nassertv(_cdata->_got_minmax);
2219 }
2220 
2221 /**
2222  *
2223  */
2224 int GeomPrimitivePipelineReader::
2225 get_first_vertex() const {
2226  if (_vertices.is_null()) {
2227  return _cdata->_first_vertex;
2228  }
2229 
2230  size_t size = _vertices_cdata->_buffer.get_size();
2231  if (size == 0) {
2232  return 0;
2233  }
2234 
2235  GeomVertexReader index(_vertices, 0);
2236  return index.get_data1i();
2237 }
2238 
2239 /**
2240  * Returns the ith vertex index in the table.
2241  */
2243 get_vertex(int i) const {
2244  if (!_vertices.is_null()) {
2245  // The indexed case.
2246  nassertr(i >= 0 && i < get_num_vertices(), -1);
2247 
2248  const unsigned char *ptr = get_read_pointer(true);
2249  switch (_cdata->_index_type) {
2250  case GeomEnums::NT_uint8:
2251  return ((uint8_t *)ptr)[i];
2252  break;
2253  case GeomEnums::NT_uint16:
2254  return ((uint16_t *)ptr)[i];
2255  break;
2256  case GeomEnums::NT_uint32:
2257  return ((uint32_t *)ptr)[i];
2258  break;
2259  default:
2260  nassert_raise("unsupported index type");
2261  return -1;
2262  }
2263 
2264  } else {
2265  // The nonindexed case.
2266  return _cdata->_first_vertex + i;
2267  }
2268 }
2269 
2270 /**
2271  *
2272  */
2273 int GeomPrimitivePipelineReader::
2274 get_num_primitives() const {
2275  int num_vertices_per_primitive = _object->get_num_vertices_per_primitive();
2276 
2277  if (num_vertices_per_primitive == 0) {
2278  // This is a complex primitive type like a triangle strip: each primitive
2279  // uses a different number of vertices.
2280  return _cdata->_ends.size();
2281 
2282  } else {
2283  // This is a simple primitive type like a triangle: each primitive uses
2284  // the same number of vertices.
2285  return (get_num_vertices() / num_vertices_per_primitive);
2286  }
2287 }
2288 
2289 /**
2290  * Turns on all the bits corresponding to the vertices that are referenced
2291  * by this GeomPrimitive.
2292  */
2295  int num_vertices = get_num_vertices();
2296 
2297  if (is_indexed()) {
2298  int strip_cut_index = get_strip_cut_index();
2299  const unsigned char *ptr = get_read_pointer(true);
2300  switch (get_index_type()) {
2301  case GeomEnums::NT_uint8:
2302  for (int vi = 0; vi < num_vertices; ++vi) {
2303  int index = ((const uint8_t *)ptr)[vi];
2304  if (index != strip_cut_index) {
2305  bits.set_bit(index);
2306  }
2307  }
2308  break;
2309  case GeomEnums::NT_uint16:
2310  for (int vi = 0; vi < num_vertices; ++vi) {
2311  int index = ((const uint16_t *)ptr)[vi];
2312  if (index != strip_cut_index) {
2313  bits.set_bit(index);
2314  }
2315  }
2316  break;
2317  case GeomEnums::NT_uint32:
2318  for (int vi = 0; vi < num_vertices; ++vi) {
2319  int index = ((const uint32_t *)ptr)[vi];
2320  if (index != strip_cut_index) {
2321  bits.set_bit(index);
2322  }
2323  }
2324  break;
2325  default:
2326  nassert_raise("unsupported index type");
2327  break;
2328  }
2329  } else {
2330  // Nonindexed case.
2331  bits.set_range(get_first_vertex(), num_vertices);
2332  }
2333 }
2334 
2335 /**
2336  *
2337  */
2338 bool GeomPrimitivePipelineReader::
2339 check_valid(const GeomVertexDataPipelineReader *data_reader) const {
2340  if (get_num_vertices() != 0 &&
2341  data_reader->get_num_arrays() > 0 &&
2342  get_max_vertex() >= data_reader->get_num_rows()) {
2343 
2344 #ifndef NDEBUG
2345  gobj_cat.error()
2346  << get_object()->get_type() << " references vertices up to "
2347  << get_max_vertex() << ", but GeomVertexData has only "
2348  << data_reader->get_num_rows() << " rows!\n";
2349 #endif
2350  return false;
2351  }
2352 
2353  return true;
2354 }
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(),...
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,...
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,...
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'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(),...
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,...
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:1324
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'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'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,...
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.