Panda3D
 All Classes Functions Variables Enumerations
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 ////////////////////////////////////////////////////////////////////
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();
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) *
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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::
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 ////////////////////////////////////////////////////////////////////
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 }
bool get_bit(int index) const
Returns true if the nth bit is set, false if it is cleared.
Definition: bitArray.I:207
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 get_num_used_vertices() const
Returns the number of vertices used by all of the primitives.
int get_primitive_start(int n) const
Returns the element within the _vertices list at which the nth primitive starts.
int release_all()
Frees the context allocated on all objects for which the data has been declared.
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_indexed() const
Returns true if the primitive is indexed, false otherwise.
UsageHint get_usage_hint() const
Returns the usage hint that describes to the rendering backend how often the vertex data will be modi...
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...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
Definition: geom.cxx:1682
Defines a series of disconnected points.
Definition: geomPoints.h:25
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:747
bool dequeue_index_buffer(GeomPrimitive *data)
Removes a buffer from the queued list of data arrays to be prepared.
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...
int get_strip_cut_index() const
If relevant, returns the index value that may be used in some cases to signify the end of a primitive...
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
const GeomVertexArrayFormat * get_index_format() const
Returns a registered format appropriate for using to store the index table.
int get_primitive_end(int n) const
Returns the element within the _vertices list at which the nth primitive ends.
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
IndexBufferContext * prepare_index_buffer_now(GeomPrimitive *data, GraphicsStateGuardianBase *gsg)
Immediately creates a new IndexBufferContext for the indicated data and returns it.
float length_squared() const
Returns the square of the vector&#39;s length, cheap and easy.
Definition: lvecBase3.h:748
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...
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...
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:74
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. ...
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 lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:34
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...
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...
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...
bool is_index_buffer_queued(const GeomPrimitive *data) const
Returns true if the index buffer has been queued on this GSG, false otherwise.
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...
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...
A dynamic array with an unlimited number of bits.
Definition: bitArray.h:42
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 represents a single element that may be timed and/or counted via stats...
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 add_vertex(int vertex)
Adds the indicated vertex to the list of vertex indices used by the graphics primitive type...
void set_row_unsafe(int row)
Sets the start row to the indicated value, without internal checks.
int get_primitive_max_vertex(int n) const
Returns the maximum vertex index number used by the nth primitive in this object. ...
Defines a series of &quot;patches&quot;, fixed-size groupings of vertices that must be processed by a tessellat...
Definition: geomPatches.h:27
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.
int get_max_vertex() const
Returns the maximum vertex index number used by all the primitives in this object.
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
virtual int get_geom_rendering() const
Returns the set of GeomRendering bits that represent the rendering properties required to properly re...
bool request_resident() const
Returns true if the primitive data is currently resident in memory.
int get_primitive_num_vertices(int n) const
Returns the number of vertices used by the nth primitive.
void clear_vertices()
Removes all of the vertices and primitives from the object, so they can be re-added.
void clear_minmax()
Undoes a previous call to set_minmax(), and allows the minimum and maximum values to be recomputed no...
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
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
UsageHint get_usage_hint() const
Returns the minimum (i.e.
Definition: geom.I:67
A container for geometry primitives.
Definition: geom.h:58
const LVecBase3 & get_data3()
Returns the data associated with the read row, expressed as a 3-component value, and advances the rea...
bool has_column() const
Returns true if a valid data type has been successfully set, or false if the data type does not exist...
virtual Geom * make_copy() const
Returns a newly-allocated Geom that is a shallow copy of this one.
Definition: geom.cxx:118
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-&gt;read_pointer() was called in fillin()...
Definition: cycleData.cxx:55
bool is_composite() const
Returns true if the primitive is a composite primitive such as a tristrip or trifan, or false if it is a fundamental primitive such as a collection of triangles.
Definition: geomPrimitive.I:93
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:880
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
int get_num_bytes() const
Returns the number of bytes consumed by the primitive and its index table(s).
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...
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.
bool is_at_end() const
Returns true if the reader or writer is currently at the end of the list of vertices, false otherwise.
This base class provides basic reference counting, but also can be used with a CopyOnWritePointer to ...
void check_minmax() const
Ensures that the primitive&#39;s minmax cache has been computed.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
int get_num_vertices() const
Returns the number of indices used by all the primitives in this object.
A thread; that is, a lightweight process.
Definition: thread.h:51
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
static UpdateSeq get_next_modified()
Returns a monotonically increasing sequence.
Definition: geom.cxx:1324
int get_primitive_min_vertex(int n) const
Returns the minimum vertex index number used by the nth primitive in this object. ...
int get_vertex(int i) const
Returns the ith vertex index in the table.
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.
void add_int32(PN_int32 value)
Adds a signed 32-bit integer to the datagram.
Definition: datagram.I:159
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.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:105
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
Encapsulates the data from a GeomPrimitive, pre-fetched for one stage of the pipeline.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
int get_vertex(int i) const
Returns the ith vertex index in the table.
void make_indexed()
Converts the primitive from nonindexed form to indexed form.
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 object provides the functionality of both a GeomVertexReader and a GeomVertexWriter, combined together into one convenient package.
int get_num_primitives() const
Returns the number of individual primitives stored within this object.
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:652
int get_num_primitives() const
Returns the number of GeomPrimitive objects stored within the Geom, each of which represents a number...
Definition: geom.I:110
int get_num_rows() const
Returns the number of rows stored within all the arrays.