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 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
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
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
A class to retrieve the individual data elements previously stored in a Datagram.
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
Encapsulates the data from a GeomPrimitive, pre-fetched for one stage of the pipeline.
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
get_usage_hint
Returns the usage hint for this primitive.
Definition: geomPrimitive.h:81
get_num_vertices
Returns the number of indices used by all the primitives in this object.
Definition: geomPrimitive.h:99
int get_first_vertex() const
Returns the first vertex number referenced by the primitive.
Definition: geomPrimitive.I:98
get_shade_model
Returns the ShadeModel hint for this primitive.
Definition: geomPrimitive.h:77
bool is_indexed() const
Returns true if the primitive is indexed, false otherwise.
Definition: geomPrimitive.I:86
Defines a series of disconnected triangles, with adjacency information.
Defines a series of disconnected triangles.
Definition: geomTriangles.h:23
This is the data for one array of a GeomVertexData structure.
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
A thread; that is, a lightweight process.
Definition: thread.h:46
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT(GeomPrimitive) GeomTriangles
Returns the fundamental rendering type of this primitive: whether it is points, lines,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.