Panda3D
geomTristrips.cxx
1 // Filename: geomTristrips.cxx
2 // Created by: drose (08Mar05)
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 "geomTristrips.h"
16 #include "geomTriangles.h"
17 #include "geomVertexRewriter.h"
18 #include "pStatTimer.h"
19 #include "bamReader.h"
20 #include "bamWriter.h"
21 #include "graphicsStateGuardianBase.h"
22 
23 TypeHandle GeomTristrips::_type_handle;
24 
25 ////////////////////////////////////////////////////////////////////
26 // Function: GeomTristrips::Constructor
27 // Access: Published
28 // Description:
29 ////////////////////////////////////////////////////////////////////
30 GeomTristrips::
31 GeomTristrips(GeomTristrips::UsageHint usage_hint) :
32  GeomPrimitive(usage_hint)
33 {
34 }
35 
36 ////////////////////////////////////////////////////////////////////
37 // Function: GeomTristrips::Copy Constructor
38 // Access: Published
39 // Description:
40 ////////////////////////////////////////////////////////////////////
41 GeomTristrips::
42 GeomTristrips(const GeomTristrips &copy) :
43  GeomPrimitive(copy)
44 {
45 }
46 
47 ////////////////////////////////////////////////////////////////////
48 // Function: GeomTristrips::Destructor
49 // Access: Published, Virtual
50 // Description:
51 ////////////////////////////////////////////////////////////////////
52 GeomTristrips::
53 ~GeomTristrips() {
54 }
55 
56 ////////////////////////////////////////////////////////////////////
57 // Function: GeomTristrips::make_copy
58 // Access: Public, Virtual
59 // Description:
60 ////////////////////////////////////////////////////////////////////
61 PT(GeomPrimitive) GeomTristrips::
62 make_copy() const {
63  return new GeomTristrips(*this);
64 }
65 
66 ////////////////////////////////////////////////////////////////////
67 // Function: GeomTristrips::get_primitive_type
68 // Access: Public, Virtual
69 // Description: Returns the fundamental rendering type of this
70 // primitive: whether it is points, lines, or polygons.
71 //
72 // This is used to set up the appropriate antialiasing
73 // settings when AntialiasAttrib::M_auto is in effect;
74 // it also implies the type of primitive that will be
75 // produced when decompose() is called.
76 ////////////////////////////////////////////////////////////////////
77 GeomPrimitive::PrimitiveType GeomTristrips::
78 get_primitive_type() const {
79  return PT_polygons;
80 }
81 
82 ////////////////////////////////////////////////////////////////////
83 // Function: GeomTristrips::get_geom_rendering
84 // Access: Published, Virtual
85 // Description: Returns the set of GeomRendering bits that represent
86 // the rendering properties required to properly render
87 // this primitive.
88 ////////////////////////////////////////////////////////////////////
90 get_geom_rendering() const {
91  if (is_indexed()) {
92  return GR_triangle_strip | GR_indexed_other;
93  } else {
94  return GR_triangle_strip;
95  }
96 }
97 
98 ////////////////////////////////////////////////////////////////////
99 // Function: GeomTristrips::get_min_num_vertices_per_primitive
100 // Access: Public, Virtual
101 // Description: Returns the minimum number of vertices that must be
102 // added before close_primitive() may legally be called.
103 ////////////////////////////////////////////////////////////////////
104 int GeomTristrips::
106  return 3;
107 }
108 
109 ////////////////////////////////////////////////////////////////////
110 // Function: GeomTristrips::get_num_unused_vertices_per_primitive
111 // Access: Public, Virtual
112 // Description: Returns the number of vertices that are added between
113 // primitives that aren't, strictly speaking, part of
114 // the primitives themselves. This is used, for
115 // instance, to define degenerate triangles to connect
116 // otherwise disconnected triangle strips.
117 ////////////////////////////////////////////////////////////////////
118 int GeomTristrips::
120  return 2;
121 }
122 
123 ////////////////////////////////////////////////////////////////////
124 // Function: GeomTristrips::draw
125 // Access: Public, Virtual
126 // Description: Calls the appropriate method on the GSG to draw the
127 // primitive.
128 ////////////////////////////////////////////////////////////////////
129 bool GeomTristrips::
131  bool force) const {
132  return gsg->draw_tristrips(reader, force);
133 }
134 
135 ////////////////////////////////////////////////////////////////////
136 // Function: GeomTristrips::decompose_impl
137 // Access: Protected, Virtual
138 // Description: Decomposes a complex primitive type into a simpler
139 // primitive type, for instance triangle strips to
140 // triangles, and returns a pointer to the new primitive
141 // definition. If the decomposition cannot be
142 // performed, this might return the original object.
143 //
144 // This method is useful for application code that wants
145 // to iterate through the set of triangles on the
146 // primitive without having to write handlers for each
147 // possible kind of primitive type.
148 ////////////////////////////////////////////////////////////////////
149 CPT(GeomPrimitive) GeomTristrips::
150 decompose_impl() const {
151  PT(GeomTriangles) triangles = new GeomTriangles(get_usage_hint());
152  triangles->set_shade_model(get_shade_model());
153  CPTA_int ends = get_ends();
154 
155  int num_vertices = get_num_vertices();
156  int num_unused = get_num_unused_vertices_per_primitive();
157 
158  // We need a slightly different algorithm for SM_flat_first_vertex
159  // than for SM_flat_last_vertex, to preserve the key vertex in the
160  // right place. The remaining shade models can use either
161  // algorithm.
162  if (get_shade_model() == SM_flat_first_vertex) {
163  // Preserve the first vertex of each component triangle as the
164  // first vertex of each generated triangle.
165  int vi = -num_unused;
166  int li = 0;
167  while (li < (int)ends.size()) {
168  // Skip unused vertices between tristrips.
169  vi += num_unused;
170  int end = ends[li];
171  nassertr(vi + 2 <= end, NULL);
172  int v0 = get_vertex(vi);
173  ++vi;
174  int v1 = get_vertex(vi);
175  ++vi;
176  bool reversed = false;
177  while (vi < end) {
178  int v2 = get_vertex(vi);
179  ++vi;
180  if (reversed) {
181  if (v0 != v1 && v0 != v2 && v1 != v2) {
182  triangles->add_vertex(v0);
183  triangles->add_vertex(v2);
184  triangles->add_vertex(v1);
185  triangles->close_primitive();
186  }
187  reversed = false;
188  } else {
189  if (v0 != v1 && v0 != v2 && v1 != v2) {
190  triangles->add_vertex(v0);
191  triangles->add_vertex(v1);
192  triangles->add_vertex(v2);
193  triangles->close_primitive();
194  }
195  reversed = true;
196  }
197  v0 = v1;
198  v1 = v2;
199  }
200  ++li;
201  }
202  nassertr(vi == num_vertices, NULL);
203 
204  } else {
205  // Preserve the last vertex of each component triangle as the
206  // last vertex of each generated triangle.
207  int vi = -num_unused;
208  int li = 0;
209  while (li < (int)ends.size()) {
210  // Skip unused vertices between tristrips.
211  vi += num_unused;
212  int end = ends[li];
213  nassertr(vi + 2 <= end, NULL);
214  int v0 = get_vertex(vi);
215  ++vi;
216  int v1 = get_vertex(vi);
217  ++vi;
218  bool reversed = false;
219  while (vi < end) {
220  int v2 = get_vertex(vi);
221  if (reversed) {
222  if (v0 != v1 && v0 != v2 && v1 != v2) {
223  triangles->add_vertex(v1);
224  triangles->add_vertex(v0);
225  triangles->add_vertex(v2);
226  triangles->close_primitive();
227  }
228  reversed = false;
229  } else {
230  if (v0 != v1 && v0 != v2 && v1 != v2) {
231  triangles->add_vertex(v0);
232  triangles->add_vertex(v1);
233  triangles->add_vertex(v2);
234  triangles->close_primitive();
235  }
236  reversed = true;
237  }
238  ++vi;
239  v0 = v1;
240  v1 = v2;
241  }
242  ++li;
243  }
244  nassertr(vi == num_vertices, NULL);
245  }
246 
247  return triangles.p();
248 }
249 
250 ////////////////////////////////////////////////////////////////////
251 // Function: GeomTristrips::doubleside_impl
252 // Access: Protected, Virtual
253 // Description: The virtual implementation of doubleside().
254 ////////////////////////////////////////////////////////////////////
255 CPT(GeomPrimitive) GeomTristrips::
256 doubleside_impl() const {
257  // TODO: implement this properly as triangle strips, without
258  // requiring a decompose operation first.
259  return decompose_impl()->doubleside();
260 }
261 
262 ////////////////////////////////////////////////////////////////////
263 // Function: GeomTristrips::reverse_impl
264 // Access: Protected, Virtual
265 // Description: The virtual implementation of reverse().
266 ////////////////////////////////////////////////////////////////////
267 CPT(GeomPrimitive) GeomTristrips::
268 reverse_impl() const {
269  // TODO: implement this properly as triangle strips, without
270  // requiring a decompose operation first.
271  return decompose_impl()->reverse();
272 }
273 
274 ////////////////////////////////////////////////////////////////////
275 // Function: GeomTristrips::rotate_impl
276 // Access: Protected, Virtual
277 // Description: The virtual implementation of do_rotate().
278 ////////////////////////////////////////////////////////////////////
279 CPT(GeomVertexArrayData) GeomTristrips::
280 rotate_impl() const {
281  // To rotate a triangle strip with an even number of vertices, we
282  // just reverse the vertices. But if we have an odd number of
283  // vertices, that doesn't work--in fact, nothing works (without also
284  // changing the winding order), so we don't allow an odd number of
285  // vertices in a flat-shaded tristrip.
286  CPTA_int ends = get_ends();
287 
288  PT(GeomVertexArrayData) new_vertices = make_index_data();
289  new_vertices->set_num_rows(get_num_vertices());
290 
291  if (is_indexed()) {
292  CPT(GeomVertexArrayData) vertices = get_vertices();
293  GeomVertexReader from(vertices, 0);
294  GeomVertexWriter to(new_vertices, 0);
295 
296  int begin = 0;
297  int last_added = 0;
298  CPTA_int::const_iterator ei;
299  for (ei = ends.begin(); ei != ends.end(); ++ei) {
300  int end = (*ei);
301  int num_vertices = end - begin;
302 
303  if (begin != 0) {
304  // Copy in the unused vertices between tristrips.
305  to.set_data1i(last_added);
306  from.set_row_unsafe(end - 1);
307  to.set_data1i(from.get_data1i());
308  begin += 2;
309  }
310 
311  // If this assertion is triggered, there was a triangle strip with
312  // an odd number of vertices, which is not allowed.
313  nassertr((num_vertices & 1) == 0, NULL);
314  for (int vi = end - 1; vi >= begin; --vi) {
315  from.set_row_unsafe(vi);
316  last_added = from.get_data1i();
317  to.set_data1i(last_added);
318  }
319 
320  begin = end;
321  }
322 
323  nassertr(to.is_at_end(), NULL);
324 
325  } else {
326  // Nonindexed case.
327  int first_vertex = get_first_vertex();
328  GeomVertexWriter to(new_vertices, 0);
329 
330  int begin = 0;
331  int last_added = 0;
332  CPTA_int::const_iterator ei;
333  for (ei = ends.begin(); ei != ends.end(); ++ei) {
334  int end = (*ei);
335  int num_vertices = end - begin;
336 
337  if (begin != 0) {
338  // Copy in the unused vertices between tristrips.
339  to.set_data1i(last_added);
340  to.set_data1i(end - 1 + first_vertex);
341  begin += 2;
342  }
343 
344  // If this assertion is triggered, there was a triangle strip with
345  // an odd number of vertices, which is not allowed.
346  nassertr((num_vertices & 1) == 0, NULL);
347  for (int vi = end - 1; vi >= begin; --vi) {
348  last_added = vi + first_vertex;
349  to.set_data1i(last_added);
350  }
351 
352  begin = end;
353  }
354 
355  nassertr(to.is_at_end(), NULL);
356  }
357  return new_vertices;
358 }
359 
360 ////////////////////////////////////////////////////////////////////
361 // Function: GeomTristrips::requires_unused_vertices
362 // Access: Protected, Virtual
363 // Description: Should be redefined to return true in any primitive
364 // that implements append_unused_vertices().
365 ////////////////////////////////////////////////////////////////////
366 bool GeomTristrips::
367 requires_unused_vertices() const {
368  return true;
369 }
370 
371 ////////////////////////////////////////////////////////////////////
372 // Function: GeomTristrips::append_unused_vertices
373 // Access: Protected, Virtual
374 // Description: Called when a new primitive is begun (other than the
375 // first primitive), this should add some degenerate
376 // vertices between primitives, if the primitive type
377 // requires that. The second parameter is the first
378 // vertex that begins the new primitive.
379 ////////////////////////////////////////////////////////////////////
380 void GeomTristrips::
381 append_unused_vertices(GeomVertexArrayData *vertices, int vertex) {
382  GeomVertexReader from(vertices, 0);
383  from.set_row_unsafe(vertices->get_num_rows() - 1);
384  int prev = from.get_data1i();
385 
386  GeomVertexWriter to(vertices, 0);
387  to.set_row_unsafe(vertices->get_num_rows());
388 
389  to.add_data1i(prev);
390  to.add_data1i(vertex);
391 }
392 
393 ////////////////////////////////////////////////////////////////////
394 // Function: GeomTristrips::register_with_read_factory
395 // Access: Public, Static
396 // Description: Tells the BamReader how to create objects of type
397 // Geom.
398 ////////////////////////////////////////////////////////////////////
399 void GeomTristrips::
401  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
402 }
403 
404 ////////////////////////////////////////////////////////////////////
405 // Function: GeomTristrips::make_from_bam
406 // Access: Protected, Static
407 // Description: This function is called by the BamReader's factory
408 // when a new object of type Geom is encountered
409 // in the Bam file. It should create the Geom
410 // and extract its information from the file.
411 ////////////////////////////////////////////////////////////////////
412 TypedWritable *GeomTristrips::
413 make_from_bam(const FactoryParams &params) {
414  GeomTristrips *object = new GeomTristrips(UH_unspecified);
415  DatagramIterator scan;
416  BamReader *manager;
417 
418  parse_params(params, scan, manager);
419  object->fillin(scan, manager);
420 
421  return object;
422 }
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
ShadeModel get_shade_model() const
Returns the ShadeModel hint for this primitive.
Definition: geomPrimitive.I:24
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:122
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:63
int get_num_vertices() const
Returns the number of indices used by all the primitives in this object.
virtual int get_geom_rendering() const
Returns the set of GeomRendering bits that represent the rendering properties required to properly re...
Defines a series of triangle strips.
Definition: geomTristrips.h:25
int get_first_vertex() const
Returns the first vertex number referenced by the primitive.
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...
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...
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
void register_factory(TypeHandle handle, CreateFunc *func)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:90
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
int get_num_rows() const
Returns the number of rows stored in the array, based on the number of bytes and the stride...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
int get_vertex(int i) const
Returns the ith vertex index in the table.
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
UsageHint get_usage_hint() const
Returns the usage hint for this primitive.
Definition: geomPrimitive.I:67
Defines a series of disconnected triangles.
Definition: geomTriangles.h:25
static void register_with_read_factory()
Tells the BamReader how to create objects of type Geom.
A class to retrieve the individual data elements previously stored in a Datagram. ...
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.
bool is_indexed() const
Returns true if the primitive is indexed, false otherwise.
Similar to PointerToArray, except that its contents may not be modified.
This is the data for one array of a GeomVertexData structure.