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