Panda3D
geomTriangles.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file geomTriangles.cxx
10  * @author drose
11  * @date 2005-03-06
12  */
13 
14 #include "geomTriangles.h"
15 #include "geomVertexRewriter.h"
16 #include "pStatTimer.h"
17 #include "bamReader.h"
18 #include "bamWriter.h"
20 #include "geomTrianglesAdjacency.h"
21 
22 using std::map;
23 
24 TypeHandle GeomTriangles::_type_handle;
25 
26 /**
27  *
28  */
29 GeomTriangles::
30 GeomTriangles(GeomTriangles::UsageHint usage_hint) :
31  GeomPrimitive(usage_hint)
32 {
33 }
34 
35 /**
36  *
37  */
38 GeomTriangles::
39 GeomTriangles(const GeomTriangles &copy) :
40  GeomPrimitive(copy)
41 {
42 }
43 
44 /**
45  *
46  */
47 GeomTriangles::
48 ~GeomTriangles() {
49 }
50 
51 /**
52  *
53  */
54 PT(GeomPrimitive) GeomTriangles::
55 make_copy() const {
56  return new GeomTriangles(*this);
57 }
58 
59 /**
60  * Returns the fundamental rendering type of this primitive: whether it is
61  * points, lines, or polygons.
62  *
63  * This is used to set up the appropriate antialiasing settings when
64  * AntialiasAttrib::M_auto is in effect; it also implies the type of primitive
65  * that will be produced when decompose() is called.
66  */
67 GeomPrimitive::PrimitiveType GeomTriangles::
68 get_primitive_type() const {
69  return PT_polygons;
70 }
71 
72 /**
73  * Adds adjacency information to this primitive. May return null if this type
74  * of geometry does not support adjacency information.
75  */
76 CPT(GeomPrimitive) GeomTriangles::
77 make_adjacency() const {
78  using std::make_pair;
79 
80  Thread *current_thread = Thread::get_current_thread();
82 
83  GeomPrimitivePipelineReader from(this, current_thread);
84  int num_vertices = from.get_num_vertices();
85 
86  PT(GeomVertexArrayData) new_vertices = adj->make_index_data();
87  new_vertices->set_num_rows(num_vertices * 2);
88 
89  // First, build a map of each triangle's halfedges to its opposing vertices.
90  map<std::pair<int, int>, int> edge_map;
91  for (int i = 0; i < num_vertices; i += 3) {
92  int v0 = from.get_vertex(i);
93  int v1 = from.get_vertex(i + 1);
94  int v2 = from.get_vertex(i + 2);
95  edge_map[make_pair(v0, v1)] = v2;
96  edge_map[make_pair(v1, v2)] = v0;
97  edge_map[make_pair(v2, v0)] = v1;
98  }
99 
100  // Now build up the new vertex data. For each edge, we insert the
101  // appropriate connecting vertex.
102  {
103  GeomVertexWriter to(new_vertices, 0);
104  for (int i = 0; i < num_vertices; i += 3) {
105  int v0 = from.get_vertex(i);
106  int v1 = from.get_vertex(i + 1);
107  int v2 = from.get_vertex(i + 2);
108 
109  // Get the third vertex of the triangle adjoining this edge.
110  to.set_data1(v0);
111  auto it = edge_map.find(make_pair(v1, v0));
112  if (it != edge_map.end()) {
113  to.set_data1i(it->second);
114  } else {
115  // Um, no adjoining triangle? Just repeat the vertex, I guess.
116  to.set_data1i(v0);
117  }
118 
119  // Do the same for the other two edges.
120  to.set_data1(v1);
121  it = edge_map.find(make_pair(v2, v1));
122  if (it != edge_map.end()) {
123  to.set_data1i(it->second);
124  } else {
125  to.set_data1i(v1);
126  }
127 
128  to.set_data1(v2);
129  it = edge_map.find(make_pair(v0, v2));
130  if (it != edge_map.end()) {
131  to.set_data1i(it->second);
132  } else {
133  to.set_data1i(v2);
134  }
135  }
136 
137  nassertr(to.is_at_end(), nullptr);
138  }
139 
140  adj->set_vertices(std::move(new_vertices));
141  return adj;
142 }
143 
144 /**
145  * If the primitive type is a simple type in which all primitives have the
146  * same number of vertices, like triangles, returns the number of vertices per
147  * primitive. If the primitive type is a more complex type in which different
148  * primitives might have different numbers of vertices, for instance a
149  * triangle strip, returns 0.
150  */
151 int GeomTriangles::
152 get_num_vertices_per_primitive() const {
153  return 3;
154 }
155 
156 /**
157  * Calls the appropriate method on the GSG to draw the primitive.
158  */
159 bool GeomTriangles::
161  bool force) const {
162  return gsg->draw_triangles(reader, force);
163 }
164 
165 /**
166  * The virtual implementation of doubleside().
167  */
168 CPT(GeomPrimitive) GeomTriangles::
169 doubleside_impl() const {
170  Thread *current_thread = Thread::get_current_thread();
171  PT(GeomTriangles) reversed = new GeomTriangles(*this);
172 
173  GeomPrimitivePipelineReader from(this, current_thread);
174 
175  // This is like reverse(), except we don't clear the vertices first. That
176  // way we double the vertices up.
177 
178  // First, rotate the original copy, if necessary, so the flat-firstflat-last
179  // nature of the vertices is consistent throughout the primitive.
180  bool needs_rotate = false;
181  switch (from.get_shade_model()) {
182  case SM_flat_first_vertex:
183  case SM_flat_last_vertex:
184  reversed = (GeomTriangles *)DCAST(GeomTriangles, reversed->rotate());
185  needs_rotate = true;
186 
187  default:
188  break;
189  }
190 
191  // Now append all the new vertices, in reverse order.
192  for (int i = from.get_num_vertices() - 1; i >= 0; --i) {
193  reversed->add_vertex(from.get_vertex(i));
194  }
195 
196  // Finally, re-rotate the whole thing to get back to the original shade
197  // model.
198  if (needs_rotate) {
199  reversed = (GeomTriangles *)DCAST(GeomTriangles, reversed->rotate());
200  }
201 
202  return reversed;
203 }
204 
205 /**
206  * The virtual implementation of reverse().
207  */
208 CPT(GeomPrimitive) GeomTriangles::
209 reverse_impl() const {
210  Thread *current_thread = Thread::get_current_thread();
211  PT(GeomTriangles) reversed = new GeomTriangles(*this);
212 
213  GeomPrimitivePipelineReader from(this, current_thread);
214  reversed->clear_vertices();
215 
216  for (int i = from.get_num_vertices() - 1; i >= 0; --i) {
217  reversed->add_vertex(from.get_vertex(i));
218  }
219 
220  switch (from.get_shade_model()) {
221  case SM_flat_first_vertex:
222  reversed->set_shade_model(SM_flat_last_vertex);
223  reversed = (GeomTriangles *)DCAST(GeomTriangles, reversed->rotate());
224  break;
225 
226  case SM_flat_last_vertex:
227  reversed->set_shade_model(SM_flat_first_vertex);
228  reversed = (GeomTriangles *)DCAST(GeomTriangles, reversed->rotate());
229  break;
230 
231  default:
232  break;
233  }
234 
235  return reversed;
236 }
237 
238 /**
239  * The virtual implementation of rotate().
240  */
241 CPT(GeomVertexArrayData) GeomTriangles::
242 rotate_impl() const {
243  // To rotate triangles, we just move one vertex from the front to the back,
244  // or vice-versa; but we have to know what direction we're going.
245  ShadeModel shade_model = get_shade_model();
246  int num_vertices = get_num_vertices();
247 
248  PT(GeomVertexArrayData) new_vertices = make_index_data();
249  new_vertices->set_num_rows(num_vertices);
250 
251  if (is_indexed()) {
252  CPT(GeomVertexArrayData) vertices = get_vertices();
253  GeomVertexReader from(vertices, 0);
254  GeomVertexWriter to(new_vertices, 0);
255 
256  switch (shade_model) {
257  case SM_flat_first_vertex:
258  // Move the first vertex to the end.
259  {
260  for (int begin = 0; begin < num_vertices; begin += 3) {
261  from.set_row_unsafe(begin + 1);
262  to.set_data1i(from.get_data1i());
263  to.set_data1i(from.get_data1i());
264  from.set_row_unsafe(begin);
265  to.set_data1i(from.get_data1i());
266  }
267  }
268  break;
269 
270  case SM_flat_last_vertex:
271  // Move the last vertex to the front.
272  {
273  for (int begin = 0; begin < num_vertices; begin += 3) {
274  from.set_row_unsafe(begin + 2);
275  to.set_data1i(from.get_data1i());
276  from.set_row_unsafe(begin);
277  to.set_data1i(from.get_data1i());
278  to.set_data1i(from.get_data1i());
279  }
280  }
281  break;
282 
283  default:
284  // This shouldn't get called with any other shade model.
285  nassertr(false, vertices);
286  }
287 
288  nassertr(to.is_at_end(), nullptr);
289 
290  } else {
291  // Nonindexed case.
292  int first_vertex = get_first_vertex();
293  GeomVertexWriter to(new_vertices, 0);
294 
295  switch (shade_model) {
296  case SM_flat_first_vertex:
297  // Move the first vertex to the end.
298  {
299  for (int begin = 0; begin < num_vertices; begin += 3) {
300  to.set_data1i(begin + 1 + first_vertex);
301  to.set_data1i(begin + 2 + first_vertex);
302  to.set_data1i(begin + first_vertex);
303  }
304  }
305  break;
306 
307  case SM_flat_last_vertex:
308  // Move the last vertex to the front.
309  {
310  for (int begin = 0; begin < num_vertices; begin += 3) {
311  to.set_data1i(begin + 2 + first_vertex);
312  to.set_data1i(begin + first_vertex);
313  to.set_data1i(begin + 1 + first_vertex);
314  }
315  }
316  break;
317 
318  default:
319  // This shouldn't get called with any other shade model.
320  nassertr(false, nullptr);
321  }
322 
323  nassertr(to.is_at_end(), nullptr);
324  }
325 
326  return new_vertices;
327 }
328 
329 /**
330  * Tells the BamReader how to create objects of type Geom.
331  */
332 void GeomTriangles::
333 register_with_read_factory() {
334  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
335 }
336 
337 /**
338  * This function is called by the BamReader's factory when a new object of
339  * type Geom is encountered in the Bam file. It should create the Geom and
340  * extract its information from the file.
341  */
342 TypedWritable *GeomTriangles::
343 make_from_bam(const FactoryParams &params) {
344  GeomTriangles *object = new GeomTriangles(UH_unspecified);
345  DatagramIterator scan;
346  BamReader *manager;
347 
348  parse_params(params, scan, manager);
349  object->fillin(scan, manager);
350 
351  return object;
352 }
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
get_usage_hint
Returns the usage hint for this primitive.
Definition: geomPrimitive.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
get_num_vertices
Returns the number of indices used by all the primitives in this object.
Definition: geomPrimitive.h:99
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Defines a series of disconnected triangles, with adjacency information.
int get_first_vertex() const
Returns the first vertex number referenced by the primitive.
Definition: geomPrimitive.I:98
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition: bamReader.I:275
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT(GeomPrimitive) GeomTriangles
Returns the fundamental rendering type of this primitive: whether it is points, lines,...
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
A thread; that is, a lightweight process.
Definition: thread.h:46
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
get_shade_model
Returns the ShadeModel hint for this primitive.
Definition: geomPrimitive.h:77
Defines a series of disconnected triangles.
Definition: geomTriangles.h:23
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:81
Encapsulates the data from a GeomPrimitive, pre-fetched for one stage of the pipeline.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool is_indexed() const
Returns true if the primitive is indexed, false otherwise.
Definition: geomPrimitive.I:86
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the data for one array of a GeomVertexData structure.